summaryrefslogtreecommitdiff
path: root/gas/testsuite/gas/all/test-gen.c
blob: 19d1a03cb54e5a54e6110707da889aae12f26b89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
#ifndef TEST_GEN_C
#define TEST_GEN_C 1

/* Copyright (C) 2000-2014 Free Software Foundation, Inc.
   Contributed by Alexandre Oliva <aoliva@cygnus.com>

   This file is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */

/* This is a source file with infra-structure to test generators for
   assemblers and disassemblers.

   The strategy to generate testcases is as follows.  We'll output to
   two streams: one will get the assembly source, and the other will
   get regexps that match the expected binary patterns.

   To generate each instruction, the functions of a func[] are called,
   each with the corresponding func_arg.  Each function should set
   members of insn_data, to decide what it's going to output to the
   assembly source, the corresponding output for the disassembler
   tester, and the bits to be set in the instruction word.  The
   strings to be output must have been allocated with strdup() or
   malloc(), so that they can be freed.  A function may also modify
   insn_size.  More details in test-gen.c

   Because this would have generated too many tests, we have chosen to
   define ``random'' sequences of numbers/registers, and simply
   generate each instruction a couple of times, which should get us
   enough coverage.

   In general, test generators should be compiled/run as follows:
  
   % gcc test.c -o test
   % ./test > test.s 2 > test.d

   Please note that this file contains a couple of GCC-isms, such as
   macro varargs (also available in C99, but with a difference syntax)
   and labeled elements in initializers (so that insn definitions are
   simpler and safer).

   It is assumed that the test generator #includes this file after
   defining any of the preprocessor macros documented below.  The test
   generator is supposed to define instructions, at least one group of
   instructions, optionally, a sequence of groups.

   It should also define a main() function that outputs the initial
   lines of the assembler input and of the test control file, that
   also contains the disassembler output.  The main() funcion may
   optionally set skip_list too, before calling output_groups() or
   output_insns().  */

/* Define to 1 to avoid repeating instructions and to use a simpler
   register/constant generation mechanism.  This makes it much easier
   to verify that the generated bit patterns are correct.  */
#ifndef SIMPLIFY_OUTPUT
#define SIMPLIFY_OUTPUT 0
#endif

/* Define to 0 to avoid generating disassembler tests.  */
#ifndef DISASSEMBLER_TEST
#define DISASSEMBLER_TEST 1
#endif

/* Define to the number of times to repeat the generation of each
   insn.  It's best to use prime numbers, to improve randomization.  */
#ifndef INSN_REPEAT
#define INSN_REPEAT 5
#endif

/* Define in order to get randomization_counter printed, as a comment,
   in the disassembler output, after each insn is emitted.  */
#ifndef OUTPUT_RANDOMIZATION_COUNTER
#define OUTPUT_RANDOMIZATION_COUNTER 0
#endif

/* Other configuration macros are DEFINED_WORD and DEFINED_FUNC_ARG,
   see below.  */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/* It is expected that the main program defines the type `word' before
   includeing this.  */
#ifndef DEFINED_WORD
typedef unsigned long long word;
#endif

/* This struct is used as the output area for each function.  It
   should store in as_in a pointer to the string to be output to the
   assembler; in dis_out, the string to be expected in return from the
   disassembler, and in bits the bits of the instruction word that are
   enabled by the assembly fragment.  */
typedef struct
{
  char * as_in;
  char * dis_out;
  word   bits;
} insn_data;

#ifndef DEFINED_FUNC_ARG
/* This is the struct that feeds information to each function.  You're
   free to extend it, by `typedef'ing it before including this file,
   and defining DEFINED_FUNC_ARG.  You may even reorder the fields,
   but do not remove any of the existing fields.  */
typedef struct
{
  int    i1;
  int    i2;
  int    i3;
  void * p1;
  void * p2;
  word   w;
} func_arg;
#endif

/* This is the struct whose arrays define insns.  Each func in the
   array will be called, in sequence, being given a pointer to the
   associated arg and a pointer to a zero-initialized output area,
   that it may fill in.  */
