mp-bits.c

     
   1  //! @file mp-bits.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! [LONG] LONG BITS routines, legacy MP implementation.
  25  
  26  #include "a68g.h"
  27  
  28  #if (A68_LEVEL <= 2)
  29  
  30  #include "a68g-prelude.h"
  31  #include "a68g-mp.h"
  32  #include "a68g-genie.h"
  33  #include "a68g-numbers.h"
  34  #include "a68g-transput.h"
  35  
  36  // This legacy code implements a quick-and-dirty LONG LONG BITS mode,
  37  // constructed on top of the LONG LONG INT/REAL/COMPLEX library.
  38  // It was essentially meant to have LONG LONG BITS for demonstration only. 
  39  // There are obvious possibilities to improve this code, but discussions 
  40  // suggested that workers needing long bit strings, in fields such as 
  41  // cryptography, would be better off implementing their own optimally
  42  // efficient tools, and investment in an efficient LONG LONG BITS library
  43  // would not be worth the while.
  44  // Hence in recent a68c versions, LONG BITS is a 128-bit quad word,
  45  // and LONG LONG BITS is mapped onto LONG BITS.
  46  // Below code is left in a68g for reference purposes, and in case a build of
  47  // a version < 3 would be required.
  48  
  49  #define MP_BITS_WIDTH(k) ((int) ceil ((k) * LOG_MP_RADIX * CONST_LOG2_10) - 1)
  50  #define MP_BITS_WORDS(k) ((int) ceil ((REAL_T) MP_BITS_WIDTH (k) / (REAL_T) MP_BITS_BITS))
  51  
  52  //! @brief Length in bits of mode.
  53  
  54  int get_mp_bits_width (const MOID_T * m)
  55  {
  56    if (m == M_LONG_BITS) {
  57      return MP_BITS_WIDTH (LONG_MP_DIGITS);
  58    } else if (m == M_LONG_LONG_BITS) {
  59      return MP_BITS_WIDTH (A68_MP (varying_mp_digits));
  60    }
  61    return 0;
  62  }
  63  
  64  //! @brief Length in words of mode.
  65  
  66  int get_mp_bits_words (const MOID_T * m)
  67  {
  68    if (m == M_LONG_BITS) {
  69      return MP_BITS_WORDS (LONG_MP_DIGITS);
  70    } else if (m == M_LONG_LONG_BITS) {
  71      return MP_BITS_WORDS (A68_MP (varying_mp_digits));
  72    }
  73    return 0;
  74  }
  75  
  76  //! @brief Convert z to a row of MP_BITS_T in the stack.
  77  
  78  MP_BITS_T *stack_mp_bits (NODE_T * p, MP_T * z, MOID_T * m)
  79  {
  80    int digits = DIGITS (m), words = get_mp_bits_words (m);
  81    MP_BITS_T *row = (MP_BITS_T *) STACK_ADDRESS (A68_SP);
  82    INCREMENT_STACK_POINTER (p, words * SIZE_ALIGNED (MP_BITS_T));
  83    MP_T *u = nil_mp (p, digits);
  84    MP_T *v = nil_mp (p, digits);
  85    MP_T *w = nil_mp (p, digits);
  86    (void) move_mp (u, z, digits);
  87  // Argument check.
  88    if (MP_DIGIT (u, 1) < 0.0) {
  89      errno = EDOM;
  90      diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, m);
  91      exit_genie (p, A68_RUNTIME_ERROR);
  92    }
  93  // Convert radix MP_BITS_RADIX number.
  94    for (int k = words - 1; k >= 0; k--) {
  95      (void) move_mp (w, u, digits);
  96      (void) over_mp_digit (p, u, u, (MP_T) MP_BITS_RADIX, digits);
  97      (void) mul_mp_digit (p, v, u, (MP_T) MP_BITS_RADIX, digits);
  98      (void) sub_mp (p, v, w, v, digits);
  99      row[k] = (MP_BITS_T) MP_DIGIT (v, 1);
 100    }
 101  // Test on overflow: too many bits or not reduced to 0.
 102    MP_BITS_T mask = 0x1;
 103    int lim = get_mp_bits_width (m) % MP_BITS_BITS;
 104    for (int k = 1; k < lim; k++) {
 105      mask <<= 1;
 106      mask |= 0x1;
 107    }
 108    if ((row[0] & ~mask) != 0x0 || MP_DIGIT (u, 1) != 0.0) {
 109      errno = ERANGE;
 110      diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, m);
 111      exit_genie (p, A68_RUNTIME_ERROR);
 112    }
 113  // Exit.
 114    return row;
 115  }
 116  
 117  //! @brief Convert row of MP_BITS_T to LONG BITS.
 118  
 119  MP_T *pack_mp_bits (NODE_T * p, MP_T * u, MP_BITS_T * row, MOID_T * m)
 120  {
 121    int digits = DIGITS (m), words = get_mp_bits_words (m);
 122    ADDR_T pop_sp = A68_SP;
 123  // Discard excess bits.
 124    MP_BITS_T mask = 0x1, musk = 0x0;
 125    MP_T *v = nil_mp (p, digits);
 126    MP_T *w = nil_mp (p, digits);
 127    int lim = get_mp_bits_width (m) % MP_BITS_BITS;
 128    for (int k = 1; k < lim; k++) {
 129      mask <<= 1;
 130      mask |= 0x1;
 131    }
 132    row[0] &= mask;
 133    for (int k = 1; k < (A68_BITS_WIDTH - MP_BITS_BITS); k++) {
 134      musk <<= 1;
 135    }
 136    for (int k = 0; k < MP_BITS_BITS; k++) {
 137      musk <<= 1;
 138      musk |= 0x1;
 139    }
 140  // Convert.
 141    SET_MP_ZERO (u, digits);
 142    SET_MP_ONE (v, digits);
 143    for (int k = words - 1; k >= 0; k--) {
 144      (void) mul_mp_digit (p, w, v, (MP_T) (musk & row[k]), digits);
 145      (void) add_mp (p, u, u, w, digits);
 146      if (k != 0) {
 147        (void) mul_mp_digit (p, v, v, (MP_T) MP_BITS_RADIX, digits);
 148      }
 149    }
 150    MP_STATUS (u) = (MP_T) INIT_MASK;
 151    A68_SP = pop_sp;
 152    return u;
 153  }
 154  
 155  //! @brief Convert multi-precision number to unt.
 156  
 157  UNSIGNED_T mp_to_unt (NODE_T * p, MP_T * z, int digits)
 158  {
 159  // This routine looks a lot like "strtol". We do not use "mp_to_real" since int
 160  // could be wider than 2 ** 52.
 161    int expo = (int) MP_EXPONENT (z);
 162    if (expo >= digits) {
 163      diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, MOID (p));
 164      exit_genie (p, A68_RUNTIME_ERROR);
 165    }
 166    UNSIGNED_T sum = 0, weight = 1;
 167    for (int j = 1 + expo; j >= 1; j--) {
 168      if ((unt) MP_DIGIT (z, j) > UINT_MAX / weight) {
 169        diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, M_BITS);
 170        exit_genie (p, A68_RUNTIME_ERROR);
 171      }
 172      UNSIGNED_T term = (unt) MP_DIGIT (z, j) * weight;
 173      if (sum > UINT_MAX - term) {
 174        diagnostic (A68_RUNTIME_ERROR, p, ERROR_OUT_OF_BOUNDS, M_BITS);
 175        exit_genie (p, A68_RUNTIME_ERROR);
 176      }
 177      sum += term;
 178      weight *= MP_RADIX;
 179    }
 180    return sum;
 181  }
 182  
 183  //! @brief Whether LONG BITS value is in range.
 184  
 185  void check_long_bits_value (NODE_T * p, MP_T * u, MOID_T * m)
 186  {
 187    if (MP_EXPONENT (u) >= (MP_T) (DIGITS (m) - 1)) {
 188      ADDR_T pop_sp = A68_SP;
 189      (void) stack_mp_bits (p, u, m);
 190      A68_SP = pop_sp;
 191    }
 192  }
 193  
 194  //! @brief LONG BITS value of LONG BITS denotation
 195  
 196  void mp_strtou (NODE_T * p, MP_T * z, char *str, MOID_T * m)
 197  {
 198    errno = 0;
 199    char *radix = NO_TEXT;
 200    int base = (int) a68_strtou (str, &radix, 10);
 201    if (radix != NO_TEXT && TO_UPPER (radix[0]) == TO_UPPER (RADIX_CHAR) && errno == 0) {
 202      int digits = DIGITS (m);
 203      ADDR_T pop_sp = A68_SP;
 204      char *q = radix;
 205      MP_T *v = nil_mp (p, digits);
 206      MP_T *w = nil_mp (p, digits);
 207      while (q[0] != NULL_CHAR) {
 208        q++;
 209      }
 210      SET_MP_ZERO (z, digits);
 211      SET_MP_ONE (w, digits);
 212      if (base < 2 || base > 16) {
 213        diagnostic (A68_RUNTIME_ERROR, p, ERROR_INVALID_RADIX, base);
 214        exit_genie (p, A68_RUNTIME_ERROR);
 215      }
 216      while ((--q) != radix) {
 217        int digit = char_value (q[0]);
 218        if (digit >= 0 && digit < base) {
 219          (void) mul_mp_digit (p, v, w, (MP_T) digit, digits);
 220          (void) add_mp (p, z, z, v, digits);
 221        } else {
 222          diagnostic (A68_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, m);
 223          exit_genie (p, A68_RUNTIME_ERROR);
 224        }
 225        (void) mul_mp_digit (p, w, w, (MP_T) base, digits);
 226      }
 227      check_long_bits_value (p, z, m);
 228      A68_SP = pop_sp;
 229    } else {
 230      diagnostic (A68_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, m);
 231      exit_genie (p, A68_RUNTIME_ERROR);
 232    }
 233  }
 234  
 235  //! @brief Convert to other radix, binary up to hexadecimal.
 236  
 237  BOOL_T convert_radix_mp (NODE_T * p, MP_T * u, int radix, int width, MOID_T * m, MP_T * v, MP_T * w)
 238  {
 239    if (width > 0 && (radix >= 2 && radix <= 16)) {
 240      static char *images = "0123456789abcdef";
 241      int digits = DIGITS (m);
 242      (void) move_mp (w, u, digits);
 243      (void) over_mp_digit (p, u, u, (MP_T) radix, digits);
 244      (void) mul_mp_digit (p, v, u, (MP_T) radix, digits);
 245      (void) sub_mp (p, v, w, v, digits);
 246      MP_INT_T digit = (MP_INT_T) MP_DIGIT (v, 1);
 247      BOOL_T success = convert_radix_mp (p, u, radix, width - 1, m, v, w);
 248      plusab_transput_buffer (p, EDIT_BUFFER, images[digit]);
 249      return success;
 250    } else {
 251      return (BOOL_T) (MP_DIGIT (u, 1) == 0);
 252    }
 253  }
 254  
 255  //! @brief OP LENG = (BITS) LONG BITS
 256  
 257  void genie_lengthen_unt_to_mp (NODE_T * p)
 258  {
 259    A68_BITS k;
 260    POP_OBJECT (p, &k, A68_BITS);
 261    int digits = DIGITS (M_LONG_INT);
 262    MP_T *z = nil_mp (p, digits);
 263    (void) unt_to_mp (p, z, (UNSIGNED_T) VALUE (&k), digits);
 264    MP_STATUS (z) = (MP_T) INIT_MASK;
 265  }
 266  
 267  //! @brief OP BIN = (LONG INT) LONG BITS
 268  
 269  void genie_bin_mp (NODE_T * p)
 270  {
 271    MOID_T *mode = SUB_MOID (p);
 272    int size = SIZE (mode);
 273    ADDR_T pop_sp = A68_SP;
 274    MP_T *u = (MP_T *) STACK_OFFSET (-size);
 275  // We convert just for the operand check.
 276    (void) stack_mp_bits (p, u, mode);
 277    MP_STATUS (u) = (MP_T) INIT_MASK;
 278    A68_SP = pop_sp;
 279  }
 280  
 281  //! @brief OP NOT = (LONG BITS) LONG BITS
 282  
 283  void genie_not_mp (NODE_T * p)
 284  {
 285    MOID_T *mode = LHS_MODE (p);
 286    int size = SIZE (mode);
 287    ADDR_T pop_sp = A68_SP;
 288    int words = get_mp_bits_words (mode);
 289    MP_T *u = (MP_T *) STACK_OFFSET (-size);
 290    MP_BITS_T *row = stack_mp_bits (p, u, mode);
 291    for (int k = 0; k < words; k++) {
 292      row[k] = ~row[k];
 293    }
 294    (void) pack_mp_bits (p, u, row, mode);
 295    A68_SP = pop_sp;
 296  }
 297  
 298  //! @brief OP SHORTEN = (LONG BITS) BITS
 299  
 300  void genie_shorten_mp_to_bits (NODE_T * p)
 301  {
 302    MOID_T *mode = LHS_MODE (p);
 303    int digits = DIGITS (mode), size = SIZE (mode);
 304    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 305    DECREMENT_STACK_POINTER (p, size);
 306    PUSH_VALUE (p, mp_to_unt (p, z, digits), A68_BITS);
 307  }
 308  
 309  //! @brief Get bit from LONG BITS.
 310  
 311  unt elem_long_bits (NODE_T * p, ADDR_T k, MP_T * z, MOID_T * m)
 312  {
 313    ADDR_T pop_sp = A68_SP;
 314    MP_BITS_T *words = stack_mp_bits (p, z, m), mask = 0x1;
 315    k += (MP_BITS_BITS - get_mp_bits_width (m) % MP_BITS_BITS - 1);
 316    for (int n = 0; n < MP_BITS_BITS - k % MP_BITS_BITS - 1; n++) {
 317      mask = mask << 1;
 318    }
 319    A68_SP = pop_sp;
 320    return (words[k / MP_BITS_BITS]) & mask;
 321  }
 322  
 323  //! @brief OP ELEM = (INT, LONG BITS) BOOL
 324  
 325  void genie_elem_long_bits (NODE_T * p)
 326  {
 327    int bits = get_mp_bits_width (M_LONG_BITS), size = SIZE (M_LONG_BITS);
 328    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 329    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 330    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 331    MP_BITS_T w = elem_long_bits (p, VALUE (i), z, M_LONG_BITS);
 332    DECREMENT_STACK_POINTER (p, size + SIZE (M_INT));
 333    PUSH_VALUE (p, (BOOL_T) (w != 0), A68_BOOL);
 334  }
 335  
 336  //! @brief OP ELEM = (INT, LONG LONG BITS) BOOL
 337  
 338  void genie_elem_long_mp_bits (NODE_T * p)
 339  {
 340    int bits = get_mp_bits_width (M_LONG_LONG_BITS), size = SIZE (M_LONG_LONG_BITS);
 341    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 342    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 343    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 344    MP_BITS_T w = elem_long_bits (p, VALUE (i), z, M_LONG_LONG_BITS);
 345    DECREMENT_STACK_POINTER (p, size + SIZE (M_INT));
 346    PUSH_VALUE (p, (BOOL_T) (w != 0), A68_BOOL);
 347  }
 348  
 349  //! @brief Set bit in LONG BITS.
 350  
 351  MP_BITS_T *set_long_bits (NODE_T * p, int k, MP_T * z, MOID_T * m, MP_BITS_T bit)
 352  {
 353    MP_BITS_T *words = stack_mp_bits (p, z, m), mask = 0x1;
 354    k += (MP_BITS_BITS - get_mp_bits_width (m) % MP_BITS_BITS - 1);
 355    for (int n = 0; n < MP_BITS_BITS - k % MP_BITS_BITS - 1; n++) {
 356      mask = mask << 1;
 357    }
 358    if (bit == 0x1) {
 359      words[k / MP_BITS_BITS] = (words[k / MP_BITS_BITS]) | mask;
 360    } else {
 361      words[k / MP_BITS_BITS] = (words[k / MP_BITS_BITS]) & (~mask);
 362    }
 363    return words;
 364  }
 365  
 366  //! @brief OP SET = (INT, LONG BITS) VOID
 367  
 368  void genie_set_long_bits (NODE_T * p)
 369  {
 370    ADDR_T pop_sp = A68_SP;
 371    int bits = get_mp_bits_width (M_LONG_BITS), size = SIZE (M_LONG_BITS);
 372    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 373    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 374    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 375    MP_BITS_T *w = set_long_bits (p, VALUE (i), z, M_LONG_BITS, 0x1);
 376    (void) pack_mp_bits (p, (MP_T *) STACK_ADDRESS (pop_sp - size - SIZE (M_INT)), w, M_LONG_BITS);
 377    A68_SP = pop_sp;
 378    DECREMENT_STACK_POINTER (p, SIZE (M_INT));
 379  }
 380  
 381  //! @brief OP SET = (INT, LONG LONG BITS) BOOL
 382  
 383  void genie_set_long_mp_bits (NODE_T * p)
 384  {
 385    ADDR_T pop_sp = A68_SP;
 386    int bits = get_mp_bits_width (M_LONG_LONG_BITS), size = SIZE (M_LONG_LONG_BITS);
 387    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 388    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 389    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 390    MP_BITS_T *w = set_long_bits (p, VALUE (i), z, M_LONG_LONG_BITS, 0x1);
 391    (void) pack_mp_bits (p, (MP_T *) STACK_ADDRESS (pop_sp - size - SIZE (M_INT)), w, M_LONG_LONG_BITS);
 392    A68_SP = pop_sp;
 393    DECREMENT_STACK_POINTER (p, SIZE (M_INT));
 394  }
 395  
 396  //! @brief OP CLEAR = (INT, LONG BITS) BOOL
 397  
 398  void genie_clear_long_bits (NODE_T * p)
 399  {
 400    ADDR_T pop_sp = A68_SP;
 401    int bits = get_mp_bits_width (M_LONG_BITS), size = SIZE (M_LONG_BITS);
 402    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 403    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 404    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 405    MP_BITS_T *w = set_long_bits (p, VALUE (i), z, M_LONG_BITS, 0x0);
 406    (void) pack_mp_bits (p, (MP_T *) STACK_ADDRESS (pop_sp - size - SIZE (M_INT)), w, M_LONG_BITS);
 407    A68_SP = pop_sp;
 408    DECREMENT_STACK_POINTER (p, SIZE (M_INT));
 409  }
 410  
 411  //! @brief OP CLEAR = (INT, LONG LONG BITS) BOOL
 412  
 413  void genie_clear_long_mp_bits (NODE_T * p)
 414  {
 415    ADDR_T pop_sp = A68_SP;
 416    int bits = get_mp_bits_width (M_LONG_LONG_BITS), size = SIZE (M_LONG_LONG_BITS);
 417    MP_T *z = (MP_T *) STACK_OFFSET (-size);
 418    A68_INT *i = (A68_INT *) STACK_OFFSET (-(size + SIZE (M_INT)));
 419    PRELUDE_ERROR (VALUE (i) < 1 || VALUE (i) > bits, p, ERROR_OUT_OF_BOUNDS, M_INT);
 420    MP_BITS_T *w = set_long_bits (p, VALUE (i), z, M_LONG_LONG_BITS, 0x0);
 421    (void) pack_mp_bits (p, (MP_T *) STACK_ADDRESS (pop_sp - size - SIZE (M_INT)), w, M_LONG_LONG_BITS);
 422    A68_SP = pop_sp;
 423    DECREMENT_STACK_POINTER (p, SIZE (M_INT));
 424  }
 425  
 426  //! @brief PROC long bits pack = ([] BOOL) LONG BITS
 427  
 428  void genie_long_bits_pack (NODE_T * p)
 429  {
 430    A68_REF z;
 431    POP_REF (p, &z);
 432    CHECK_REF (p, z, M_ROW_BOOL);
 433    A68_ARRAY *arr; A68_TUPLE *tup;
 434    GET_DESCRIPTOR (arr, tup, &z);
 435    int size = ROW_SIZE (tup);
 436    MOID_T *mode = MOID (p);
 437    int bits = get_mp_bits_width (mode);
 438    int digits = DIGITS (mode);
 439    PRELUDE_ERROR (size < 0 || size > bits, p, ERROR_OUT_OF_BOUNDS, M_ROW_BOOL);
 440  // Convert so that LWB goes to MSB, so ELEM gives same order as [] BOOL.
 441    MP_T *sum = nil_mp (p, digits);
 442    ADDR_T pop_sp = A68_SP;
 443    MP_T *fact = lit_mp (p, 1, 0, digits);
 444    if (ROW_SIZE (tup) > 0) {
 445      BYTE_T *base = DEREF (BYTE_T, &ARRAY (arr));
 446      for (int k = UPB (tup); k >= LWB (tup); k--) {
 447        int addr = INDEX_1_DIM (arr, tup, k);
 448        A68_BOOL *boo = (A68_BOOL *) & (base[addr]);
 449        CHECK_INIT (p, INITIALISED (boo), M_BOOL);
 450        if (VALUE (boo)) {
 451          (void) add_mp (p, sum, sum, fact, digits);
 452        }
 453        (void) mul_mp_digit (p, fact, fact, (MP_T) 2, digits);
 454      }
 455    }
 456    A68_SP = pop_sp;
 457    MP_STATUS (sum) = (MP_T) INIT_MASK;
 458  }
 459  
 460  //! @brief OP SHL = (LONG BITS, INT) LONG BITS
 461  
 462  void genie_shl_mp (NODE_T * p)
 463  {
 464    A68_INT j;
 465    POP_OBJECT (p, &j, A68_INT);
 466    MOID_T *mode = LHS_MODE (p);
 467    int size = SIZE (mode), words = get_mp_bits_words (mode);
 468    MP_T *u = (MP_T *) STACK_OFFSET (-size);
 469    ADDR_T pop_sp = A68_SP;
 470    MP_BITS_T *row_u = stack_mp_bits (p, u, mode);
 471    if (VALUE (&j) >= 0) {
 472      for (int i = 0; i < VALUE (&j); i++) {
 473        BOOL_T carry = A68_FALSE;
 474        for (int k = words - 1; k >= 0; k--) {
 475          row_u[k] <<= 1;
 476          if (carry) {
 477            row_u[k] |= 0x1;
 478          }
 479          carry = (BOOL_T) ((row_u[k] & MP_BITS_RADIX) != 0);
 480          row_u[k] &= ~((MP_BITS_T) MP_BITS_RADIX);
 481        }
 482      }
 483    } else {
 484      for (int i = 0; i < -VALUE (&j); i++) {
 485        BOOL_T carry = A68_FALSE;
 486        for (int k = 0; k < words; k++) {
 487          if (carry) {
 488            row_u[k] |= MP_BITS_RADIX;
 489          }
 490          carry = (BOOL_T) ((row_u[k] & 0x1) != 0);
 491          row_u[k] >>= 1;
 492        }
 493      }
 494    }
 495    (void) pack_mp_bits (p, u, row_u, mode);
 496    A68_SP = pop_sp;
 497  }
 498  
 499  //! @brief OP SHR = (LONG BITS, INT) LONG BITS
 500  
 501  void genie_shr_mp (NODE_T * p)
 502  {
 503    A68_INT *j;
 504    POP_OPERAND_ADDRESS (p, j, A68_INT);
 505    VALUE (j) = -VALUE (j);
 506    (void) genie_shl_mp (p);      // Conform RR
 507  }
 508  
 509  //! @brief OP <= = (LONG BITS, LONG BITS) BOOL
 510  
 511  void genie_le_long_bits (NODE_T * p)
 512  {
 513    MOID_T *mode = LHS_MODE (p);
 514    int size = SIZE (mode), words = get_mp_bits_words (mode);
 515    ADDR_T pop_sp = A68_SP;
 516    MP_T *u = (MP_T *) STACK_OFFSET (-2 * size), *v = (MP_T *) STACK_OFFSET (-size);
 517    MP_BITS_T *row_u = stack_mp_bits (p, u, mode), *row_v = stack_mp_bits (p, v, mode);
 518    BOOL_T result = A68_TRUE;
 519    for (int k = 0; (k < words) && result; k++) {
 520      result = (BOOL_T) (result & ((row_u[k] | row_v[k]) == row_v[k]));
 521    }
 522    A68_SP = pop_sp;
 523    DECREMENT_STACK_POINTER (p, 2 * size);
 524    PUSH_VALUE (p, (BOOL_T) (result ? A68_TRUE : A68_FALSE), A68_BOOL);
 525  }
 526  
 527  //! @brief OP >= = (LONG BITS, LONG BITS) BOOL
 528  
 529  void genie_ge_long_bits (NODE_T * p)
 530  {
 531    MOID_T *mode = LHS_MODE (p);
 532    int size = SIZE (mode), words = get_mp_bits_words (mode);
 533    ADDR_T pop_sp = A68_SP;
 534    MP_T *u = (MP_T *) STACK_OFFSET (-2 * size), *v = (MP_T *) STACK_OFFSET (-size);
 535    MP_BITS_T *row_u = stack_mp_bits (p, u, mode), *row_v = stack_mp_bits (p, v, mode);
 536    BOOL_T result = A68_TRUE;
 537    for (int k = 0; (k < words) && result; k++) {
 538      result = (BOOL_T) (result & ((row_u[k] | row_v[k]) == row_u[k]));
 539    }
 540    A68_SP = pop_sp;
 541    DECREMENT_STACK_POINTER (p, 2 * size);
 542    PUSH_VALUE (p, (BOOL_T) (result ? A68_TRUE : A68_FALSE), A68_BOOL);
 543  }
 544  
 545  //! @brief OP AND = (LONG BITS, LONG BITS) LONG BITS
 546  
 547  void genie_and_mp (NODE_T * p)
 548  {
 549    MOID_T *mode = LHS_MODE (p);
 550    int size = SIZE (mode), words = get_mp_bits_words (mode);
 551    ADDR_T pop_sp = A68_SP;
 552    MP_T *u = (MP_T *) STACK_OFFSET (-2 * size), *v = (MP_T *) STACK_OFFSET (-size);
 553    MP_BITS_T *row_u = stack_mp_bits (p, u, mode), *row_v = stack_mp_bits (p, v, mode);
 554    for (int k = 0; k < words; k++) {
 555      row_u[k] &= row_v[k];
 556    }
 557    (void) pack_mp_bits (p, u, row_u, mode);
 558    A68_SP = pop_sp;
 559    DECREMENT_STACK_POINTER (p, size);
 560  }
 561  
 562  //! @brief OP OR = (LONG BITS, LONG BITS) LONG BITS
 563  
 564  void genie_or_mp (NODE_T * p)
 565  {
 566    MOID_T *mode = LHS_MODE (p);
 567    int size = SIZE (mode), words = get_mp_bits_words (mode);
 568    ADDR_T pop_sp = A68_SP;
 569    MP_T *u = (MP_T *) STACK_OFFSET (-2 * size), *v = (MP_T *) STACK_OFFSET (-size);
 570    MP_BITS_T *row_u = stack_mp_bits (p, u, mode), *row_v = stack_mp_bits (p, v, mode);
 571    for (int k = 0; k < words; k++) {
 572      row_u[k] |= row_v[k];
 573    }
 574    (void) pack_mp_bits (p, u, row_u, mode);
 575    A68_SP = pop_sp;
 576    DECREMENT_STACK_POINTER (p, size);
 577  }
 578  
 579  //! @brief OP XOR = (LONG BITS, LONG BITS) LONG BITS
 580  
 581  void genie_xor_mp (NODE_T * p)
 582  {
 583    MOID_T *mode = LHS_MODE (p);
 584    int size = SIZE (mode), words = get_mp_bits_words (mode);
 585    ADDR_T pop_sp = A68_SP;
 586    MP_T *u = (MP_T *) STACK_OFFSET (-2 * size), *v = (MP_T *) STACK_OFFSET (-size);
 587    MP_BITS_T *row_u = stack_mp_bits (p, u, mode), *row_v = stack_mp_bits (p, v, mode);
 588    for (int k = 0; k < words; k++) {
 589      row_u[k] ^= row_v[k];
 590    }
 591    (void) pack_mp_bits (p, u, row_u, mode);
 592    A68_SP = pop_sp;
 593    DECREMENT_STACK_POINTER (p, size);
 594  }
 595  
 596  //! @brief LONG BITS long max bits
 597  
 598  void genie_long_max_bits (NODE_T * p)
 599  {
 600    int digits = DIGITS (M_LONG_BITS);
 601    int width = get_mp_bits_width (M_LONG_BITS);
 602    MP_T *z = nil_mp (p, digits);
 603    ADDR_T pop_sp = A68_SP;
 604    (void) set_mp (z, (MP_T) 2, 0, digits);
 605    (void) pow_mp_int (p, z, z, width, digits);
 606    (void) minus_one_mp (p, z, z, digits);
 607    A68_SP = pop_sp;
 608  }
 609  
 610  //! @brief LONG LONG BITS long long max bits
 611  
 612  void genie_long_mp_max_bits (NODE_T * p)
 613  {
 614    int digits = DIGITS (M_LONG_LONG_BITS), width = get_mp_bits_width (M_LONG_LONG_BITS);
 615    MP_T *z = nil_mp (p, digits);
 616    ADDR_T pop_sp = A68_SP;
 617    (void) set_mp (z, (MP_T) 2, 0, digits);
 618    (void) pow_mp_int (p, z, z, width, digits);
 619    (void) minus_one_mp (p, z, z, digits);
 620    A68_SP = pop_sp;
 621  }
 622  
 623  //! @brief Lengthen LONG BITS to [] BOOL.
 624  
 625  void genie_lengthen_long_bits_to_row_bool (NODE_T * p)
 626  {
 627    MOID_T *m = MOID (SUB (p));
 628    int size = SIZE (m), width = get_mp_bits_width (m), words = get_mp_bits_words (m);
 629    ADDR_T pop_sp = A68_SP;
 630  // Calculate and convert BITS value.
 631    MP_T *x = (MP_T *) STACK_OFFSET (-size);
 632    MP_BITS_T *bits = stack_mp_bits (p, x, m);
 633  // Make [] BOOL.
 634    A68_REF z, row; A68_ARRAY arr; A68_TUPLE tup;
 635    NEW_ROW_1D (z, row, arr, tup, M_ROW_BOOL, M_BOOL, width);
 636    PUT_DESCRIPTOR (arr, tup, &z);
 637    BYTE_T *base = ADDRESS (&row) + (width - 1) * SIZE (M_BOOL);
 638    int k = width;
 639    while (k > 0) {
 640      MP_BITS_T bit = 0x1;
 641      for (int j = 0; j < MP_BITS_BITS && k >= 0; j++) {
 642        STATUS ((A68_BOOL *) base) = INIT_MASK;
 643        VALUE ((A68_BOOL *) base) = (BOOL_T) ((bits[words - 1] & bit) ? A68_TRUE : A68_FALSE);
 644        base -= SIZE (M_BOOL);
 645        bit <<= 1;
 646        k--;
 647      }
 648      words--;
 649    }
 650    A68_SP = pop_sp;
 651    PUSH_REF (p, z);
 652  }
 653  
 654  #endif