Subversion Repositories tendra.SVN

Rev

Rev 2 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
2
    		 Crown Copyright (c) 1997
3
 
4
    This TenDRA(r) Computer Program is subject to Copyright
5
    owned by the United Kingdom Secretary of State for Defence
6
    acting through the Defence Evaluation and Research Agency
7
    (DERA).  It is made available to Recipients with a
8
    royalty-free licence for its use, reproduction, transfer
9
    to other parties and amendment for any purpose not excluding
10
    product development provided that any such use et cetera
11
    shall be deemed to be acceptance of the following conditions:-
12
 
13
        (1) Its Recipients shall ensure that this Notice is
14
        reproduced upon any copies or amended versions of it;
15
 
16
        (2) Any amended version of it shall be clearly marked to
17
        show both the nature of and the organisation responsible
18
        for the relevant amendment or amendments;
19
 
20
        (3) Its onward transfer from a recipient to another
21
        party shall be deemed to be that party's acceptance of
22
        these conditions;
23
 
24
        (4) DERA gives no warranty or assurance as to its
25
        quality or suitability for any purpose and DERA accepts
26
        no liability whatsoever in relation to any use to which
27
        it may be put.
28
*/
29
 
30
 
31
/*** rule-tail.c --- Tail recursion elimination routines.
32
 *
33
 ** Author: Steve Folkes <smf@hermes.mod.uk>
34
 *
35
 *** Commentary:
36
 *
37
 * This file implements the SID inlining routines.
38
 *
39
 * There are five separate phases implemented in this file.
40
 *
41
 * The first phase is to find and eliminate all tail recursive cycles that
42
 * each rule is involved in.  The cycles are detected by the
43
 * ``grammar_compute_inlining'' function in the file "grammar.c".  For each
44
 * cyclic group that is found, the ``rule_handle_tails'' function is called to
45
 * remove the cycle.  All rules in the cycle are marked as being cyclic, and
46
 * are given a unique identification that is the same for all members of the
47
 * cycle (but different for members of different cycles).  The tail recursive
48
 * calls are marked as inlinable and tail recursive, and the rules' call
49
 * graphs are computed (this is the set of rules that will make tail calls).
50
 * This phase is only performed if tail recursion inlining is enabled.
51
 *
52
 * The second phase is implemented by the ``rule_compute_all_basics''
53
 * function.  This marks a rule that only contains basics as such.  This phase
54
 * is only performed if all basic inlining is enabled.
55
 *
56
 * The third phase is implemented by the ``rule_compute_inlining'' function.
57
 * This marks all calls to all basic rules as inlinable.  If single
58
 * alternative rule inlining is enabled, then all calls to single alternative
59
 * rules are marked as inlinable.  If non tail recursion inlining is enabled,
60
 * it also marks all other calls as inlinable, and computes their call count
61
 * if functions that are called more than once are not to be inlined (the
62
 * output routines won't inline rules with a call count greater than one).
63
 *
64
 * The fourth phase is implemented by the ``rule_compute_needed_functions''
65
 * function.  It marks all required functions, and functions that are called
66
 * from a non-inlinable position as requiring function implementations.
67
 *
68
 * The final phase is implemented by the ``rule_handle_need_functions''
69
 * function.  The cycle detection routines are used in the
70
 * ``grammar_compute_inlining'' function to find cycles in the function call
71
 * graph.  If any such cycles are found, then all of the rules in the cycle
72
 * are marked as needing a function implementation.
73
 *
74
 *** Change Log:
75
 * $Log: rule-tail.c,v $
76
 * Revision 1.1.1.1  1998/01/17  15:57:47  release
77
 * First version to be checked into rolling release.
78
 *
79
 * Revision 1.3  1994/12/15  09:58:53  smf
80
 * Brought into line with OSSG C Coding Standards Document, as per
81
 * "CR94_178.sid+tld-update".
82
 *
83
 * Revision 1.2  1994/11/11  11:47:09  smf
84
 * Fixed a bug in the tail recursion elimination, for bug fix
85
 * CR94_127.sid-tail-rec.
86
 * There was a problem with tail calls that had reference parameters in an
87
 * earlier version of SID, and they had been disabled.  This should have been
88
 * fixed when the output routines were fixed to do references properly, but the
89
 * check wasn't removed.  It has been now.
90
 *
91
 * Revision 1.1.1.1  1994/07/25  16:04:41  smf
92
 * Initial import of SID 1.8 non shared files.
93
 *
94
**/
95
 
96
/****************************************************************************/
97
 
98
#include "rule.h"
99
#include "action.h"
100
#include "basic.h"
101
#include "entry-list.h"
102
#include "name.h"
103
#include "type.h"
104
 
105
/*--------------------------------------------------------------------------*/
106
 
107
typedef struct CycleHeadT {
108
    RuleP			head;
109
    RuleP		       *tail;
110
} CycleHeadT, *CycleHeadP;
111
 
112
typedef struct RuleStackT {
113
    struct RuleStackT	       *next;
114
    RuleP			rule;
115
} RuleStackT, *RuleStackP;
116
 
117
/*--------------------------------------------------------------------------*/
118
 
119
static BoolT			rule_do_inline_tail_calls     = TRUE;
120
static BoolT			rule_do_inline_all_basics     = TRUE;
121
static BoolT			rule_do_inline_singles        = FALSE;
122
static BoolT			rule_do_inline_non_tail_calls = FALSE;
123
static BoolT			rule_do_multiple_inlining     = FALSE;
124
 
125
/*--------------------------------------------------------------------------*/
126
 
127
static void
128
rule_inline_tail_calls_1 PROTO_N ((rule, alt, tail_group))
129
			 PROTO_T (RuleP rule X
130
				  AltP  alt X
131
				  RuleP tail_group)
132
{
133
    ItemP item = alt_item_head (alt);
134
    ItemP next;
135
 
136
    while ((next = item_next (item)) != NIL (ItemP)) {
137
	item = next;
138
    }
139
    if (item_is_rule (item)) {
140
	RuleP item_rule = entry_get_rule (item_entry (item));
141
 
142
	if ((rule_get_tail_group (item_rule) == tail_group) &&
143
	    (types_equal_names (rule_result (rule), item_result (item)))) {
144
	    item_inlinable (item);
145
	    item_tail_call (item);
146
	}
147
    }
148
}
149
 
150
static void
151
rule_inline_tail_calls PROTO_N ((rule))
152
		       PROTO_T (RuleP rule)
153
{
154
    RuleP tail_group = rule_get_tail_group (rule);
155
    AltP  alt;
156
 
157
    if ((alt = rule_get_handler (rule)) != NIL (AltP)) {
158
	rule_inline_tail_calls_1 (rule, alt, tail_group);
159
    }
160
    for (alt = rule_alt_head (rule); alt; alt = alt_next (alt)) {
161
	rule_inline_tail_calls_1 (rule, alt, tail_group);
162
    }
163
}
164
 
165
static void			rule_compute_call_graph
166
	PROTO_S ((RuleP, EntryListP, RuleStackP));
167
 
168
static void
169
rule_compute_call_graph_1 PROTO_N ((alt, call_list, next))
170
			  PROTO_T (AltP       alt X
171
				   EntryListP call_list X
172
				   RuleStackP next)
173
{
174
    ItemP item = alt_item_head (alt);
175
    ItemP next_item;
176
 
177
    while ((next_item = item_next (item)) != NIL (ItemP)) {
178
	item = next_item;
179
    }
180
    if (item_is_tail_call (item)) {
181
	EntryP entry     = item_entry (item);
182
	RuleP  item_rule = entry_get_rule (entry);
183
 
184
	rule_compute_call_graph (item_rule, call_list, next);
185
    }
186
}
187
 
188
static void
189
rule_compute_call_graph PROTO_N ((rule, call_list, next))
190
			PROTO_T (RuleP      rule X
191
				 EntryListP call_list X
192
				 RuleStackP next)