typedef struct
{
  int (*    func) (func_arg *, insn_data *);
  func_arg  arg;
} func;

/* Use this to group insns under a name.  */
typedef struct
{
  const char * name;
  func **      insns;
} group_t;

/* This is the size of each instruction.  Use `insn_size_bits' instead
   of `insn_bits' in an insn defition to modify it.  */
int insn_size = 4;

/* The offset of the next insn, as expected in the disassembler
   output.  */
int current_offset = 0;

/* The offset and name of the last label to be emitted.  */
int last_label_offset = 0;
const char * last_label_name = 0;

/* This variable may be initialized in main() to `argv+1', if
   `argc>1', so that tests are emitted only for instructions that
   match exactly one of the given command-line arguments.  If it is
   NULL, tests for all instructions are emitted.  It must be a
   NULL-terminated array of pointers to strings (just like
   `argv+1').  */
char ** skip_list = 0;

/* This is a counter used to walk the various arrays of ``random''
   operand generation.  In simplified output mode, it is zeroed after
   each insn, otherwise it just keeps growing.  */
unsigned randomization_counter = 0;

/* Use `define_insn' to create an array of funcs to define an insn,
   then `insn' to refer to that insn when defining an insn group.  */
#define define_insn(insname, funcs...) \
  func i_ ## insname[] = { funcs, { 0 } }
#define insn(insname) (i_ ## insname)

/* Use these to output a comma followed by an optional space, a single
   space, a plus sign, left and right square brackets and parentheses,
   all of them properly quoted.  */
#define comma  literal_q (", ", ", ?")
#define space  literal (" ")
#define tab    literal ("\t")
#define plus   literal_q ("+", "\\+")
#define lsqbkt literal_q ("[", "\\[")
#define rsqbkt literal_q ("]", "\\]")
#define lparen literal_q ("(", "\\(")
#define rparen literal_q (")", "\\)")

/* Use this as a placeholder when you define a macro that expects an
   argument, but you don't have anything to output there.  */
int
nothing (func_arg *arg, insn_data *data)
#define nothing { nothing }
{
  return 0;
}

/* This is to be used in the argument list of define_insn, causing a
   string to be copied into both the assembly and the expected
   disassembler output.  It is assumed not to modify the binary
   encoding of the insn.  */
int
literal (func_arg *arg, insn_data *data)
#define literal(s) { literal, { p1: (s) } }
{
  data->as_in = data->dis_out = strdup ((char *) arg->p1);
  return 0;
}

/* The characters `[', `]', `\\' and `^' must be quoted in the
   disassembler-output matcher.  If a literal string contains any of
   these characters, use literal_q instead of literal, and specify the
   unquoted version (for as input) as the first argument, and the
   quoted version (for expected disassembler output) as the second
   one.  */
int
literal_q (func_arg *arg, insn_data *data)
#define literal_q(s,q) { literal_q, { p1: (s), p2: (q) } }
{
  data->as_in = strdup ((char *) arg->p1);
  data->dis_out = strdup ((char *) arg->p2);
  return 0;
}

/* Given an insn name, check whether it should be skipped or not,
   depending on skip_list.  Return non-zero if the insn is to be
   skipped.  */
int
skip_insn (char *name)
{
  char **test;

  if (! skip_list)
    return 0;

  for (test = skip_list; * test; ++ test)
    if (strcmp (name, * test) == 0)
      return 0;

  return 1;
}

/* Use this to emit the actual insn name, with its opcode, in
   architectures with fixed-length instructions.  */
