4

I heard that the Motorola 68000 and Intel x86 architectures handle overflow from left shifting differently. Specifically the 68k LSL vs. the Intel SAL/SHL assembly instructions.

Does anyone know the specifics of this? Do they set different flags, or set them differently? I tried to look this up in the reference manuals, but I don't see any difference. Why would one want to handle this situation differently?

halfer
  • 19,824
  • 17
  • 99
  • 186
Tony R
  • 11,224
  • 23
  • 76
  • 101

3 Answers3

6

The X bit is not involved. The confusion over the 68000 flags arises because there are two left shift instructions:

  • LSL, logical shift left, clears the overflow flag.
  • ASL, Arithmetic shift left, sets the V flag if the MSB changes sign at any time during the shift.

The x86 instruction set is not nearly as powerful. If the shift count = 1 then OF, the overflow flag, = (MSB XOR CF), i.e. if the MSB changed sign as a result of the 1-bit shift, OF = 1, else OF = 0.

If the shift count is >1 then OF is undefined. (HTML extract of Intel's documentation for SHL).

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
4

The programmer's manuals for the CPUs have the specifics:

Motorola 68K:

X — Set according to the last bit shifted out of the operand; 
    unaffected for a shift count of zero. 
N — Set if the result is negative; cleared otherwise. 
Z  — Set if the result is zero; cleared otherwise. 
V — Always cleared. 
C — Set according to the last bit shifted out of the operand; 
    cleared for a shift count of zero. 

Intel x86:

  • The CF flag contains the value of the last bit shifted out of the destination operand; it is undefined for SHL and SHR instructions where the count is greater than or equal to the size (in bits) of the destination operand.
  • The OF flag is affected only for 1-bit shifts (refer to “Description” above); otherwise, it is undefined.
  • The SF, ZF, and PF flags are set according to the result. If the count is 0, the flags are not affected.
  • For a non-zero count, the AF flag is undefined.

So the overflow flag is treated differently. It'll let you know in x86 if a multiply by 2 (a single bit left shift) resulted in an overflow. I don't know why it's so specific to just 1 bit shifts. I'd guess (and it's just a guess) that the OF flag gets set according to the 'last' bit shift - and that might not indicate whether the whole operation overflowed, so Intel just documented it as 'undefined'.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 2
    It's for historical reasons from back in the day when one-bit shifts and arithmetic shifts were implemented differently in the silicon. They made that specification back then, and ever since we've been stuck with it for backwards compatibility. – Crashworks Nov 11 '09 at 03:29
  • @Crashworks: In fact, it might still be the case that OF is only defined for the dedicated shift-by-1 opcode, not for variable or imm8 count shifts with count=1. Rotates work like that; it's not count=1 that matters, it's only the ROL/ROR-by-1 short-form opcode that decodes to an extra uop to handle the weird flag semantics (which differ from shifts). (http://agner.org/optimize/) – Peter Cordes Jul 25 '18 at 20:25
3

(Yes I am reviewing my Motorola 68000 Reference from 1979.)

Probably what you're thinking of is the 68000's rather strange X bit. The eXtend bit is essentially a copy of the C (carry) bit, but isn't affected by non-arithmetic instructions. Suppose you are adding 12-word integers, for example. In x86, you might see something like:

  .
  .
loop:
  ADC AX,[SI]    ; recycle carry-out from last iter as carry-in to this one

  LEA SI, [SI+2] ; flags untouched
  INC BX         ; BX is loop index.  sets all flags except CF
  CMP BX, 12     ; doh, changes carry (BUG)
  JB  loop

This code doesn't work because the compare instruction mucks up the carry flag. This is one reason why the loop instruction was historically useful, counting CX down to zero without modifying flags. Counting down to zero with dec / jnz also works, but causes partial-flag stalls on modern x86. Unfortunately loop is slow now too, so there was no good way to make a loop like this from about 486 until Sandybridge.

But in 68000:

  .
  .
loop:
  ADDX.W (A0)+, D0   ; both C and X set the same
  INC.W  D7          ; D7 is loop index
  CMP.W  #12, D7     ; harms C, but X left intact
  BCC  loop

Motorola thought they were doing programmers a favor, but the X bit business ended up causing more confusion than it was worth.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
I. J. Kennedy
  • 24,725
  • 16
  • 62
  • 87