193
{
194
    RuleStackT stack;
195
    AltP       alt;
196
 
197
    stack.rule = rule;
198
    stack.next = next;
199
    while (next) {
200
	if (next->rule == rule) {
201
	    entry_list_add_if_missing (call_list, rule_entry (rule));
202
	    return;
203
	}
204
	next = next->next;
205
    }
206
    if ((alt = rule_get_handler (rule)) != NIL (AltP)) {
207
	rule_compute_call_graph_1 (alt, call_list, &stack);
208
    }
209
    for (alt = rule_alt_head (rule); alt; alt = alt_next (alt)) {
210
	rule_compute_call_graph_1 (alt, call_list, &stack);
211
    }
212
}
213
 
214
static void
215
rule_compute_all_basics_1 PROTO_N ((rule))
216
			  PROTO_T (RuleP rule)
217
{
218
    if ((!rule_has_empty_alt (rule)) &&
219
	(rule_get_handler (rule) == NIL (AltP))) {
220
	AltP alt;
221
 
222
	for (alt = rule_alt_head (rule); alt; alt = alt_next (alt)) {
223
	    ItemP item;
224
 
225
	    for (item = alt_item_head (alt); item; item = item_next (item)) {
226
		if (!item_is_basic (item)) {
227
		    return;
228
		}
229
	    }
230
	}
231
	rule_all_basics (rule);
232
    }
233
}
234
 
235
static void			rule_compute_inlining_1
236
	PROTO_S ((RuleP));
237
 
238
static void
239
rule_compute_inlining_2 PROTO_N ((alt))
240
			PROTO_T (AltP alt)
241
{
242
    ItemP item;
243
 
244
    for (item = alt_item_head (alt); item; item = item_next (item)) {
245
	if ((item_is_rule (item)) && (!item_is_tail_call (item))) {
246
	    EntryP entry     = item_entry (item);
247
	    RuleP  item_rule = entry_get_rule (entry);
248
 
249
	    if (rule_is_all_basics (item_rule)) {
250
		item_inlinable (item);
251
	    } else if (rule_do_inline_singles &&
252
		       rule_has_one_alt (item_rule)) {
253
		item_inlinable (item);
254
	    } else if (!rule_do_multiple_inlining) {
255
		rule_inc_call_count (item_rule);
256
	    }
257
	    if (rule_do_inline_non_tail_calls) {
258
		item_inlinable (item);
259
	    }
260
	    rule_compute_inlining_1 (item_rule);
261
	}
262
    }
263
}
264
 
265
static void
266
rule_compute_inlining_1 PROTO_N ((rule))
267
			PROTO_T (RuleP rule)
268
{
269
    if (!rule_is_checked_for_inlining (rule)) {
270
	if (!rule_is_being_inlined (rule)) {
271
	    AltP alt;
272
 
273
	    rule_being_inlined (rule);
274
	    if ((alt = rule_get_handler (rule)) != NIL (AltP)) {
275
		rule_compute_inlining_2 (alt);
276
	    }
277
	    for (alt = rule_alt_head (rule); alt; alt = alt_next (alt)) {
278
		rule_compute_inlining_2 (alt);
279
	    }
280
	    rule_checked_for_inlining (rule);
281
	}
282
    }
283
}
284
 
285
static void
286
rule_compute_needed_functions_2 PROTO_N ((alt))
287
				PROTO_T (AltP alt)
288
{
289
    ItemP item;
290
 
291
    for (item = alt_item_head (alt); item; item = item_next (item)) {
292
	if (item_is_rule (item)) {
293
	    RuleP item_rule = entry_get_rule (item_entry (item));
294
 
295
	    if ((!item_is_inlinable (item)) ||
296
		(rule_get_call_count (item_rule) > 1)) {
297
		rule_will_need_function (item_rule);
298
	    }
299
	}
300
    }
301
}
302
 
303
static void
304
rule_compute_needed_functions_1 PROTO_N ((rule))
305
				PROTO_T (RuleP rule)
306
{
307
    AltP     alt;
308
 
309
    if ((alt = rule_get_handler (rule)) != NIL (AltP)) {
310
	rule_compute_needed_functions_2 (alt);
311
    }
312
    for (alt = rule_alt_head (rule); alt; alt = alt_next (alt)) {
313
	rule_compute_needed_functions_2 (alt);
314
    }
315
}
316
 
