{ %opt=-O2 -Sew -vw }

{$inline on}

type
  Int96 = packed record
    case Integer of
      0:
        (
          {$IFDEF ENDIAN_LITTLE}
          Lo32 : DWord;
          case Integer of
            0:
              (
                Mid32 : DWord;
                Hi32 : LongInt;
              );
            1:
              ( Hi64: Int64; );
          {$ELSE ENDIAN_LITTLE}
          Hi32 : LongInt;
          case Integer of
            0:
              (
                Mid32 : DWord;
                Lo32 : DWord;
              );
            1:
              ( Lo64: QWord; );
          {$ENDIF ENDIAN_LITTLE}
        );
      1:
        (
          {$IFDEF ENDIAN_LITTLE}
          Lo64 : QWord;
          {$ELSE ENDIAN_LITTLE}
          Hi64 : Int64;
          {$ENDIF ENDIAN_LITTLE}
        );
  end;

operator shl (const Left: Int96; const Right: LongInt) Result : Int96; forward;

operator shr (const Left: Int96; const Right: LongInt) Result : Int96; inline;
begin
  if Right >= 0 then
    if Right = 32 then begin
      Result.Lo32 := Left.Mid32;
      Result.Mid32 := Left.Hi32;
      Result.Hi32 := 0;
    end else if Right = 0 then begin
      Result.Lo32 := Left.Lo32;
      Result.Mid32 := Left.Mid32;
      Result.Hi32 := Left.Hi32;
    end else if Right = 64 then begin
      Result.Lo32 := Left.Hi32;
      Result.Mid32 := 0;
      Result.Hi32 := 0;
    end else if Right < 32 then begin
      Result.Hi32 := Left.Hi32 shr Right;
      Result.Mid32 := (Left.Mid32 shr Right) or dword(Left.Hi32 shl (32 - Right));
      Result.Lo32 := (Left.Lo32 shr Right) or (Left.Mid32 shl (32 - Right));
    end else if Right < 64 then begin
      Result.Hi32 := 0;
      Result.Mid32 := Left.Hi32 shr (Right-32);
      Result.Lo32 := longint(Left.Mid32 shr (Right-32)) or (Left.Hi32 shl (64 - Right));
    end else if Right < 96 then begin
      Result.Hi32 := 0;
      Result.Mid32 := 0;
      Result.Lo32 := Left.Hi32 shr (Right-64);
    end else begin
      Result.Lo32 := 0;
      Result.Mid32 := 0;
      Result.Hi32 := 0;
    end
  else
    Result := Left shl (-Right);
end;

operator shl (const Left: Int96; const Right: LongInt) Result : Int96; inline;
begin
  { ToDo: optimized code for 64bit cpu's }
  if Right >= 0 then
    if Right = 32 then begin
      Result.Lo32 := 0;
      Result.Mid32 := Left.Lo32;
      Result.Hi32 := Left.Mid32;
    end else if Right = 0 then begin
      Result.Lo32 := Left.Lo32;
      Result.Mid32 := Left.Mid32;
      Result.Hi32 := Left.Hi32;
    end else if Right = 64 then begin
      Result.Lo32 := 0;
      Result.Mid32 := 0;
      Result.Hi32 := Left.Lo32;
    end else if Right < 32 then begin
      Result.Lo32 := Left.Lo32 shl Right;
      Result.Mid32 := (Left.Mid32 shl Right) or (Left.Lo32 shr (32 - Right));
      Result.Hi32 := (Left.Hi32 shl Right) or longint(Left.Mid32 shr (32 - Right));
    end else if Right < 64 then begin
      Result.Lo32 := 0;
      Result.Mid32 := Left.Lo32 shl (Right-32);
      Result.Hi32 := (Left.Mid32 shl (Right-32)) or (Left.Lo32 shr (64 - Right));
    end else if Right < 96 then begin
      Result.Lo32 := 0;
      Result.Mid32 := 0;
      Result.Hi32 := Left.Lo32 shl (Right-64);
    end else begin
      Result.Lo32 := 0;
      Result.Mid32 := 0;
      Result.Hi32 := 0;
    end
  else
    Result := Left shr (-Right);
end;

operator := (const Right: QWord) Result : Int96; inline;
begin
  Result.Lo64  := Right;
  Result.Hi32  := 0;
end;


procedure t;
var
  a: int96;
begin
  a := 500000000000000;
  a := a shr 1;
  if (a.lo64 <> (500000000000000 shr 1)) or
     (a.hi32 <> 0) then
    halt(1);
end;

begin
  t;
end.
