Friday, March 30, 2012

I've been looking through the tms9900.c file, here are some random notes for later:

The SP currently points at the bottommost used register, but every other machine I know points at the topmost free address, I should probably chnage that. Shouldn't be a big deal, but may break backwards-compatability.

I fixed the df_ref_record crash. The problem was not respecting the difference between strict and non-strict validation in GO_IF_LEGITIMATE_ADDRESS. When in non-strict mode, all pseudoregisters are treated as if they were real registers. In strict mode, they are treated as memory locations.

Since this distinction was not made, the value (r10+18) was treated as a register, accepted by GO_IF_LEGITIMATE_ADDRESS, and things blew up later. Now, that construct is seen as invalid, and GCC refactors the expression to find an equivalent valid form.

Back to printf...

Wednesday, March 28, 2012

I recently upgraded my laptop to Ubuntu 11.10, and this has made a mess of the porting effort. Since I needed to relink against new libraries, Binutils and GCC need to be rebuilt. This shouldn't be a problem, but for some reason, the -Werror flag (treat all warnings as errors) is now respected, where it seemed to be ignored before. None of the warnings are in my code, so I don't feel bad disabling warnings.

So I've got to update the build directions for Binutils.

patching:
$ cd {path_to_original_files}
$ patch -p1 < patchfile

binutils:
$ ./configure --target tms9900 --prefix /home/eric/dev/tios/toolchain --disable-build-warnings
$ make all
$ make install

GCC:
$ ./configure --prefix /home/eric/dev/tios/toolchain --target=tms9900 --enable-languages=c
$ make all-gcc
$ make install

Sunday, March 25, 2012

I Found this during testing:

printf.c: In function ‘printf’:
printf.c:239: internal compiler error: in df_ref_record, at df-scan.c:2803

This was the faulting expression:
(mem/c:HI (plus:HI (reg/f:HI 10 r10)
(const_int 18 [0x12])) [6 %sfp+10 S2 A16])

Since this expression doesn't show up in the debug output, I need to backtrace to find out what happened here

df_ref_record (cl=DF_REF_REGULAR)
df_uses_record (in the POST_INC case)

RTL of offending instruction:
(set (reg/v:QI 2 r2 [orig:49 c ] [49])
(mem:QI (post_inc:HI (mem/c:HI (plus:HI (reg/f:HI 10 r10)
(const_int 18 [0x12])) [6 %sfp+10 S2 A16])) [0 S1 A8]))

It looks like this came from this instruction, seen in 168r.asmcons

(insn 39 168 41 5 printf.c:152 (set (reg/v:QI 49 [ c ])
(mem:QI (post_inc:HI (reg/v/f:HI 46 [ p.44 ])) [0 S1 A8])) 71 {movqi} (expr_list:REG_INC (reg/v/f:HI 46 [ p.44 ])
(nil)))

In a more readable form:
movb 18(r10+), r2

It took me a while to figure this out, but GCC is not trying to increment R10, but the expression (R10+18), which rightly fails.

The pseudoregisgter R46 is "p" (a pointer into the current string) which is used later, as is R10, which is the stack pointer. This means that the post-increment expression needs to be removed somehow.

I imagine if I used the "register" keyword, that would probably fix this problem, but this would just show up again sometime later.

I need to take a closer look at the PDP11 config to see how they dealt with the problem.

Saturday, March 24, 2012

I played around with the compiler trying to reduce the test program output and found a few things.

There is a note attached to the add instruction that the R3 regisgter in HI mode is unused after that instruction, so we could skip the "jnc, inc" sequence.

The check commonly used for the other machines, "find_reg_note(insn, REG_UNUSED, operands[0])", will not work here. There are two reasons for this. The first is that the operand is in SI mode, but the note is for HI mode. The second is that the function only checks for pointer equality, and does not compare the RTX expressions to which the pointers refer. I'd have to make a new find_reg_note function to do note checking.

If I just change the order of typecasting, all this goes away:

char test(long a) {return((char)a+'0');}

Becomes:

test
mov r2, r1
swpb r1
ai r1, >3000
b *r11

This is the ideal sequence I was looking for originally, so another best practice seems to be to to late promotion and early demotion of datatypes. That seems to result in better code.

So for now, I'll put compiler changes on hold, and just go back to printf.

Friday, March 23, 2012

I'm tracing backwards through the call tree to find where this problem shows up. Call tree is shown below:

ira
reload
cleanup_subreg_operands
alter_subreg
simplify_subreg

Found it. The problem is in the change I made earlier in simplify-rtx. That change was to handle int-to-char conversions, but it doesn't handle long-to-char properly. It was finding the correct register to use after conversion, but the wrong mode, this was described earlier during initial investigation.

