2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/utils.c - Some utility functions
11 Prototypes are in F<src/misc.h>.
13 Opcode helper functions that don't really fit elsewhere.
23 #include "parrot/parrot.h"
24 #include "pmc/pmc_nci.h"
26 typedef unsigned short _rand_buf
[3];
28 /* Parrot_register_move companion functions i and data */
29 typedef struct parrot_prm_context
{
30 unsigned char *dest_regs
;
31 unsigned char *src_regs
;
32 unsigned char temp_reg
;
38 reg_move_func mov_alt
;
42 /* HEADERIZER HFILE: include/parrot/misc.h */
43 /* HEADERIZER BEGIN: static */
44 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
46 static FLOATVAL
_drand48(void);
47 static FLOATVAL
_erand48(_rand_buf buf
);
48 static long _jrand48(_rand_buf buf
);
49 static long _lrand48(void);
50 static long _mrand48(void);
51 static long _nrand48(_rand_buf buf
);
52 static void _srand48(long seed
);
53 static INTVAL
COMPARE(PARROT_INTERP
,
57 __attribute__nonnull__(1)
58 __attribute__nonnull__(2)
59 __attribute__nonnull__(3)
60 __attribute__nonnull__(4);
62 static void next_rand(_rand_buf X
);
63 static void process_cycle_without_exit(
65 ARGIN(const parrot_prm_context
*c
))
66 __attribute__nonnull__(2);
68 static void rec_climb_back_and_mark(
70 ARGIN(const parrot_prm_context
*c
))
71 __attribute__nonnull__(2);
73 #define ASSERT_ARGS__drand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
74 #define ASSERT_ARGS__erand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
75 #define ASSERT_ARGS__jrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
76 #define ASSERT_ARGS__lrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
77 #define ASSERT_ARGS__mrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
78 #define ASSERT_ARGS__nrand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
79 #define ASSERT_ARGS__srand48 __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
80 #define ASSERT_ARGS_COMPARE __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
81 PARROT_ASSERT_ARG(interp) \
82 , PARROT_ASSERT_ARG(a) \
83 , PARROT_ASSERT_ARG(b) \
84 , PARROT_ASSERT_ARG(cmp))
85 #define ASSERT_ARGS_next_rand __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
86 #define ASSERT_ARGS_process_cycle_without_exit __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
88 #define ASSERT_ARGS_rec_climb_back_and_mark __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
90 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
91 /* HEADERIZER END: static */
93 #define move_reg(from, dest, c) (c)->mov((c)->interp, (unsigned char)(dest), \
94 (unsigned char)(from), (c)->info)
98 =item C<INTVAL intval_mod(INTVAL i2, INTVAL i3)>
100 NOTE: This "corrected mod" algorithm is based on the C code on page 70
101 of [1]. Assuming correct behavior of the built-in mod operator (%) with
102 positive arguments, this algorithm implements a mathematically
103 convenient version of mod, defined thus:
105 x mod y = x - y * floor(x / y)
107 For more information on this definition of mod, see section 3.4 of [2],
112 [1] Donald E. Knuth, *MMIXware: A RISC Computer for the Third
113 Millennium* Springer, 1999.
115 [2] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, *Concrete
116 Mathematics*, Second Edition. Addison-Wesley, 1994.
122 PARROT_CONST_FUNCTION
123 PARROT_WARN_UNUSED_RESULT
125 intval_mod(INTVAL i2
, INTVAL i3
)
127 ASSERT_ARGS(intval_mod
)
139 if (y
< 0) { s
+= 2; y
= -y
; }
140 if (z
< 0) { s
+= 1; z
= -z
; }
144 if (r
) { /* # 36003 */
147 case 1: r
= r
- z
; break;
148 case 2: r
= z
- r
; break;
149 case 3: r
= -r
; break;
160 =item C<FLOATVAL floatval_mod(FLOATVAL n2, FLOATVAL n3)>
162 Returns C<n2 mod n3>.
164 Includes a workaround for buggy code generation in the C<lcc> compiler.
170 PARROT_CONST_FUNCTION
171 PARROT_WARN_UNUSED_RESULT
173 floatval_mod(FLOATVAL n2
, FLOATVAL n3
)
175 ASSERT_ARGS(floatval_mod
)
178 /* Another workaround for buggy code generation in the lcc compiler-
179 * adding a temporary variable makes it pass the test.
181 const FLOATVAL temp
= n3
* floor(n2
/ n3
);
183 return !FLOAT_IS_ZERO(n3
)
187 return !FLOAT_IS_ZERO(n3
)
188 ? (n2
- n3
* floor(n2
/ n3
))
198 =head2 Random Number Generator
200 Based on the C<rand48()> family of functions.
209 * currently undefined
211 #ifndef PARROT_HAS_DRAND48
214 * s. man drand48, SuS V2
216 * X(n+1) = ( aX(n) + c ) mod 2^48
220 # define A_mid 0xDEEC
223 # define SEED_LO 0x330E
225 static _rand_buf a
= { A_lo
, A_mid
, A_hi
};
226 static _rand_buf last_rand
;
227 static unsigned short c
= C
;
231 =item C<static void next_rand(_rand_buf X)>
233 Returns the next random number in C<X>.
240 next_rand(_rand_buf X
)
242 ASSERT_ARGS(next_rand
)
243 unsigned short lo
, mid
, hi
;
246 /* 48 bit mul, one short at a time */
249 mid
= (t
>> 16) & 0xffff;
251 t
= X
[1] * a
[0] + X
[0] * a
[1] + mid
;
253 hi
= (t
>> 16) & 0xffff;
255 t
= X
[2] * a
[0] + X
[1] * a
[1] + X
[0] * a
[2] + hi
;
264 =item C<static FLOATVAL _erand48(_rand_buf buf)>
266 Returns a C<double> in the interval C<[0.0, 1.0)>.
273 _erand48(_rand_buf buf
)
275 ASSERT_ARGS(_erand48
)
278 r
= ((buf
[0] / 65536.0 + buf
[1]) / 65536.0 + buf
[2]) / 65536.0;
284 =item C<static FLOATVAL _drand48(void)>
286 Returns a C<double> in the interval C<[0.0, 1.0)>.
295 ASSERT_ARGS(_drand48
)
296 return _erand48(last_rand
);
301 =item C<static long _jrand48(_rand_buf buf)>
303 Returns a C<long> in the interval C<[-2^31, 2^31)>.
310 _jrand48(_rand_buf buf
)
312 ASSERT_ARGS(_jrand48
)
315 ret
= buf
[2] << 16 | buf
[1];
321 =item C<static long _nrand48(_rand_buf buf)>
323 Returns a C<long> in the interval C<[0, 2^31)>.
330 _nrand48(_rand_buf buf
)
332 ASSERT_ARGS(_nrand48
)
333 return _jrand48(buf
) & 0x7fffffff;
338 =item C<static long _lrand48(void)>
340 Returns a C<long> in the interval C<[0, 2^31)>.
349 ASSERT_ARGS(_lrand48
)
350 return _nrand48(last_rand
);
355 =item C<static long _mrand48(void)>
357 Returns a C<long> in the interval C<[-2^31, 2^31)>.
366 ASSERT_ARGS(_mrand48
)
367 return _jrand48(last_rand
);
372 =item C<static void _srand48(long seed)>
374 Sets the high order 32 bits to the argument C<seed>. The low order 16
375 bits are set to the arbitrary value 0x330e.
384 ASSERT_ARGS(_srand48
)
385 last_rand
[0] = SEED_LO
;
386 last_rand
[1] = (unsigned short)(seed
& 0xffff);
387 last_rand
[2] = (unsigned short)((seed
>> 16) & 0xffff);
389 * reinit a, c if changed by lcong48()
400 # define _drand48 drand48
401 # define _erand48(b) erand48(b)
403 # define _lrand48 lrand48
404 # define _nrand48(b) nrand48(b)
406 # define _mrand48 mrand48
407 # define _jrand48(b) jrand48(b)
409 # define _srand48 srand48
415 =item C<FLOATVAL Parrot_float_rand(INTVAL how_random)>
417 Returns a C<FLOATVAL> uniformly distributed in the in the interval
420 C<how_random> is currently ignored.
427 PARROT_WARN_UNUSED_RESULT
429 Parrot_float_rand(INTVAL how_random
)
431 ASSERT_ARGS(Parrot_float_rand
)
434 return _drand48(); /* [0.0..1.0] */
439 =item C<INTVAL Parrot_uint_rand(INTVAL how_random)>
441 Returns an C<INTVAL> uniformly distributed in the interval C<[0, 2^31)>.
443 C<how_random> is ignored.
450 PARROT_WARN_UNUSED_RESULT
452 Parrot_uint_rand(INTVAL how_random
)
454 ASSERT_ARGS(Parrot_uint_rand
)
457 return _lrand48(); /* [0..2^31] */
462 =item C<INTVAL Parrot_int_rand(INTVAL how_random)>
464 Returns an C<INTVAL> in the interval C<[-2^31, 2^31)>.
466 C<how_random> is ignored.
473 PARROT_WARN_UNUSED_RESULT
475 Parrot_int_rand(INTVAL how_random
)
477 ASSERT_ARGS(Parrot_int_rand
)
480 return _mrand48(); /* [-2^31..2^31] */
485 =item C<INTVAL Parrot_range_rand(INTVAL from, INTVAL to, INTVAL how_random)>
487 Returns an C<INTVAL> in the range C<[from, to]>.
489 C<how_random> is ignored.
496 PARROT_WARN_UNUSED_RESULT
498 Parrot_range_rand(INTVAL from
, INTVAL to
, INTVAL how_random
)
500 ASSERT_ARGS(Parrot_range_rand
)
501 const double spread
= (double)(to
- from
+ 1);
502 const double randpart
= Parrot_float_rand(how_random
);
503 const INTVAL raw
= from
+ (INTVAL
)(spread
* randpart
);
510 =item C<void Parrot_srand(INTVAL seed)>
512 Seeds the random number generator with C<seed>.
520 Parrot_srand(INTVAL seed
)
522 ASSERT_ARGS(Parrot_srand
)
527 /* &gen_from_enum(tm.pasm) */
543 =item C<PMC* Parrot_tm_to_array(PARROT_INTERP, const struct tm *tm)>
545 Helper to convert a B<struct tm *> to an Array
552 PARROT_WARN_UNUSED_RESULT
553 PARROT_CANNOT_RETURN_NULL
555 Parrot_tm_to_array(PARROT_INTERP
, ARGIN(const struct tm
*tm
))
557 ASSERT_ARGS(Parrot_tm_to_array
)
559 PMC
* const Array
= Parrot_pmc_new(interp
,
560 Parrot_get_ctx_HLL_type(interp
, enum_class_FixedIntegerArray
));
561 VTABLE_set_integer_native(interp
, Array
, 9);
563 VTABLE_set_integer_keyed_int(interp
, Array
, 0, tm
->tm_sec
);
564 VTABLE_set_integer_keyed_int(interp
, Array
, 1, tm
->tm_min
);
565 VTABLE_set_integer_keyed_int(interp
, Array
, 2, tm
->tm_hour
);
566 VTABLE_set_integer_keyed_int(interp
, Array
, 3, tm
->tm_mday
);
567 VTABLE_set_integer_keyed_int(interp
, Array
, 4, tm
->tm_mon
+ 1);
568 VTABLE_set_integer_keyed_int(interp
, Array
, 5, tm
->tm_year
+ 1900);
569 VTABLE_set_integer_keyed_int(interp
, Array
, 6, tm
->tm_wday
);
570 VTABLE_set_integer_keyed_int(interp
, Array
, 7, tm
->tm_yday
);
571 VTABLE_set_integer_keyed_int(interp
, Array
, 8, tm
->tm_isdst
);
578 =item C<INTVAL Parrot_byte_index(PARROT_INTERP, const STRING *base, const STRING
579 *search, UINTVAL start_offset)>
581 Looks for the location of a substring within a longer string. Takes
582 pointers to the strings and the offset within the string at which
583 to start searching as arguments.
585 Returns an offset value if it is found, or -1 if no match.
592 PARROT_WARN_UNUSED_RESULT
594 Parrot_byte_index(SHIM_INTERP
, ARGIN(const STRING
*base
),
595 ARGIN(const STRING
*search
), UINTVAL start_offset
)
597 ASSERT_ARGS(Parrot_byte_index
)
598 const char * const str_start
= base
->strstart
;
599 const INTVAL str_len
= base
->strlen
;
600 const char * const search_str
= search
->strstart
;
601 const INTVAL search_len
= search
->strlen
;
602 const char *str_pos
= str_start
+ start_offset
;
603 INTVAL len_remain
= str_len
- start_offset
;
604 const char *search_pos
;
606 /* find the next position of the first character in the search string
607 * Parrot strings can have NULLs, so strchr() won't work here */
608 while ((search_pos
= (const char *)memchr(str_pos
, *search_str
, len_remain
))) {
609 const INTVAL offset
= search_pos
- str_start
;
611 /* now look for the entire string */
612 if (memcmp(search_pos
, search_str
, search_len
) == 0)
615 /* otherwise loop and memchr() with the rest of the string */
616 len_remain
= str_len
- offset
;
617 str_pos
= search_pos
+ 1;
619 if (len_remain
< search_len
)
628 =item C<INTVAL Parrot_byte_rindex(PARROT_INTERP, const STRING *base, const
629 STRING *search, UINTVAL start_offset)>
631 Substring search (like Parrot_byte_index), but works backwards,
632 from the rightmost end of the string.
634 Returns offset value or -1 (if no match).
641 PARROT_WARN_UNUSED_RESULT
643 Parrot_byte_rindex(SHIM_INTERP
, ARGIN(const STRING
*base
),
644 ARGIN(const STRING
*search
), UINTVAL start_offset
)
646 ASSERT_ARGS(Parrot_byte_rindex
)
647 const INTVAL searchlen
= search
->strlen
;
648 const char * const search_start
= (const char *)(search
->strstart
);
649 UINTVAL max_possible_offset
= (base
->strlen
- search
->strlen
);
650 INTVAL current_offset
;
652 if (start_offset
&& start_offset
< max_possible_offset
)
653 max_possible_offset
= start_offset
;
655 for (current_offset
= max_possible_offset
; current_offset
>= 0;
657 const char * const base_start
= (char *)(base
->strstart
) + current_offset
;
658 if (memcmp(base_start
, search_start
, searchlen
) == 0) {
659 return current_offset
;
668 =item C<static void rec_climb_back_and_mark(int node_index, const
669 parrot_prm_context *c)>
671 Recursive function, used by Parrot_register_move to
672 climb back the graph of register moves operations.
674 The node must have a predecessor: it is implicit because if a node has
675 a node_index, it must have a predecessor because the node_index are the
676 index of registers in dest_regs[] array, so by definition they have
677 a corrsponding src_regs register.
679 Then it emits the move operation with its predecessor, or its backup
680 if already used/visited.
682 Then continues the climbing if the predecessor was not modified, anf in that
683 case marks it, and set node_index as its backup.
685 node_index ... the index of a destination (i.e. with a pred.) register
686 c ... the graph and all the needed params : the context
693 rec_climb_back_and_mark(int node_index
, ARGIN(const parrot_prm_context
*c
))
695 ASSERT_ARGS(rec_climb_back_and_mark
)
696 const int node
= c
->dest_regs
[node_index
];
697 const int pred
= c
->src_regs
[node_index
];
698 const int pred_index
= c
->reg_to_index
[pred
];
700 if (pred_index
< 0) { /* pred has no predecessor */
701 move_reg(pred
, node
, c
);
703 else { /* pred has a predecessor, so may be processed */
704 const int src
= c
->backup
[pred_index
];
705 if (src
< 0) { /* not visited */
706 move_reg(pred
, node
, c
);
707 c
->backup
[pred_index
] = node
; /* marks pred*/
708 rec_climb_back_and_mark(pred_index
, c
);
710 else { /* already visited, use backup instead */
711 move_reg(src
, node
, c
);
719 =item C<static void process_cycle_without_exit(int node_index, const
720 parrot_prm_context *c)>
722 Recursive function, used by Parrot_register_move to handle the case
723 of cycles without exits, that are cycles of move ops between registers
724 where each register has exactly one predecessor and one successor
726 For instance: 1-->2, 2-->3, 3-->1
728 node_index ... the index of a destination (i.e. with a pred.) register
729 c ... the graph and all the needed params : the context
736 process_cycle_without_exit(int node_index
, ARGIN(const parrot_prm_context
*c
))
738 ASSERT_ARGS(process_cycle_without_exit
)
739 const int pred
= c
->src_regs
[node_index
];
741 /* let's try the alternate move function*/
744 ? c
->mov_alt(c
->interp
, c
->dest_regs
[node_index
], pred
, c
->info
)
747 if (0 == alt
) { /* use temp reg */
748 move_reg(c
->dest_regs
[node_index
], c
->temp_reg
, c
);
749 c
->backup
[node_index
] = c
->temp_reg
;
752 c
->backup
[node_index
] = c
->dest_regs
[node_index
];
754 rec_climb_back_and_mark(node_index
, c
);
759 =item C<void Parrot_register_move(PARROT_INTERP, int n_regs, unsigned char
760 *dest_regs, unsigned char *src_regs, unsigned char temp_reg, reg_move_func mov,
761 reg_move_func mov_alt, void *info)>
763 Move C<n_regs> from the given register list C<src_regs> to C<dest_regs>.
765 n_regs ... amount of registers to move
766 dest_regs ... list of register numbers 0..255
767 src_regs ... list of register numbers 0..255
768 temp_reg ... a register number not in one of these lists
769 mov ... a register move function to be called to move one register
770 mov_alt ... a register move function to be called to move one register
771 which triese fetching from an alternate src (or NULLfunc):
773 (void) (mov)(interp, dest, src, info);
774 moved = (mov_alt)(interp, dest, src, info);
776 Some C<dest_regs> might be the same as C<src_regs>, which makes this a bit
777 non-trivial, because if the destination is already clobbered, using it
778 later as source doesn"t work. E.g.
781 1 <- 0 # register 0 already clobbered
787 3 <- 2 # register 2 already clobbered - reorder moves
789 To handle such cases, we do:
791 a) rearrange the order of moves (not possible in the first case)
792 and/or if that failed:
793 b) if an alternate move function is available, it may fetch the
794 source from a different (non-clobbered) location - call it.
795 if the function returns 0 also use c)
796 c) if no alternate move function is available, use the temp reg
798 The amount of register moves should of course be minimal.
800 TODO The current implementation will not work for following cases
802 Talked to Leo and he said those cases are not likely (Vishal Soni).
803 1. I0->I1 I1->I0 I0->I3
806 TODO: Add tests for the above conditions.
814 Parrot_register_move(PARROT_INTERP
,
816 ARGOUT(unsigned char *dest_regs
),
817 ARGIN(unsigned char *src_regs
),
818 unsigned char temp_reg
,
820 reg_move_func mov_alt
,
823 ASSERT_ARGS(Parrot_register_move
)
828 int* reg_to_index
= NULL
;
829 parrot_prm_context c
;
835 if (src_regs
[0] != dest_regs
[0])
836 mov(interp
, dest_regs
[0], src_regs
[0], info
);
844 c
.src_regs
= src_regs
;
845 c
.dest_regs
= dest_regs
;
846 c
.temp_reg
= temp_reg
;
848 /* compute max_reg, the max reg number + 1 */
849 for (i
= 0; i
< n_regs
; ++i
) {
850 if (src_regs
[i
] > max_reg
)
851 max_reg
= src_regs
[i
];
852 if (dest_regs
[i
] > max_reg
)
853 max_reg
= dest_regs
[i
];
858 /* allocate space for data structures */
859 /* NOTA: data structures could be kept allocated somewhere waiting to get reused...*/
860 c
.nb_succ
= nb_succ
= mem_gc_allocate_n_zeroed_typed(interp
, n_regs
, int);
861 c
.backup
= backup
= mem_gc_allocate_n_zeroed_typed(interp
, n_regs
, int);
862 c
.reg_to_index
= reg_to_index
= mem_gc_allocate_n_zeroed_typed(interp
, max_reg
, int);
864 /* init backup array */
865 for (i
= 0; i
< n_regs
; ++i
)
868 /* fill in the conversion array between a register number and its index */
869 for (i
= 0; i
< max_reg
; ++i
)
870 reg_to_index
[i
] = -1;
871 for (i
= 0; i
< n_regs
; ++i
) {
872 const int index
= dest_regs
[i
];
873 if (index
!= src_regs
[i
]) /* get rid of self-assignment */
874 reg_to_index
[index
] = i
;
877 /* count the nb of successors for each reg index */
878 for (i
= 0; i
< n_regs
; ++i
) {
879 const int index
= reg_to_index
[ src_regs
[i
] ];
880 if (index
>= 0) /* not interested in the wells that have no preds */
883 /* process each well if any */
884 for (i
= 0; i
< n_regs
; ++i
) {
885 if (0 == nb_succ
[i
]) { /* a well */
886 rec_climb_back_and_mark(i
, &c
);
890 /* process remaining dest registers not processed */
891 /* remaining nodes are members of cycles without exits */
892 for (i
= 0; i
< n_regs
; ++i
) {
893 if (0 < nb_succ
[i
] && 0 > backup
[i
]) { /* not a well nor visited*/
894 process_cycle_without_exit(i
, &c
);
898 mem_gc_free(interp
, nb_succ
);
899 mem_gc_free(interp
, reg_to_index
);
900 mem_gc_free(interp
, backup
);
903 typedef INTVAL (*sort_func_t
)(PARROT_INTERP
, void *, void *);
907 =item C<static INTVAL COMPARE(PARROT_INTERP, void *a, void *b, PMC *cmp)>
909 General PMC comparison function. Takes two PMCs. Returns 0 if they are equal,
910 returns 1 if C<a> is bigger, and returns -1 if C<b> is bigger.
916 /* TODO: Macroize COMPARE */
917 /* This is an awfully expensive function to call, what with all the */
918 /* comparisons that never change. We ought to precompute everything. */
919 /* XXX We should be able to guarantee that *a and *b never change via const parameters. */
921 COMPARE(PARROT_INTERP
, ARGIN(void *a
), ARGIN(void *b
), ARGIN(PMC
*cmp
))
925 if (PMC_IS_NULL(cmp
))
926 return VTABLE_cmp(interp
, (PMC
*)a
, (PMC
*)b
);
928 if (cmp
->vtable
->base_type
== enum_class_NCI
) {
929 const sort_func_t f
= (sort_func_t
)D2FPTR(PARROT_NCI(cmp
)->func
);
930 return f(interp
, a
, b
);
933 Parrot_pcc_invoke_sub_from_c_args(interp
, cmp
, "PP->I", a
, b
, &result
);
939 =item C<void Parrot_quicksort(PARROT_INTERP, void **data, UINTVAL n, PMC *cmp)>
941 Perform a quicksort on a PMC array.
948 Parrot_quicksort(PARROT_INTERP
, ARGMOD(void **data
), UINTVAL n
, ARGIN(PMC
*cmp
))
950 ASSERT_ARGS(Parrot_quicksort
)
952 UINTVAL i
, j
, ln
, rn
;
960 for (i
= 0, j
= n
; ;) {
963 while (j
> 0 && COMPARE(interp
, data
[j
], data
[0], cmp
) > 0);
967 while (i
< j
&& COMPARE(interp
, data
[i
], data
[0], cmp
) < 0);
987 Parrot_quicksort(interp
, data
, ln
, cmp
);
992 Parrot_quicksort(interp
, data
+ j
, rn
, cmp
);
1007 * c-file-style: "parrot"
1009 * vim: expandtab shiftwidth=4: