Subversion Repositories tendra.SVN

Rev

Rev 5 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
6 7u83 2
 * Copyright (c) 2002-2006 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
33
 
34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
42
 
43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
45
 
46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
49
 
50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
53
 
54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
61
/**********************************************************************
62
$Author: release $
63
$Date: 1998/01/17 15:55:46 $
64
$Revision: 1.1.1.1 $
65
$Log: case_opt.c,v $
66
 * Revision 1.1.1.1  1998/01/17  15:55:46  release
67
 * First version to be checked into rolling release.
68
 *
69
 * Revision 1.2  1996/11/18  14:36:49  currie
70
 * case_opt fixes
71
 *
72
 * Revision 1.1  1995/04/06  10:44:05  currie
73
 * Initial revision
74
 *
75
***********************************************************************/
76
/************************************************************
77
  OPTIMIZATION of case_tag's
78
  Author: mjg
79
************************************************************/
80
 
81
#include "config.h"
82
#include "common_types.h"
83
#include "installglob.h"
84
#include "exp.h"
85
#include "expmacs.h"
86
#include "tags.h"
87
#include "check.h"
88
#include "flags.h"
89
#include "check_id.h"
90
#include "const.h"
91
#include "foralls.h"
92
#include "shapemacs.h"
93
#include "glopt.h"
94
#include "inline.h"
95
#include "global_opt.h"
96
#include "case_opt.h"
97
#include "externs.h"
98
#include "me_fns.h"
99
#include "xalloc.h"
100
#include "install_fns.h"
101
#include "szs_als.h"
102
 
103
#ifndef jump_table_density
104
#define jump_table_density  60
105
#endif
106
#ifndef min_jump_table_size
107
#define min_jump_table_size 10
108
#endif
109
#ifndef max_jump_table_size
110
#define max_jump_table_size 100
111
#endif
112
#ifndef min_no_of_default_destinations
113
#define min_no_of_default_destinations 3
114
#endif
115
 
6 7u83 116
static int density(exp *, int, int, int);
117
static exp exhaustive_conditional_maker(int, int, exp);
118
static exp inexhaustive_conditional_maker(int, int, exp, exp);
119
static exp set_up_sequence(exp, exp, ntest, int, exp, int);
120
static exp set_up_assign(exp, int);
121
static exp set_up_unsigned_test(exp, exp, int, ntest);
122
static exp like_me_q1(int, ntest, exp, exp, exp, unsigned char);
2 7u83 123
 
124
 
125
/* VARIABLES */
126
 
127
static int  no_of_nodes;
6 7u83 128
static exp *node_start;
129
static exp *node_end;
2 7u83 130
static double *node_weight;
131
static unsigned char *node_start_flag;
132
static unsigned char *node_end_flag;
133
 
134
 
135
/* PROCEDURES */
136
 
137
 
138
 
139
 
140
 
141
/*
142
 * case_optimisation takes a case_tag and an ident_tag and
143
 * splits up the case_tag into parts which it thinks should
144
 * be done as jump tables.
145
 */
6 7u83 146
exp
147
case_optimisation(exp body, exp id, shape shape_of_case, exp control_expression)
2 7u83 148
{
6 7u83 149
	exp t;
150
	exp *ELEMENTS;
151
	int i;
152
	int n;
153
	int no_of_cases = 1;
154
	int jump_table_present = 0;
2 7u83 155
 
6 7u83 156
	no_of_nodes = 0;
157
	/* Calculate the number of cases in the case_tag */
158
	t = body;
159
	while (!last(t)) {
160
		no_of_cases = no_of_cases + 1;
161
		t = bro(t);
162
	}
2 7u83 163
 
6 7u83 164
	ELEMENTS = (exp *)xcalloc(no_of_cases, sizeof(exp));
165
	node_start = (exp *)xcalloc(no_of_cases, sizeof(exp));
166
	node_end = (exp *)xcalloc(no_of_cases, sizeof(exp));
167
	node_weight = (double *)xcalloc(no_of_cases, sizeof(double));
2 7u83 168
 
6 7u83 169
	/* Set up the values of these arrays * First set up the ELEMENTS array
170
	 */
171
	t = body;
172
	for (i = 0; i < no_of_cases; i++) {
173
		ELEMENTS[i] = t;
174
		t = bro(t);
175
	}
176
	n = 0;
177
	/* Calculation of where should do jump tables * This sets up the arrays
178
	   node_weight, node_start and node_end */
179
	while (n < no_of_cases) {
180
		int z;
181
		double node_weight_sum = 0.0;
182
		i = no_of_cases - 1;
183
		while (density(ELEMENTS, n, i,
184
			       is_signed(sh(control_expression)))
185
		       < jump_table_density) {
186
			i--;
187
		}
188
		for (z = n; z <= i; z++) {
189
			if (son(ELEMENTS[z]) != nilexp) {
190
				if (is_signed(sh(control_expression))) {
191
					node_weight_sum +=
192
					    ((double)no(son(ELEMENTS[z])) -
193
					     (double)no(ELEMENTS[z]));
194
				} else {
195
					node_weight_sum +=
196
					    ((double)(unsigned long)no(son(ELEMENTS[z]))
197
					     - (double)(unsigned long)no(ELEMENTS[z]));
198
				}
199
			}
200
			node_weight_sum += 1.0;
201
		}
2 7u83 202
 
6 7u83 203
		if (node_weight_sum < (double)min_jump_table_size) {
204
			i = n;
205
		}
206
		if (node_weight_sum > (double)max_jump_table_size) {
207
			i=n;
208
		}
209
		if ((i - n) < min_no_of_default_destinations) {
210
			i = n;
211
		}
2 7u83 212
 
6 7u83 213
		/* Lump together into a jump_table or a single * Sets up the
214
		   node_start pointers */
215
		node_start[no_of_nodes] = ELEMENTS[n];
2 7u83 216
 
6 7u83 217
		/* Sets up the node_end pointers */
218
		node_end[no_of_nodes] = (son(ELEMENTS[i]) == nilexp
219
					 ? ELEMENTS[i] : son(ELEMENTS[i]));
2 7u83 220
 
6 7u83 221
		/* sets up the node_weight of the node */
222
		node_weight[no_of_nodes] = 0.0;
223
		for (z = n; z <= i; z++) {
224
			if (son(ELEMENTS[z]) != nilexp) {
225
				if (is_signed(sh(control_expression))) {
226
					node_weight[no_of_nodes] +=
227
					    ((double)no(son(ELEMENTS[z])) -
228
					     (double)no(ELEMENTS[z]));
229
				} else {
230
					node_weight[no_of_nodes] +=
231
					    ((double)(unsigned long)no(son(ELEMENTS[z])) -
232
					     (double)(unsigned long)no(ELEMENTS[z]));
233
				}
234
			}
235
			node_weight[no_of_nodes] += 1.0;
236
		}
237
		if (n != i) {
238
			jump_table_present = 1;
239
		}
2 7u83 240
 
6 7u83 241
		no_of_nodes = no_of_nodes + 1;
242
		bro(ELEMENTS[i]) = nilexp;
243
		/* Chops up the list for later use */
244
		setlast(ELEMENTS[i]);
245
		/* Sets the last of ELEMENTS[i] so can be substituted directly into
246
		   new case_tag's */
247
		n = i + 1;
248
	}
2 7u83 249
 
250
#if has_byte_ops
6 7u83 251
	if (!jump_table_present) {
252
		kill_exp(son(id), son(id));
253
		son(id) = control_expression;
254
		sh(id) = sh(control_expression);
255
		t = body;
256
		for (;;) {
257
			sh(t) = sh(control_expression);
258
			if (son(t) != nilexp) {
259
				sh(son(t)) = sh(control_expression);
260
			}
261
			if (last(t)) {
262
				break;
263
			}
264
		}
265
	} else {
266
		kill_exp(control_expression, control_expression);
267
	}
2 7u83 268
#else
6 7u83 269
	kill_exp(control_expression, control_expression);
270
	UNUSED(jump_table_present);
2 7u83 271
#endif
272
 
6 7u83 273
	/* Set up the node_start_flag and node_end_flag arrays */
274
	node_start_flag =
275
	    (unsigned char *)xcalloc(no_of_nodes, sizeof(unsigned char));
276
	node_end_flag =
277
	    (unsigned char *)xcalloc(no_of_nodes, sizeof(unsigned char));
278
	for (i=0; i < no_of_nodes; i++) {
279
		node_start_flag[i] = node_end_flag[i] = 0;
280
	}
281
	if (shape_of_case == f_bottom) {
282
		t = exhaustive_conditional_maker(0, no_of_nodes - 1, id);
283
	}
284
	if (shape_of_case == f_top) {
285
		exp COND__TAG;
286
		exp LABST__TAG;
287
		exp TOP__TAG;
288
		exp CLEAR__TAG;
2 7u83 289
 
6 7u83 290
		TOP__TAG = getexp(f_top, nilexp, 0, nilexp, nilexp, 0, 0,
291
				  top_tag);
292
		CLEAR__TAG = getexp(f_top, nilexp, 0, nilexp, nilexp, 0, 0,
293
				    clear_tag);
294
		LABST__TAG = me_b3(sh(TOP__TAG), CLEAR__TAG, TOP__TAG,
295
				   labst_tag);
296
		t = inexhaustive_conditional_maker(0, no_of_nodes - 1, id,
297
						   LABST__TAG);
298
		COND__TAG = me_b3(f_top, t, LABST__TAG, cond_tag);
299
		t = COND__TAG;
300
	}
301
	xfree((void*)ELEMENTS);
302
	xfree((void*)node_start);
303
	xfree((void*)node_end);
304
	xfree((void*)node_weight);
305
	xfree((void*)node_start_flag);
306
	xfree((void*)node_end_flag);
307
	return t;
2 7u83 308
}
309
 
310
 
311
/*
312
 * density is used for calculating whether the elements of the
313
 * case_tag should be made into jump tables.
314
 */
6 7u83 315
static int
316
density(exp *ELEMENTS, int start, int end, int sgn)
2 7u83 317
{
6 7u83 318
	int index;
319
	double numerator;
320
	double denominator;
2 7u83 321
 
6 7u83 322
	if (son(ELEMENTS[end]) == nilexp) {
323
		if (sgn) {
324
			denominator = (double)no(ELEMENTS[end]) -
325
			    (double)no(ELEMENTS[start]);
326
		} else {
327
			denominator = (double)(unsigned long)no(ELEMENTS[end]) -
328
			    (double)(unsigned long)no(ELEMENTS[start]);
329
		}
330
	} else {
331
		if (sgn) {
332
			denominator = (double)no(son(ELEMENTS[end])) -
333
			    (double)no(ELEMENTS[start]);
334
		} else {
335
			denominator =
336
			    (double)(unsigned long)no(son(ELEMENTS[end])) -
337
			    (double)(unsigned long)no(ELEMENTS[start]);
338
		}
339
	}
2 7u83 340
 
6 7u83 341
	denominator = denominator + 1.0;
342
	numerator = 0.0;
343
	for (index = start; index <= end; index++) {
344
		if (son(ELEMENTS[index]) == nilexp) {
345
			numerator = numerator + 1.0;
346
		} else {
347
			if (sgn) {
348
				numerator = numerator +
349
				    ((double)no(son(ELEMENTS[index])) -
350
				     (double)no(ELEMENTS[index])) + 1.0;
351
			} else {
352
				numerator = numerator +
353
				    ((double)(unsigned long)no(son(ELEMENTS[index])) -
354
				     (double)(unsigned long)no(ELEMENTS[index])) + 1.0;
355
			}
356
		}
357
	}
358
	return((int)(100.0 * (numerator / denominator)));
2 7u83 359
}
360
 
361
 
362
/*
363
 * set_up_sequence creates a simple sequence with a
364
 * test_tag.
365
 */
6 7u83 366
static exp
367
set_up_sequence(exp left, exp right, ntest test, int integer_value, exp id,
368
		int probability)
2 7u83 369
{
6 7u83 370
	exp SEQ__TAG;
371
	exp ZERO__TAG;
372
	exp TEST__TAG;
373
	exp NAME__TAG;
374
	exp VAL__TAG;
375
	exp CONT__TAG;
2 7u83 376
 
6 7u83 377
	/* sets up the test_tag */
378
	NAME__TAG = me_obtain(id);
379
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
380
	VAL__TAG = me_shint(sh(CONT__TAG), integer_value);
381
	TEST__TAG = like_me_q1(probability, test, right, CONT__TAG, VAL__TAG,
382
			       test_tag);
383
	/* sets up the seq_tag for the conditional */
384
	ZERO__TAG = me_u3(f_top, TEST__TAG, 0);
385
	SEQ__TAG = me_b3(sh(left), ZERO__TAG, left, seq_tag);
386
	return SEQ__TAG;
2 7u83 387
}
388
 
389
 
390
/*
391
 * set_up_conditional creates a conditional based on a simple
392
 * integer test.
393
 */
6 7u83 394
static exp
395
set_up_conditional(exp left, exp right, ntest test, int integer_value, exp id,
396
		   int probability)
2 7u83 397
{
6 7u83 398
	exp CLEAR__TAG;
399
	exp LABST__TAG;
400
	exp NAME__TAG;
401
	exp VAL__TAG;
402
	exp TEST__TAG;
403
	exp ZERO__TAG;
404
	exp SEQ__TAG;
405
	exp COND__TAG;
406
	exp CONT__TAG;
2 7u83 407
 
6 7u83 408
	/* Sets up the labst_tag for the conditional */
409
	CLEAR__TAG = getexp(f_top, nilexp, 0, nilexp, nilexp, 0, 0, clear_tag);
410
	LABST__TAG = me_b3(sh(right), CLEAR__TAG, right, labst_tag);
411
	/* sets up the test_tag */
412
	NAME__TAG = me_obtain(id);
413
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
414
	VAL__TAG = me_shint(sh(CONT__TAG), integer_value);
415
	TEST__TAG = like_me_q1(probability, test, LABST__TAG, CONT__TAG,
416
			       VAL__TAG, test_tag);
417
	/* sets up the seq_tag for the conditional */
418
	ZERO__TAG = me_u3(f_top, TEST__TAG, 0);
419
	SEQ__TAG = me_b3(sh(left), ZERO__TAG, left, seq_tag);
420
	/* sets up the cond_tag */
421
	COND__TAG = me_b3(f_bottom, SEQ__TAG, LABST__TAG, cond_tag);
422
	return COND__TAG;
2 7u83 423
}
424
 
425
 
426
/*
427
 * set_up_exhaustive_case does exactly what it suggests.
428
 */
6 7u83 429
static exp
430
set_up_exhaustive_case(exp body_of_case, exp id)
2 7u83 431
{
6 7u83 432
	exp NAME__TAG;
433
	exp CASE__TAG;
434
	exp CONT__TAG;
435
	exp r;
2 7u83 436
 
6 7u83 437
	NAME__TAG = me_obtain(id);
438
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
439
	CASE__TAG = getexp(f_bottom, nilexp, 0, CONT__TAG, nilexp, 0, 0,
440
			   case_tag);
441
	bro(CONT__TAG) = body_of_case;
442
	clearlast(CONT__TAG);
443
	r = body_of_case;
444
	while (!last(r)) {
445
		r = bro(r);
446
	}
2 7u83 447
 
6 7u83 448
	bro(r) = CASE__TAG;
449
	return CASE__TAG;
2 7u83 450
}
451
 
452
 
453
/*
454
 * set_up_inexhaustive_case does exactly what it suggests.
455
 */
6 7u83 456
static exp
457
set_up_inexhaustive_case(exp body_of_case, exp id, exp default_exp)
2 7u83 458
{
6 7u83 459
	exp NAME__TAG;
460
	exp GOTO__TAG;
461
	exp CASE__TAG;
462
	exp ZERO__TAG;
463
	exp SEQ__TAG;
464
	exp CONT__TAG;
465
	exp r;
2 7u83 466
 
6 7u83 467
	NAME__TAG = me_obtain(id);
468
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
469
	/* shape of case is f_top since it is not exhaustive */
470
	CASE__TAG = getexp(f_top, nilexp, 0, CONT__TAG, nilexp, 0, 0, case_tag);
471
	bro(CONT__TAG) = body_of_case;
472
	clearlast(CONT__TAG);
473
	r = body_of_case;
474
	while (!last(r)) {
475
		r = bro(r);
476
	}
477
	bro(r) = CASE__TAG;
478
	GOTO__TAG = getexp(f_bottom, nilexp, 0, nilexp, nilexp, 0, 0, goto_tag);
479
	pt(GOTO__TAG) = default_exp;
480
	no(son(default_exp)) ++;
481
	ZERO__TAG = me_u3(f_top, CASE__TAG, 0);
482
	/* doesn't matter what shape zero_tag is */
483
	SEQ__TAG = me_b3(f_bottom, ZERO__TAG, GOTO__TAG, seq_tag);
484
	return SEQ__TAG;
2 7u83 485
}
486
 