The fix was to first convert long-to-int to find the correct register, then int-to-char to complete the conversion.

Finally, I get this code, which is longer than strictly necessary

test
clr r3 # Clear upper word of temp long
mov r2, r4 # Copy lower word of input to temp
ai r4, >30 # Add '0' to temp
jnc $+>4 # Add carry bit to upper word of temp
inc r3
mov r4, r1 # Copy low word of temp into output register
swpb r1 # Move result into position for return
b *r11

A better result would be more this like:

test
ai r2, >30 # Add '0' to low word of input
mov r2, r1 # Copy result into output register
swpb r1 # Move result into position for return
b *r11

Thursday, March 22, 2012

Here's a simplified version of the instructions up to step 182r.peephole2 for the "long" type.

inputs: r1,r2=val, r3=a_base (unused)
insn 24: r3=0 \_ Set temp 32-bit value to zero
insn 25: r4=r3 /
insn 28: r4=r2 <- Copy low word into temp value
insn 12: r4&=0x0F <- Apply mask
insn 13: r3(32-bit)+=48 <- '0'=48 <- Adding constant to low word
insn 14: r1=(char)r4
insn 15: number_buf[0]=r1
insn 33: return

GCC is claiming that R3 is unused (this is true), and so any manipulation of R3 can be safely removed. GCC also seems to be expanding this to R4, as it's part of the temporary 32-bit value defined in insn 24 and 25.

That results in these instructions being deleted in step 182:

insn 13
insn 12
insn 28
insn 25
insn 24

We are left with R4, with the note that it's in SImode (32-bit value), somehow the notion that R4 is the low word is lost, and R5 is selected for the low word of the value. This results in the final code:

print_hex
mov r5, r1
swpb r1
movb r1, @number_buf
b *r11

Similar behavior was seen with this code as well:
char test(long a) {return(a+'0');}

test
mov r5, r1
swpb r1
b *r11

Testing will continue with this example, since it's much shorter.

I found that the problem happens during register allocation. In all prior steps, the RTX looks good, but at 172r.ira, the wrong register is chosen, which makes a mess of everything from that point on.

168r.asmcoms
insn 3: (HI)((SI)r24)[0] = r1
insn 4: (HI)((SI)r24)[1] = r2
insn 9: (SI)r26=(SI)r24+48
insn 10: (QI)r27=(QI)((SI)r26)[3]
insn 16: (QI)r1=(QI)r27

172r.ira
insn 3: r3=r1
insn 4: r4=r2
insn 9: (SI)r3+=48
insn 10: (QI)r1=(SI)4 <- this is wrong, should be (SI)r3

Wednesday, March 21, 2012

Ok, this is wierd. I was working on a hex printing routine, and was seeing some strange behavior, so I've isolated it below:

void print_hex(long val, char a_base)
{
char *p=number_buf;
unsigned char a = ((val & 0x0F) + '0');
*p++ = a;
}

This results in this assembly:

print_hex
mov r5, r1
swpb r1
movb r1, @number_buf
b *r11

If "val" is defined as an "int" all is well:

print_hex
li r2, >F
mov r2, r2 <-- Wierd, but OK I guess
inv r2
szc r2, r1
ai r1, >30
swpb r1
movb r1, @number_buf
b *r11

I'm totally confused.

The wierd MOV instruction was from the "andhi3" pattern. The idea was to move data into the correct temporary register for the SZC instruction. This move was inserted every time SZC is used, even if it would be pointless, as in the example above.

I've reworked the word and byte "and" patterns to emit optimal code. As a side-effect, some of the gyrations needed to handle SZC have been reduced. Here's the new code for this function:

print_hex
andi r1, >F
ai r1, >30
swpb r1
movb r1, @number_buf
b *r11

Much better. Now back to bizarro-ness.

The problem shows up in step 182r.peephole2, but I'm not sure why these instructions were deleted. I see that there are notes like "DCE: Deleting insn 25". DCE stands for Dead Code Elimination, but the code in question is not dead. Or at least I don't think it is.

This is the first deleted instruction:

(insn 13 12 14 2 printhex.c:17 (set (reg:SI 3 r3 [27])
(plus:SI (reg:SI 3 r3 [26])
(const_int 48 [0x30]))) 56 {addsi3} (expr_list:REG_UNUSED (reg:SI 3 r3 [27])
(nil)))

This would be equivalent to the "ai r1, >30" instruction in the working int case. For some reason, this code is marked as unused, and removing this instruction causes all prior code to be marked and deleted as well.

Now I just need to find out why GCC think this is unused.