317
/*--------------------------------------------------------------------------*/
318
 
319
void
320
rule_handle_tails PROTO_N ((rule_list))
321
		  PROTO_T (RuleP rule_list)
322
{
323
    RuleP rule;
324
 
325
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs (rule)) {
326
	rule_set_tail_group (rule, rule_list);
327
	rule_no_cycles (rule);
328
    }
329
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs (rule)) {
330
	rule_inline_tail_calls (rule);
331
    }
332
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs (rule)) {
333
	rule_compute_call_graph (rule, rule_call_list (rule),
334
				 NIL (RuleStackP));
335
    }
336
}
337
 
338
void
339
rule_compute_all_basics PROTO_N ((entry, gclosure))
340
			PROTO_T (EntryP   entry X
341
				 GenericP gclosure)
342
{
343
    UNUSED (gclosure);
344
    if (rule_do_inline_all_basics && entry_is_rule (entry)) {
345
	RuleP rule = entry_get_rule (entry);
346
 
347
	rule_compute_all_basics_1 (rule);
348
    }
349
}
350
 
351
void
352
rule_compute_inlining PROTO_N ((entry, gclosure))
353
		      PROTO_T (EntryP   entry X
354
			       GenericP gclosure)
355
{
356
    UNUSED (gclosure);
357
    if (entry_is_rule (entry)) {
358
	RuleP rule = entry_get_rule (entry);
359
 
360
	rule_compute_inlining_1 (rule);
361
    }
362
}
363
 
364
void
365
rule_compute_needed_functions PROTO_N ((entry, gclosure))
366
			      PROTO_T (EntryP   entry X
367
				       GenericP gclosure)
368
{
369
    UNUSED (gclosure);
370
    if (entry_is_rule (entry)) {
371
	RuleP rule = entry_get_rule (entry);
372
 
373
	rule_compute_needed_functions_1 (rule);
374
    }
375
}
376
 
377
void
378
rule_handle_need_functions PROTO_N ((rule_list))
379
			   PROTO_T (RuleP rule_list)
380
{
381
    RuleP rule;
382
 
383
    for (rule = rule_list; rule; rule = rule_get_next_in_reverse_dfs (rule)) {
384
	rule_will_need_function (rule);
385
    }
386
}
387
 
388
BoolT
389
rule_get_inline_tail_calls PROTO_Z ()
390
{
391
    return (rule_do_inline_tail_calls);
392
}
393
 
394
void
395
rule_set_inline_tail_calls PROTO_N ((enable))
396
			   PROTO_T (BoolT enable)
397
{
398
    rule_do_inline_tail_calls = enable;
399
}
400
 
401
void
402
rule_set_inline_all_basics PROTO_N ((enable))
403
			   PROTO_T (BoolT enable)
404
{
405
    rule_do_inline_all_basics = enable;
406
}
407
 
408
void
409
rule_set_inline_singles PROTO_N ((enable))
410
			PROTO_T (BoolT enable)
411
{
412
    rule_do_inline_singles = enable;
413
}
414
 
415
void
416
rule_set_inline_non_tail_calls PROTO_N ((enable))
417
			       PROTO_T (BoolT enable)
418
{
419
    if (enable) {
420
	rule_do_inline_non_tail_calls = TRUE;
421
    } else {
422
	rule_do_inline_non_tail_calls = FALSE;
423
	rule_do_multiple_inlining     = FALSE;
424
    }
425
}
426
 
427
void
428
rule_set_multiple_inlining PROTO_N ((enable))
429
			   PROTO_T (BoolT enable)
430
{
431
    if (enable) {
432
	rule_do_inline_non_tail_calls = TRUE;
433
	rule_do_multiple_inlining     = TRUE;
434
    } else {
435
	rule_do_multiple_inlining     = FALSE;
436
    }
437
}
438
 
439
/*
440
 * Local variables(smf):
441
 * eval: (include::add-path-entry "../os-interface" "../library")
442
 * eval: (include::add-path-entry "../generated")
443
 * end:
444
**/