6 7u83 487
 
2 7u83 488
/*
489
 * like_me_q1 sets up a test_tag and is very similar to me_q1.
490
 * me_q1 is found in me_fns.c
491
 */
6 7u83 492
static exp
493
like_me_q1(int prob, ntest nt, exp lab, exp arg1, exp arg2, unsigned char nm)
2 7u83 494
{
6 7u83 495
	exp r;
2 7u83 496
 
6 7u83 497
	r = getexp(f_top, nilexp, 0, arg1, lab, 0, 0, nm);
498
	no(r) = prob;
499
	settest_number(r, nt);
500
	setbro(arg1, arg2);
501
	clearlast(arg1);
502
	++no(son(lab));
503
	setfather(r, arg2);
504
	return r;
2 7u83 505
}
506
 
507
 
508
/*
509
 *  find_the_split_value is used by exhaustive_conditional_maker
510
 *  and inexhaustive_conditional_maker in order to calculate
511
 *  where to do a comparison.
512
 */
6 7u83 513
static int
514
find_the_split_value(int start, int end)
2 7u83 515
{
6 7u83 516
	int w;
517
	int split_value;
518
	double halfway_value;
519
	double best_diff;
520
	double count;
2 7u83 521
 
6 7u83 522
	count = 0.0;
523
	halfway_value = 0.0;
524
	for (w = start; w <= end; w++) {
525
		halfway_value += node_weight[w];
526
	}
527
	halfway_value = halfway_value / 2.0;
528
	best_diff = node_weight[start] - halfway_value;
529
	if (best_diff < 0.0) {
530
		best_diff = - best_diff;
531
	}
532
	split_value = start;
533
	for (w = start; w <= end; w++) {
534
		count += node_weight[w];
535
		if ((count - halfway_value) < best_diff &&
536
		    (halfway_value - count) < best_diff) {
537
			split_value = w;
538
			best_diff = count - halfway_value;
539
			if (best_diff < 0.0) {
540
				best_diff = - best_diff;
541
			}
542
		}
543
	}
544
	return split_value;
2 7u83 545
}
546
 
547
 
548
/*
549
 * exhaustive_conditional_maker is the recursive routine for
550
 * making the internal transformed tdf in the case of an
551
 * exhaustive case_tag.
552
 */
6 7u83 553
static exp
554
exhaustive_conditional_maker(int start, int end, exp id)
2 7u83 555
{
6 7u83 556
	int split_value;
557
	exp option_left;
558
	exp option_right;
559
	exp t;
2 7u83 560
 
6 7u83 561
	/* first test to see if we have only one node */
562
	if (start == end) {
563
		/* Check to see if not a jump table */
564
		if (bro(node_start[start]) == nilexp) {
565
			t = getexp(f_bottom, nilexp, 0, nilexp, nilexp, 0, 0,
566
				   goto_tag);
567
			pt(t) = pt(node_start[start]);
568
			return t;
569
		} else {
570
			/* We must have to make a jump table */
571
			return set_up_exhaustive_case(node_start[start], id);
572
		}
573
	}
574
	split_value = find_the_split_value(start, end);
575
	if (split_value == end) {
576
		split_value --;
577
	}
578
	option_left = exhaustive_conditional_maker(split_value + 1, end, id);
579
	option_right = exhaustive_conditional_maker(start, split_value, id);
580
	return set_up_conditional(option_left, option_right,
581
				  f_greater_than_or_equal,
582
				  no(node_start[split_value + 1]), id, 1000);
2 7u83 583
}
584
 
585
 
586
/*
587
 * inexhaustive_conditional_maker is the recursive routine for
588
 * making the internal transformed tdf in the case of an
589
 * inexhaustive case_tag.
590
 */
