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
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|