Sunday, July 15, 2012

Binutils 2.19.1 patch 1.4

Changes this version:

Fixed bug prohibiting the use of single quotes in a string Strings my be in either TI-style 'stuff' or C-style "stuff" TI-style strings follow E/A text rules C-style strings may include standard escape codes "example\n"

Download:
binutils-2.19.1-tms9900-1.4-patch.tar.gz

GCC 4.4.0 patch 1.6

Changes this version:

Fixed comparison against +-1 and +-2, were broken in 1.5
Prevented incorrect use of fake PC register for real work
Improved AND operations to reduce setup instructions
Fixed long-to-char conversions
Fixed post-increment pointers which live on the stack
Added optimization for setting byte quantities to zero
Added optimization for (int)X = (unsigned char)((int)X)
Removed double-counting saved registers on the stack
Reduced overhead needed for multiply instructions
Fixed bug causing structres to be loaded into registers
Structures used as function arguments now passed by reference
Fixed more bugs causing bad int-to-char conversions


Download:
gcc-4.4.0-tms9900-1.6-patch.tar.gz

Saturday, July 14, 2012

I was looking for another instance where int-to-char conversion was done incorrectly. Once again, GCC was assuming that byte quantities stored in registers are stored in the least significant byte. After much poking around, I found the problem in find_reloads. It was in a portion of code which was a default handler of reload conditions.

I had earlier fixed code in this function which handled most cases of subreg substitution, but I believe since the source and destination registers were the same in this case, execution skipped down to the default handler.

In any case, I added a check on that path to prevent modification of the subreg expression when int-to-char and char-to-int converstons are called for. These cases are properly handled in the machine description, and the correct instructions are issued as expected.

Unfortunately, once find_reloads was fixed, there was still a problem. The instruction was being broken in a different way, and looked something like this:

(insn 72 71 74 3 lucien2_8.c:39 (set (reg:QI 7 r7 [orig:73 D.1232 ] [73])
        (reg:QI 7 r7 [+1 ])) 71 {movqi} (nil))

This effectively returns us to the situation we just fixed, that the byte quantity was assumed to be in the least significant byte of a register.

After tracing execution and checking the evolution of the instruction, I found where the subreg expression was converted to the "+1" form above. This was done in alter_subreg.

The code there was intended to handle special cases which escaped processing by simplify_subreg. Since I've disabled a lot of sode which would remove subreg expressions, these default handlers are getting more use.

At this point, I need to go through my earlier notes, but I think it's time for another release.

Monday, May 21, 2012

I've noticed a few places where we have a sequence where a register is loaded with a constant, used for some operation, then discarded. Like this:
  li r1, 27
  mpy r1, r4

I wonder if it would be better to put these constants in the data section, and do something like this:
  mpy @const_27, r4

Lets check it out!

li r1, 27  - 4 bytes, 12+4+4=20 clocks
mpy r1, r4 - 2 byte, 52+4=56 clocks
total: 6 bytes, 76 clocks

.data const_27: data 27 - 2 bytes, 0 clocks
mpy @const_27, r4 - 2 bytes, 52+4+8=64 clocks
total: 4 bytes, 64 clocks

Hmm, pretty good... 33% smaller, 15% faster. I wasn't expecting that. This could be better if the constant is used in other places too. That would further reduce the effective bytes used for each instruction. (Average size is between 4 and 2 bytes per operation. Asymptotic to 2.) This is also more drastic for quicker instructions (like movb: 20+14+4+8=46 clocks vs. 26 clocks, 43% faster).

I should look at ways to optimize memset and memcpy sequences, there's got to be a way to take advantage of that.

Saturday, May 19, 2012

I fixed the problem with the use_regs error. The TARGET_PASS_BY_REFERENCE macro was not changed from the default value. This macro is evaluated to determine if function parameters which are to be passed by value should instead be silently copied to the stack and then that copy be passed by reference. This is the problem I saw earlier, the structure was being passed by value, but there were not enough registers to hold the bytes of that value.

The default action of TARGET_PASS_BY_REFERENCE is to never silently pass by reference (which causes the problem seen here). I've overridden this to instead use pass-by-reference for data types larger than four bytes or for aggregate data types (structures).

Saturday, May 12, 2012

I got some free time again to look at GCC stuff, so I'm going through the source code for Nyog Sothep looking at the problems there.

Right now I'm looking at a problem resulting in "internal compiler error: in use_regs, at expr.c:2245"

This is the result of an assert requiring that all registers be valid. This assert is within expr.c::use_regs.

The call_regs function is being called to validate the usage of a record requiring 19 registers, starting at R1. This sounds like an entire structure is being loaded into registers, and not just the element of that structure we are interested in.

This is the operation which is causing problems: has_item(investigators[i],RETURN_SPELL)

All of "investigators[i]" is being passed by value in registers instead of passed by reference using one register. Since we don't have enough registers to hold the entire structure, we get a fatal error.

Thursday, May 3, 2012

Well, I finally got multiply working using define_expand, but it's worse than what I had before.

This approach allocates two registers for the multiply result, and doesn't seem to allow for reuse of one of the input registers. The registers seem to be allocated at the beginning of the instruction, and any dead registers are marked as available for reuse after the instruction. This results in more used registers and an extra MOV instruction in most cases. The MOV is sued to copy one operand into the newly allocated 32-bit registers. This is no good, so I'll just back this out and pretend it never happened.

The good news is that this experience has given me more tools to use for the compiler. That's been handy for MULHI3, which is defined using define_expand, and results in nice clean code.