6 7u83 591
static exp
592
inexhaustive_conditional_maker(int start, int end, exp id, exp default_exp)
2 7u83 593
{
6 7u83 594
	int split_value;
595
	exp option_left;
596
	exp option_right;
597
	exp spare;
2 7u83 598
 
6 7u83 599
	if (start == end) {
600
		/* Single range to single destination */
601
		if (node_start[start] == node_end[start]) {
602
			if ((node_start_flag[start] == 1) &&
603
			    (node_end_flag[start] == 1)) {
604
				spare = getexp(f_bottom, nilexp, 0, nilexp,
605
					       nilexp, 0, 0, goto_tag);
606
				pt(spare) = pt(node_start[start]);
607
				return spare;
608
			} else {
609
				option_left = getexp(f_bottom, nilexp, 0,
610
						     nilexp, nilexp, 0, 0,
611
						     goto_tag);
612
				pt(option_left) = default_exp;
613
				no(son(default_exp)) ++;
614
				no(son(pt(node_start[start]))) --;
615
				return set_up_sequence(option_left,
616
						       pt(node_start[start]),
617
						       f_not_equal,
618
						       no(node_start[start]),
619
						       id, 1000);
620
			}
621
		}
622
		/* Multi range to single destination */
623
		if (son(node_start[start]) == node_end[start]) {
624
			if ((node_start_flag[start] == 1) &&
625
			    (node_end_flag[start] == 1)) {
626
				spare = getexp(f_bottom, nilexp, 0, nilexp,
627
					       nilexp, 0, 0, goto_tag);
628
				pt(spare) = pt(node_start[start]);
629
				return spare;
630
			}
631
			if ((node_start_flag[start] == 1) &&
632
			    (node_end_flag[start] == 0)) {
633
				option_left = getexp(f_bottom, nilexp, 0,
634
						     nilexp, nilexp, 0, 0,
635
						     goto_tag);
636
				pt(option_left) = default_exp;
637
				no(son(default_exp))++;
638
				no(son(pt(node_start[start])))--;
639
				node_end_flag[start] = 1;
640
				return set_up_sequence(option_left,
641
						       pt(node_start[start]),
642
						       f_greater_than,
643
						       no(node_end[start]), id,
644
						       1000);
645
			}
646
			if ((node_start_flag[start] == 0) &&
647
			    (node_end_flag[start] == 1)) {
648
				option_left = getexp(f_bottom, nilexp, 0,
649
						     nilexp, nilexp, 0, 0,
650
						     goto_tag);
651
				pt(option_left) = default_exp;
652
				no(son(default_exp)) ++;
653
				no(son(pt(node_start[start])))--;
654
				node_start_flag[start] = 1;
655
				return set_up_sequence(option_left,
656
						       pt(node_start[start]),
657
						       f_less_than,
658
						       no(node_start[start]),
659
						       id, 1000);
660
			}
661
			/* We may as well do a subtraction and a comparison */
662
			node_start_flag[start] = node_end_flag[start] = 1;
2 7u83 663
 
6 7u83 664
			{
665
				exp SEQUENCE__TAG;
666
				exp ZERO__TAG;
667
				exp GOTO__TAG;
668
				int   subtract_value = no(node_start[start]);
2 7u83 669
 
6 7u83 670
				GOTO__TAG = getexp(f_bottom, nilexp, 0, nilexp,
671
						   nilexp, 0, 0, goto_tag);
672
				pt(GOTO__TAG) = default_exp;
673
				no(son(default_exp)) ++;
674
				no(son(pt(node_start[start])))--;
675
				ZERO__TAG =
676
				    me_b3(f_top,
677
					  set_up_assign(id, -subtract_value),
678
					  set_up_unsigned_test(pt(node_start[start]), id,
679
							       (no(node_end[start]) - subtract_value),
680
							       f_greater_than), 0);
681
				SEQUENCE__TAG = me_b3(f_bottom, ZERO__TAG,
682
						      GOTO__TAG, seq_tag);
683
				return SEQUENCE__TAG;
684
			}
685
		}
686
		/* We must have to do a jump table */
687
		if ((node_start_flag[start] == 1) &&
688
		    (node_end_flag[start] == 1)) {
689
			return set_up_inexhaustive_case(node_start[start], id,
690
							default_exp);
691
		}
692
		if ((node_start_flag[start] == 1) &&
693
		    (node_end_flag[start] == 0)) {
694
			option_left =
695
			    set_up_inexhaustive_case(node_start[start], id,
696
						     default_exp);
697
			node_end_flag[start] = 1;
698
			return set_up_sequence(option_left, default_exp,
699
					       f_less_than_or_equal,
700
					       no(node_end[start]), id, 1000);
701
		}
702
		if ((node_start_flag[start] == 0) &&
703
		    (node_end_flag[start] == 1)) {
704
			option_left =
705
			    set_up_inexhaustive_case(node_start[start], id,
706
						     default_exp);
707
			node_start_flag[start] = 1;
708
			return set_up_sequence(option_left, default_exp,
709
					       f_greater_than_or_equal,
710
					       no(node_start[start]), id, 1000);
711
		}
712
		/* Put in a jump table by doing a subtraction first and comparison for
713
		   both sides */
714
		node_start_flag[start] = node_end_flag[start] = 1;
715
		{
716
			exp ZERO__TAG;
717
			exp SEQUENCE__TAG;
718
			exp SPARE__TAG;
719
			exp r;
720
			int subtract_value;
721
			subtract_value = no(node_start[start]);
2 7u83 722
 
6 7u83 723
			ZERO__TAG =
724
			    me_b3(f_top, set_up_assign(id, -subtract_value),
725
				  set_up_unsigned_test(default_exp, id,
726
						       (no(node_end[start]) -
727
							subtract_value),
728
						       f_less_than_or_equal),
729
				  0);
730
			r = node_start[start];
731
			while (r != nilexp) {
732
				no(r) = no(r) - subtract_value;
733
				if (son(r) != nilexp) {
734
					no(son(r)) = no(son(r)) -
735
					    subtract_value;
736
				}
737
				r = bro(r);
738
			}
739
			SPARE__TAG =
740
			    set_up_inexhaustive_case(node_start[start], id,
741
						     default_exp);
742
			SEQUENCE__TAG = me_b3(sh(SPARE__TAG), ZERO__TAG,
743
					      SPARE__TAG, seq_tag);
744
			return SEQUENCE__TAG;
745
		}
746
	}
747
	split_value = find_the_split_value(start, end);
748
	/* assert that node_start_flag[split_value+1] and
749
	   node_end_flag[split_value] should be zero or split_value = end */
750
	if (split_value == start && (node_start[start] == node_end[start])) {
751
		/* This is the case when we have a simple single range node in
752
		 * the 1:n split */
753
		option_left =
754
		    inexhaustive_conditional_maker(start + 1, end, id,
755
						   default_exp);
756
		no(son(pt(node_start[start])))--;
757
		return set_up_sequence(option_left, pt(node_start[start]),
758
				       f_not_equal, no(node_start[start]), id,
759
				       1000);
760
	}
761
	if (split_value >= end - 1 && (node_start[end] == node_end[end])) {
762
		/* This is the case when we have a simple single range node in
763
		 * the n:1 split */
764
		option_left =
765
		    inexhaustive_conditional_maker(start, end - 1, id,
766
						   default_exp);
767
		no(son(pt(node_start[end])))--;
768
		return set_up_sequence(option_left, pt(node_start[end]),
769
				       f_not_equal, no(node_start[end]), id,
770
				       1001);
771
	}
772
	if (split_value == start &&
773
	    (son(node_start[start]) == node_end[start]) &&
774
	    node_start_flag[start] == 1) {
775
		/* This is the case when we have a multi range to the in the
776
		 * 1:n split where the left hand comparison has been done */
2 7u83 777
 
6 7u83 778
		/* If we have a close together split there is no need to
779
		 * recompare */
780
		if (no(node_end[start]) == (no(node_start[start+1]) -1)) {
781
			node_start_flag[start+1] = 1;
782
		}
2 7u83 783
 
6 7u83 784
		option_left =
785
		    inexhaustive_conditional_maker(start + 1, end, id,
786
						   default_exp);
787
		no(son(pt(node_start[start])))--;
788
		return set_up_sequence(option_left, pt(node_start[start]),
789
				       f_greater_than, no(node_end[start]), id,
790
				       1001);
791
	}
792
	if (split_value >= end - 1 &&
793
	    (son(node_start[end]) == node_end[end]) &&
794
	    node_end_flag[end] == 1) {
795
		/* This is the case when we have a multi range to the in the
796
		 * n:1 split where the right hand comparison has been done */
2 7u83 797
 
6 7u83 798
		/* If we have a close together split there is no need to
799
		 * recompare */
800
		if (no(node_end[end - 1]) == (no(node_start[end]) - 1)) {
801
			node_end_flag[end-1] = 1;
802
		}
2 7u83 803
 
6 7u83 804
		option_left =
805
		    inexhaustive_conditional_maker(start, end - 1, id,
806
						   default_exp);
807
		no(son(pt(node_start[end])))--;
808
		return set_up_sequence(option_left, pt(node_start[end]),
809
				       f_less_than, no(node_start[end]), id,
810
				       1000);
811
	}
812
	if (split_value == end) {
813
		split_value --;
814
	}
815
	/* If we have a multi range or a jump table to the left or right of the
816
	   split, it is better to do one of those comparisons because it will
817
	   save a comparison whereas doing a comparison against a single range
818
	   saves nothing */
819
	if (node_start[split_value] == node_end[split_value]) {
820
		/* do the comparison against split_value+1 */
821
		node_start_flag[split_value + 1] = 1;
2 7u83 822
 
6 7u83 823
		/* If we have a close together split there is no need to
824
		 * recompare */
825
		if (no(node_end[split_value]) ==
826
		    (no(node_start[split_value + 1]) - 1)) {
827
			node_end_flag[split_value] = 1;
828
		}
2 7u83 829
 
6 7u83 830
		option_right =
831
		    inexhaustive_conditional_maker(start, split_value, id,
832
						   default_exp);
833
		option_left =
834
		    inexhaustive_conditional_maker(split_value + 1, end, id,
835
						   default_exp);
836
		return set_up_conditional(option_left, option_right,
837
					  f_greater_than_or_equal,
838
					  no(node_start[split_value + 1]), id,
839
					  1000);
840
	} else {
841
		/* do the comparison against split_value */
842
		node_end_flag[split_value] = 1;
843
		/* If we have a close together split there is no need to
844
		 * recompare */
845
		if (no(node_end[split_value]) ==
846
		    (no(node_start[split_value + 1]) - 1)) {
847
			node_start_flag[split_value + 1] = 1;
848
		}
2 7u83 849
 
6 7u83 850
		option_right =
851
		    inexhaustive_conditional_maker(start, split_value, id,
852
						   default_exp);
853
		option_left =
854
		    inexhaustive_conditional_maker(split_value + 1, end, id,
855
						   default_exp);
856
		return set_up_conditional(option_left, option_right,
857
					  f_greater_than,
858
					  no(node_end[split_value]), id, 1000);
859
	}
2 7u83 860
}
861
 
