Skip to main content
1 of 3

Assembler Enhancements

None of these proposals affect scoring or execution speed; they are only possibilities to improve code readability.

sz and snz instructions

I've often found myself writing patterns like this:

# adds c,d to a,b
add_128:
  add b, b, d
  leu d, b, d
  jz skip_carry, d
  add a, a, 1
skip_carry:
  add a, a, d
  ret a, b

Personally, I don't like that extra label floating around.

(This particular case would be rendered trivial by an adc instruction, but I think introducing a status register goes against the goals of GOLF.)

I propose two new psuedo-instructions:

sz   a       ' |    1  | skip on zero        | Skips the next instruction if a is zero.
snz  a       ' |    1  | skip on non-zero    | Skips the next instruction if a is non-zero.

These would get transformed to jz and jnz instructions by the assembler, with the address to jump to set to the current address + two instructions. The previous sample could become:

# adds c,d to a,b
add_128:
  add b, b, d
  leu d, b, d
  sz skip_carry, d
  add a, a, 1
  add a, a, d
  ret a, b

#include directive

As a simpler alternative to the dynamic/static linking proposals, you could add a function include(filename) that would cause the assembler to insert the contents of the specified file at the location of the function call. This would allow splitting utility functions and lookup tables into different files without two much trouble.

Precomputed data offsets

My submission for "Testing if a number is a square" included this snippet:

  add x, x, data(lookup_table)
  sub x, x, 2**10

I could have saved one cycle if the assembler allowed me to do something like:

  add x, x, data(lookup_table) - 2**10

I could have edited the binary myself, but as it was a 0.2-cycle (on average) optimization was not worth it. However I could see places where this could be useful.

Automatic loop unrolling:

The same submission also included the following snippet:

  and c, x, 0xFFFFFFFF00000000
  jnz skip32, c
  shl x, x, 32
  sub b, b, 16
skip32:
  and c, x, 0xFFFF000000000000
  jnz skip16, c
  shl x, x, 16
  sub b, b, 8
skip16:
  and c, x, 0xFF00000000000000
  jnz skip8, c
  shl x, x, 8
  sub b, b, 4
skip8:
  and c, x, 0xF000000000000000
  jnz skip4, c
  shl x, x, 4
  sub b, b, 2
skip4:
  and c, x, 0xC000000000000000
  jnz skip2, c
  shl x, x, 2
  sub b, b, 1
skip2:

Hard to read and prone to mistakes. What if we could do something like:

for i in range(5,0,-1):
    and c, x, 2**64 - 2**(64 - 2**i)
    jnz skip<i>, c
    shl x, x, 2**i
    sub b, b, 2**(i-1)
  skip<i>:
end

The syntax needs some work (especially the labels), but you get the idea. Here it's not so bad, but if you want to unroll (say) a 129-bit long division algorithm, where eliminating the conditional and jump would save ~20% on each cycle? Priceless.

Access to python libraries

In order to create the lookup table for the above problem, I did

lookup_table = bytes(int((16*n)**0.5) for n in range(2**10, 2**12))

But what if I wanted to make a lookup table for sin(x)? If the assembler allowed an equivalent of include math I could just use math.sin. As it is I have to prepare the lookup table ahead of time and then paste it in as a huge string: not very pretty.