int
insn_bits (func_arg *arg, insn_data *data)
#define insn_bits(name,bits) \
  { insn_bits, { p1: # name, w: bits } }
{
  if (skip_insn ((char *) arg->p1))
    return 1;
  data->as_in = data->dis_out = strdup ((char *) arg->p1);
  data->bits = arg->w;
  return 0;
}

/* Use this to emit the insn name and its opcode in architectures
   without a variable instruction length.  */ 
int
insn_size_bits (func_arg *arg, insn_data *data)
#define insn_size_bits(name,size,bits) \
  { insn_size_bits, { p1: # name, i1: size, w: bits } }
{
  if (skip_insn ((char *) arg->p1))
    return 1;
  data->as_in = data->dis_out = strdup ((char *) arg->p1);
  data->bits = arg->w;
  insn_size = arg->i1;
  return 0;
}

/* Use this to advance the random generator by one, in case it is
   generating repetitive patterns.  It is usually good to arrange that
   each insn consumes a prime number of ``random'' numbers, or, at
   least, that it does not consume an exact power of two ``random''
   numbers.  */
int
tick_random (func_arg *arg, insn_data *data)
#define tick_random { tick_random }
{
  ++ randomization_counter;
  return 0;
}

/* Select the next ``random'' number from the array V of size S, and
   advance the counter.  */
#define get_bits_from_size(V,S) \
  ((V)[randomization_counter ++ % (S)])

/* Utility macros.  `_get_bits_var', used in some macros below, assume
   the names of the arrays used to define the ``random'' orders start
   with `random_order_'.  */
#define _get_bits_var(N) (random_order_ ## N)
#define _get_bits_size(V) (sizeof (V) / sizeof * (V))

/* Use this within a `func_arg' to select one of the arrays below (or
   any other array that starts with random_order_N.  */
#define mk_get_bits(N) \
  p2: _get_bits_var (N), i3: _get_bits_size (_get_bits_var (N))

/* Simplified versions of get_bits_from_size for when you have access
   to the array, so that its size can be implicitly calculated.  */
#define get_bits_from(V) get_bits_from_size ((V),_get_bits_size ((V)))
#define get_bits(N)      get_bits_from (_get_bits_var (N))


/* Use `2u' to generate 2-bit unsigned values.  Good for selecting
   registers randomly from a set of 4 registers.  */
unsigned random_order_2u[] =
  {
    /* This sequence was generated by hand so that no digit appers more
       than once in any horizontal or vertical line.  */
    0, 1, 3, 2,
    2, 0, 1, 3,
    1, 3, 2, 0,
    3, 2, 0, 1
  };

/* Use `3u' to generate 3-bit unsigned values.  Good for selecting
   registers randomly from a set of 8 registers.  */
unsigned random_order_3u[] =
  {
    /* This sequence was generated by:
       f(k) = 3k mod 8
       except that the middle pairs were swapped.  */
    0, 6, 3, 1, 4, 2, 7, 5,
    /* This sequence was generated by:
       f(k) = 5k mod 8
       except that the middle pairs were swapped.  */
    0, 2, 5, 7, 4, 6, 1, 3,
  };

/* Use `4u' to generate 4-bit unsigned values.  Good for selecting
   registers randomly from a set of 16 registers.  */
unsigned random_order_4u[] =
  {
    /* This sequence was generated by:
       f(k) = 5k mod 16
       except that the middle pairs were swapped.  */
    0,  5, 15, 10, 9,  4, 14,  3,
    8, 13,  7,  2, 1, 12,  6, 11,
    /* This sequence was generated by:
       f(k) = 7k mod 16
       except that the middle pairs were swapped.  */
    0,  7,  5, 14,  3, 12, 10, 1,
    8, 15, 13,  6, 11,  4,  2, 9,
  };

/* Use `5u' to generate 5-bit unsigned values.  Good for selecting
   registers randomly from a set of 32 registers.  */
unsigned random_order_5u[] =
  {
    /* This sequence was generated by:
       f(k) = (13k) mod 32
       except that the middle pairs were swapped.  */
    0, 26, 13,  7, 20, 14,  1, 27,
    8, 2,  21, 15, 28, 22,  9,  3,
    16, 10, 29, 23,  4, 30, 17, 11,
    24,  18, 5, 31, 12, 6,  25, 19
  };

/* Use `7s' to generate 7-bit signed values.  Good for selecting
   ``interesting'' constants from -64 to +63.  */
int random_order_7s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    0, -1, -64, 63, -32, 32, 24, -20,
    9, -27, -31, 33, 40, -2, -5, 1
  };

/* Use `8s' to generate 8-bit signed values.  Good for selecting
   ``interesting'' constants from -128 to +127.  */
int random_order_8s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    0, -1, -128, 127, -32, 32, 24, -20,
    73, -27, -95, 33, 104, -2, -69, 1
  };

/* Use `9s' to generate 9-bit signed values.  Good for selecting
   ``interesting'' constants from -256 to +255.  */
int random_order_9s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    0, -1, -256, 255, -64, 64, 72, -40,
    73, -137, -158, 37, 104, -240, -69, 1
  };

/* Use `16s' to generate 16-bit signed values.  Good for selecting
   ``interesting'' constants from -32768 to +32767.  */
int random_order_16s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    -32768,
    32767,
    (-1 << 15) | (64 << 8) | 32,
    (64 << 8) | 32,
    0x1234,
    (-1 << 15) | 0x8765,
    0x0180,
    (-1 << 15) | 0x8001
};