862
 
863
/*
864
 * set_up_assign takes a variable and adds an integer to
865
 * it, and replaces it.
866
 */
6 7u83 867
static exp
868
set_up_assign(exp id, int number)
2 7u83 869
{
6 7u83 870
	exp NAME__TAG;
871
	exp VAL__TAG;
872
	exp CONT__TAG;
873
	exp PLUS__TAG;
874
	exp ASSIGN__TAG;
2 7u83 875
 
6 7u83 876
	NAME__TAG = me_obtain(id);
877
	VAL__TAG = me_shint(sh(id), number);
878
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
879
	PLUS__TAG = me_b3(sh(id), CONT__TAG, VAL__TAG, plus_tag);
880
	ASSIGN__TAG = me_b3(f_top, me_obtain(id), PLUS__TAG, ass_tag);
881
	return ASSIGN__TAG;
2 7u83 882
}
6 7u83 883
 
884
 
2 7u83 885
/*
886
 * set_up_unsigned_test returns a test_tag. The test is
887
 * specified, along with the value to be tested against
888
 * the default_exp labst_tag and the var_tag to test
889
 * against.
890
 */
6 7u83 891
static exp
892
set_up_unsigned_test(exp default_exp, exp id, int test_value, ntest test)
2 7u83 893
{
6 7u83 894
	exp NAME__TAG;
895
	exp CHVAR__TAG;
896
	exp CONT__TAG;
897
	exp VAL__TAG;
898
	exp TEST__TAG;
2 7u83 899
 
6 7u83 900
	NAME__TAG = me_obtain(id);
901
	CONT__TAG = me_u3(sh(id), NAME__TAG, cont_tag);
902
	CHVAR__TAG = hold_check(me_u3(ulongsh, CONT__TAG, chvar_tag));
903
	VAL__TAG = me_shint(ulongsh, test_value);
904
	TEST__TAG = like_me_q1(1000, test, default_exp, CHVAR__TAG, VAL__TAG,
905
			       test_tag);
906
	return TEST__TAG;
2 7u83 907
}