Code Archeology

It’s easy to spot the thinking of long-forgotten legacy assembler programmers in the production code that runs on today’s systems.  Working under the constraints of limited memory, these programmers developed techniques for making their code as small and as efficient as possible.  While we’re not as memory constrained as these early programmers, you’ll still find their old techniques being practiced in today’s shops.  When I code these old tidbits, I like to think of it as “tipping my cap” to programmers who came before me.  Here are some examples:

Decrementing a register:

BCTR   R5,R0

This is a simple way to subtract 1 from register five.  Coding 0 for the second operand causes the flow of control to continue with the next instruction.  We could just as easily have coded this:

S      R5,=F’1’

So, why was the first technique originally preferred?  BCTR is a register-to-register (RR) instruction and will run faster than the register-to-indexed storage (RX) version.  Also the second version requires the assembler to build a fullword in memory.  Today, we might not give a second thought to defining a field, but in 1964, every byte was precious.

Moving blanks to a field:

This technique has existed since the Ancient of Days.

Assume that field X is defined as below:

X     DS    CL80

The following code will move blanks to X :

MVI      X,C’ ’

MVC      X+1(L’X–1),X

The MVI fills the first byte with a blank, and the MVC propagates blanks, one byte at a time, from left to right in field X.  The length attribute L’X gets the assembler to plug in the correct length.  Today we might code this without thinking:

BLANKS   DC   CL80’ ’

MVC    X,BLANKS

This technique requires an 80 byte field that the first method does not.   But, what’s a few bytes among friends?

Loading a “small” number into a register:

This code will put 100 in register five:

LA     R5,100

What’s going on here?  The assembler is looking for a base/displacement and perhaps an index register for creating the address that will be loaded into the register.  Everything is explicitly coded and there are no parentheses.  Explicit addresses look like this – D2(X2,B2) – that means the only thing the 100 can represent is a displacement.  The base and index registers are assumed to be zero, and therefore don’t contribute to the effective address.  If you use this technique, you are limited to a maximum value of 4095 – the maximum displacement that will fit in three hex digits.  So why not just code this instead?

L        R5,=F’100’

Well … that works fine, but again, our “modern” technique requires the assembler to build a fullword field that isn’t needed with the first method.

Do you have a favorite legacy technique I’ve missed?  Let me hear from you.

4 thoughts on “Code Archeology”

  1. Multiply a value in a register by a factor of two (or divide by two) SLL, SRL.

    Convert a single digit number to binary without using storage (a consideration in reentrant programs sometimes) ICM R0,X (where X contains the number). SLL R0,28, SRL R0,28

    Executing a TM instruction can do some funky things. Particularly if you do it in a loop combined with a SLL on the EX register… 🙂

    In the old TPF (pre z/TPF) size mattered as programs were limited to 4k assembled length, so people got quite inventive in coding neatly (sometimes to the point of obscurity!).

  2. Though some standards checking programs/programmers object, I prefer Minus1 BCTR Rx,0
    over
    BCTR Rx,R0

    since the machine does not reference register zero in the operation (unless Rx is 0).

    The use of the shift instructions to multiply or divide by a power of two should employ the algebraic shifts, not the logical ones, so that negative (two’s complement) integers are handled correctly.

    If the byte in storage represents a positive number (0-255), simpler is
    XR Rx,Rx
    IC Rx,byte

    If the byte in storage represents a signed number (something I’ve never encountered)
    ICM Rx,B’1000′,byte
    SRA Rx,28

Leave a Reply