/* Use `24s' to generate 24-bit signed values.  Good for selecting
   ``interesting'' constants from -2^23 to 2^23-1.  */
int random_order_24s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    -1 << 23,
    1 << 23 -1,
    (-1 << 23) | (((64 << 8) | 32) << 8) | 16,
    (((64 << 8) | 32) << 8) | 16,
    0x123456,
    (-1 << 23) | 0x876543,
    0x01ff80,
    (-1 << 23) | 0x80ff01
};

/* Use `32s' to generate 32-bit signed values.  Good for selecting
   ``interesting'' constants from -2^31 to 2^31-1.  */
int random_order_32s[] =
  {
    /* Sequence generated by hand, to explore limit values and a few
       intermediate values selected by chance.  Keep the number of
       intermediate values low, to ensure that the limit values are
       generated often enough.  */
    -1 << 31,
    1 << 31 - 1,
    (-1 << 31) | (((((64 << 8) | 32) << 8) | 16) << 8) | 8,
    (((((64 << 8) | 32) << 8) | 16) << 8) | 8,
    0x12345678,
    (-1 << 31) | 0x87654321,
    0x01ffff80,
    (-1 << 31) | 0x80ffff01
  };

/* This function computes the number of digits needed to represent a
   given number.  */
unsigned long
ulen (unsigned long i, unsigned base)
{
  int count = 0;

  if (i == 0)
    return 1;
  for (; i > 0; ++ count)
    i /= base;
  return count;
}

/* Use this to generate a signed constant of the given size, shifted
   by the given amount, with the specified endianness.  */
int
signed_constant (func_arg * arg, insn_data * data)
#define signed_constant(bits, shift, revert) \
  { signed_constant, { i1: shift, i2: bits * (revert ? -1 : 1), \
		       mk_get_bits (bits ## s) } }
{
  long val = get_bits_from_size ((unsigned *) arg->p2, arg->i3);
  int len = (val >= 0 ? ulen (val, 10) : (1 + ulen (-val, 10)));
  int nbits = (arg->i2 >= 0 ? arg->i2 : -arg->i2);
  word bits = ((word) val) & (((((word) 1) << (nbits - 1)) << 1) - 1);

  data->as_in = data->dis_out = malloc (len + 1);
  sprintf (data->as_in, "%ld", val);
  if (arg->i2 < 0)
    {
      word rbits = 0;

      do
	{
	  rbits <<= 8;
	  rbits |= bits & 0xff;
	  bits >>= 8;
	  nbits -= 8;
	}
      while (nbits > 0);

      bits = rbits;
    }
  data->bits = bits << arg->i1;

  return 0;
}

/* Use this to generate a unsigned constant of the given size, shifted
   by the given amount, with the specified endianness.  */
int
unsigned_constant (func_arg * arg, insn_data * data)
#define unsigned_constant(bits, shift, revert) \
  { unsigned_constant, { i1: shift, i2: bits * (revert ? -1 : 1), \
			 mk_get_bits (bits ## s) } }
{
  int nbits = (arg->i2 >= 0 ? arg->i2 : -arg->i2);
  unsigned long val =
    get_bits_from_size ((unsigned *) arg->p2, arg->i3)
    & (((((word) 1) << (nbits - 1)) << 1) - 1);
  int len = ulen (val, 10);
  word bits = val;

  data->as_in = data->dis_out = malloc (len + 1);
  sprintf (data->as_in, "%lu", val);
  if (arg->i2 < 0)
    {
      word rbits = 0;

      do
	{
	  rbits <<= 8;
	  rbits |= bits & 0xff;
	  bits >>= 8;
	  nbits -= 8;
	}
      while (nbits > 0);

      bits = rbits;
    }
  data->bits = bits << arg->i1;

  return 0;
}

/* Use this to generate an absolute address of the given size, shifted
   by the given amount, with the specified endianness.  */
int
absolute_address (func_arg *arg, insn_data *data)
#define absolute_address (bits, shift, revert) \
  { absolute_address, { i1: shift, i2: bits * (revert ? -1 : 1), \
			mk_get_bits (bits ## s) } }
{
  int nbits = (arg->i2 >= 0 ? arg->i2 : -arg->i2);
  unsigned long val =
    get_bits_from_size ((unsigned *) arg->p2, arg->i3)
    & (((((word) 1) << (nbits - 1)) << 1) - 1);
  word bits = val;

  data->as_in = malloc (ulen (val, 10) + 1);
  sprintf (data->as_in, "%lu", val);
  data->dis_out = malloc (nbits / 4 + 11);
  sprintf (data->dis_out, "0*%0*lx <[^>]*>", nbits / 4, val);
  if (arg->i2 < 0)
    {
      word rbits = 0;

      do
	{
	  rbits <<= 8;
	  rbits |= bits & 0xff;
	  bits >>= 8;
	  nbits -= 8;
	}
      while (nbits > 0);

      bits = rbits;
    }
  data->bits = bits << arg->i1;

  return 0;
}

/* Use this to generate a register name that starts with a given
   prefix, and is followed by a number generated by `gen' (see
   mk_get_bits below).  The register number is shifted `shift' bits
   left before being stored in the binary insn.  */
int
reg_p (func_arg *arg, insn_data *data)
#define reg_p(prefix,shift,gen) \
  { reg_p, { i1: (shift), p1: (prefix), gen } }
{
  unsigned reg = get_bits_from_size ((unsigned *) arg->p2, arg->i3);
  char *regname = (char *) arg->p1;

  data->as_in = data->dis_out = malloc (strlen (regname) + ulen (reg, 10) + 1);
  sprintf (data->as_in, "%s%u", regname, reg);
  data->bits = reg;
  data->bits <<= arg->i1;
  return 0;
}

/* Use this to generate a register name taken from an array.  The
   index into the array `names' is to be produced by `gen', but `mask'
   may be used to filter out some of the bits before choosing the
   disassembler output and the bits for the binary insn, shifted left
   by `shift'.  For example, if registers have canonical names, but
   can also be referred to by aliases, the array can be n times larger
   than the actual number of registers, and the mask is then used to
   pick the canonical name for the disassembler output, and to
   eliminate the extra bits from the binary output.  */
int
reg_r (func_arg *arg, insn_data *data)
#define reg_r(names,shift,mask,gen) \
  { reg_r, { i1: (shift), i2: (mask), p1: (names), gen } }
{
  unsigned reg = get_bits_from_size ((unsigned *) arg->p2, arg->i3);
  
  data->as_in = strdup (((const char **) arg->p1)[reg]);
  reg &= arg->i2;
  data->dis_out = strdup (((const char **) arg->p1)[reg]);
  data->bits = reg;
  data->bits <<= arg->i1;
  return 0;
}

/* Given a NULL-terminated array of insns-definitions (pointers to
   arrays of funcs), output test code for the insns to as_in (assembly
   input) and dis_out (expected disassembler output).  */
void
output_insns (func **insn, FILE *as_in, FILE *dis_out)
{
  for (; *insn; ++insn)
    {
      insn_data *data;
      func *parts = *insn;
      int part_count = 0, r;

      /* Figure out how many funcs have to be called.  */
      while (parts[part_count].func)
	++part_count;

      /* Allocate storage for the output area of each func.  */
      data = (insn_data*) malloc (part_count * sizeof (insn_data));

#if SIMPLIFY_OUTPUT
      randomization_counter = 0;
#else
      /* Repeat each insn several times.  */
      for (r = 0; r < INSN_REPEAT; ++r)
#endif
	{
	  unsigned saved_rc = randomization_counter;
	  int part;
	  word bits = 0;

	  for (part = 0; part < part_count; ++part)
	    {
	      /* Zero-initialize the storage.  */
	      data[part].as_in = data[part].dis_out = 0;
	      data[part].bits = 0;
	      /* If a func returns non-zero, skip this line.  */
	      if (parts[part].func (&parts[part].arg, &data[part]))
		goto skip;
	      /* Otherwise, get its output bit pattern into the total
	         bit pattern.  */
	      bits |= data[part].bits;
	    }
	  
	  if (as_in)
	    {
	      /* Output the whole assembly line.  */
	      fputc ('\t', as_in);
	      for (part = 0; part < part_count; ++part)
		if (data[part].as_in)
		  fputs (data[part].as_in, as_in);
	      fputc ('\n', as_in);
	    }

	  if (dis_out)
	    {
	      /* Output the disassembler expected output line,
	         starting with the offset and the insn binary pattern,
	         just like objdump outputs.  Because objdump sometimes
	         inserts spaces between each byte in the insn binary
	         pattern, make the space optional.  */
	      fprintf (dis_out, "0*%x <", current_offset);
	      if (last_label_name)
		if (current_offset == last_label_offset)
		  fputs (last_label_name, dis_out);
		else
		  fprintf (dis_out, "%s\\+0x%x", last_label_name,
			   current_offset - last_label_offset);
	      else
		fputs ("[^>]*", dis_out);
	      fputs ("> ", dis_out);
	      for (part = insn_size; part-- > 0; )
		fprintf (dis_out, "%02x ?", (int)(bits >> (part * 8)) & 0xff);
	      fputs (" *\t", dis_out);
	      
#if DISASSEMBLER_TEST
	      for (part = 0; part < part_count; ++part)
		if (data[part].dis_out)
		  fputs (data[part].dis_out, dis_out);
#else
	      /* If we're not testing the DISASSEMBLER, just match
	         anything.  */
	      fputs (".*", dis_out);
#endif
	      fputc ('\n', dis_out);
#if OUTPUT_RANDOMIZATION_COUNTER
	      fprintf (dis_out, "# %i\n", randomization_counter);
#endif
	    }

	  /* Account for the insn_size bytes we've just output.  */
	  current_offset += insn_size;

	  /* Release the memory that each func may have allocated.  */
	  for (; part-- > 0;)
	    {
	    skip:
	      if (data[part].as_in)
		free (data[part].as_in);
	      if (data[part].dis_out
		  && data[part].dis_out != data[part].as_in)
		free (data[part].dis_out);
	    }

	  /* There's nothing random here, don't repeat this insn.  */
	  if (randomization_counter == saved_rc)
	    break;
	}

      free (data);
    }
}

/* For each group, output an asm label and the insns of the group.  */
void
output_groups (group_t group[], FILE *as_in, FILE *dis_out)
{
  for (; group->name; ++group)
    {
      fprintf (as_in, "%s:\n", group->name);
      fprintf (dis_out, "# %s:\n", group->name);
      last_label_offset = current_offset;
      last_label_name = group->name;
      output_insns (group->insns, as_in, dis_out);
    }
}

#endif