4 * Copyright: (c) Universitaet Karlsruhe
5 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
7 * Implementation of the RA-Interface for an external, (non-SSA) register allocator.
9 * The external register allocator is a program taking 2 arguments:
10 * 1) An input file in which the cfg is defined
11 * 2) An output file containing the essential actions performed during allocation
16 ----------------------
18 inputfile ::= regs nodes interf affinities .
20 regs ::= 'regs' regcount . // Anzahl der register (0..regcount-1), die zur Verfuegung stehen
22 nodes ::= 'nodes' '{' node* '}' . // All nodes in the graph
24 interf ::= 'interferences' '{' edge* '}' . // Interference edges of the graph
26 affinities ::= 'affinities' '{' edge* '}' . // Affinity edges of the graph
29 | node-nr '<' reg-nr '>' . // Reg-nr is present in case of constraints
31 edge ::= '(' node-nr node-nr ')' .
34 regcount, node-nr ::= integer .
37 The output file format
38 -----------------------
40 outputfile ::= spills | allocs .
42 spills ::= 'spills' '{' node-nr+ '}' .
44 allocs ::= 'allocs' '{' alloc* '}' .
46 alloc ::= node-nr reg-nr .
49 Constraints for output file
50 ---------------------------
51 1) The returned actions must result in a non-ssa-program
52 equivalent to the former input.
53 2) All names (numbers) must be defined before their first use.
54 Numbers already occuring in the input file are implicitly defined in the output file.
55 3) All spills of a variable must precede the first reload of this variable
56 4) Each reload must define a new variable name
60 ******** End of file format docu ********/
75 #include <libcore/lc_opts.h>
76 #include <libcore/lc_opts_enum.h>
84 #include "irprintf_t.h"
86 #include "irgraph_t.h"
91 #include "beraextern.h"
98 typedef struct _var_info_t var_info_t;
101 * Environment with all the needed stuff
103 typedef struct _be_raext_env_t {
105 const arch_register_class_t *cls;
107 dom_front_info_t *dom_info;
109 FILE *f; /**< file handle used for out- and input file */
110 set *vars; /**< contains all var_info_t */
112 var_info_t **cls_vars; /**< only the var_infos for current cls. needed for double iterating */
113 set *edges; /**< interference and affinity edges */
114 pmap *nodes; /**< maps nodes numbers (int) to the node (ir_node*) having that node_nr */
119 /******************************************************************************
122 | |__| | ___| |_ __ ___ _ __ ___
123 | __ |/ _ \ | '_ \ / _ \ '__/ __|
124 | | | | __/ | |_) | __/ | \__ \
125 |_| |_|\___|_| .__/ \___|_| |___/
128 *****************************************************************************/
131 #define pset_foreach(pset, irn) for(irn=pset_first(pset); irn; irn=pset_next(pset))
132 #define set_foreach(set, e) for(e=set_first(set); e; e=set_next(set))
136 * Checks if _the_ result of the irn belongs to the
137 * current register class (raenv->cls)
138 * NOTE: Only the first result is checked.
140 #define is_res_in_reg_class(irn) arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls)
144 * Checks if the irn uses or defines values of the
145 * current register class (raenv->cls)
147 static INLINE int is_sth_in_reg_class(be_raext_env_t *raenv, const ir_node *irn) {
150 /* check arguments */
151 for (i=0, max=get_irn_arity(irn); i<max; ++i)
152 if (arch_irn_has_reg_class(raenv->aenv, get_irn_n(irn, i), -1, raenv->cls))
155 /* check result(s) */
156 if (get_irn_mode(irn) == mode_T) {
158 for (proj = sched_next(irn); is_Proj(proj); proj = sched_next(proj))
159 if (arch_irn_has_reg_class(raenv->aenv, proj, -1, raenv->cls))
163 return arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls);
166 assert(0 && "Where did you come from???");
169 /******************************************************************************
171 / ____/ ____| /\ | __ \ | |
172 | (___| (___ / \ ______| | | | ___ ___| |_ _ __
173 \___ \\___ \ / /\ \______| | | |/ _ \/ __| __| '__|
174 ____) |___) / ____ \ | |__| | __/\__ \ |_| |
175 |_____/_____/_/ \_\ |_____/ \___||___/\__|_|
177 *****************************************************************************/
179 #define mark_as_done(irn, pos) set_irn_link(irn, INT_TO_PTR(pos+1))
180 #define has_been_done(irn, pos) (PTR_TO_INT(get_irn_link(irn)) > pos)
183 * Insert a copy for the argument of @p start_phi found at position @p pos.
184 * Also searches a phi-loop of arbitrary length to detect and resolve
185 * the class of phi-swap-problems. To search for a loop recursion is used.
187 * 1) Simplest case (phi with a non-phi arg):
188 * A single copy is inserted.
190 * 2) Phi chain (phi (with phi-arg)* with non=phi arg):
191 * Several copies are placed, each after returning from recursion.
194 * On detection a loop breaker is inserted, which is a copy of the start_phi.
195 * This copy then pretends beeing the argumnent of the last phi.
196 * Now case 2) can be used.
198 * The values of @p start_phi and @p pos never change during recursion.
200 * @p raenv Environment with all the stuff needed
201 * @p start_phi Phi node to process
202 * @p pos Argument position to insert copy/copies for
203 * @p curr_phi Phi node currently processed during recursion. Equals start_phi on initial call
205 * @return NULL If no copy is necessary
206 * NULL If the phi has already been processed at this pos
207 * Link field is used to keep track of processed positions
208 * In all other cases the ir_node *copy which was placed is returned.
210 static ir_node *insert_copies(be_raext_env_t *raenv, ir_node *start_phi, int pos, ir_node *curr_phi) {
211 ir_node *arg = get_irn_n(curr_phi, pos);
212 ir_node *arg_blk = get_nodes_block(arg);
213 ir_node *pred_blk = get_Block_cfgpred_block(get_nodes_block(curr_phi), pos);
214 ir_node *curr_cpy, *last_cpy;
216 assert(is_Phi(start_phi) && is_Phi(curr_phi));
218 if (has_been_done(start_phi, pos))
221 /* In case this is a 'normal' phi we insert into
222 * the schedule before the pred_blk irn */
225 /* If we detect a loop stop recursion. */
226 if (arg == start_phi) {
227 ir_node *loop_breaker;
228 if (start_phi == curr_phi) {
229 /* Phi directly uses itself. No copy necessary */
233 /* At least 2 phis are involved */
234 /* Insert a loop breaking copy (an additional variable T) */
235 loop_breaker = be_new_Copy(raenv->cls, raenv->irg, pred_blk, start_phi);
236 sched_add_before(pred_blk, loop_breaker);
241 /* If arg is a phi in the same block we have to continue search */
242 if (is_Phi(arg) && arg_blk == get_nodes_block(start_phi))
243 last_cpy = insert_copies(raenv, start_phi, pos, arg);
245 /* Insert copy of argument (may be the loop-breaker) */
246 curr_cpy = be_new_Copy(raenv->cls, raenv->irg, pred_blk, arg);
247 set_irn_n(curr_phi, pos, curr_cpy);
248 mark_as_done(curr_phi, pos);
249 sched_add_before(last_cpy, curr_cpy);
255 * Perform simple SSA-destruction with copies.
256 * The order of processing _must_ be
257 * for all positions {
262 * else the magic to keep track of processed phi-positions will fail in
263 * function 'insert_copies'
265 static void ssa_destr_simple_walker(ir_node *blk, void *env) {
266 be_raext_env_t *raenv = env;
270 /* for all argument positions of the phis */
271 for (pos=0, max=get_irn_arity(blk); pos<max; ++pos) {
273 /* for all phi nodes (which are scheduled first) */
274 sched_foreach(blk, phi) {
278 raenv->cls = arch_get_irn_reg_class(raenv->aenv, phi, -1);
279 insert_copies(raenv, phi, pos, phi);
285 static void ssa_destr_simple(be_raext_env_t *raenv) {
286 be_clear_links(raenv->irg);
287 irg_block_walk_graph(raenv->irg, ssa_destr_simple_walker, NULL, raenv);
291 static void ssa_destr_rastello(be_raext_env_t *raenv) {
294 phi_class_compute(raenv->irg);
295 irg_block_walk_graph(irg, ssa_destr_rastello, NULL, &raenv);
299 /******************************************************************************
301 \ \ / / | | |__ \ \ \ / /
302 \ \ / /_ _| |___ ) | \ \ / /_ _ _ __ ___
303 \ \/ / _` | / __| / / \ \/ / _` | '__/ __|
304 \ / (_| | \__ \ / /_ \ / (_| | | \__ \
305 \/ \__,_|_|___/ |____| \/ \__,_|_| |___/
306 *****************************************************************************/
309 * This struct maps a variable (nr) to
310 * 1) the values belonging to this variable
311 * 2) the spills of this variable
314 int var_nr; /* the key for comparesion */
315 pset *values; /* the ssa-values belonging to this variable */
316 pset *spills; /* the spills of this variable */
317 pset *reloads; /* the relaods of this variable */
318 unsigned reload_phase:1; /* 0 initially, 1 if a reload of this var has been inserted */
322 * The link field of an irn points to the var_info struct
323 * representing the corresponding variable.
325 #define set_var_info(irn, vi) set_irn_link(irn, vi)
326 #define get_var_info(irn) ((var_info_t *)get_irn_link(irn))
328 /* TODO insn-nr handling if ext defines new ones */
329 #define pmap_insert_sth(pmap, key, val) pmap_insert(pmap, (void *)key, (void *)val)
330 #define pmap_get_sth(pmap, key) pmap_get(pmap, (void *)key)
333 #define HASH_VAR_NR(var_nr) var_nr
337 static int compare_var_infos(const void *e1, const void *e2, size_t size) {
338 const var_info_t *v1 = e1;
339 const var_info_t *v2 = e2;
341 return v1->var_nr != v2->var_nr;
344 static INLINE var_info_t *var_find(set *vars, int var_nr) {
348 return set_find(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
351 static INLINE var_info_t *var_find_or_insert(set *vars, int var_nr) {
352 var_info_t vi, *found;
353 memset(&vi, 0, sizeof(vi));
356 found = set_insert(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
358 if (!found->values) {
359 found->values = pset_new_ptr(1);
360 found->spills = pset_new_ptr(1);
361 found->reloads = pset_new_ptr(1);
368 * Adds a value to a variable. Sets all pointers accordingly.
370 static INLINE var_info_t *var_add_value(be_raext_env_t *raenv, int var_nr, ir_node *irn) {
371 var_info_t *vi = var_find_or_insert(raenv->vars, var_nr);
373 /* var 2 value mapping */
374 pset_insert_ptr(vi->values, irn);
376 /* value 2 var mapping */
377 set_var_info(irn, vi);
383 * Adds a spill to a variable. Sets all pointers accordingly.
385 static INLINE var_info_t *var_add_spill(be_raext_env_t *raenv, int var_to_spill, ir_node *before) {
386 var_info_t *vi = var_find_or_insert(raenv->vars, var_to_spill);
387 ir_node *blk, *tospill, *spill;
389 assert(pset_count(vi->values) && "There are no values associated to this variable");
390 assert(!vi->reload_phase && "I have already seen a reload for this variable, so you cant spill anymore!");
392 /* add spill to graph and schedule */
393 blk = get_nodes_block(before);
394 tospill = dom_up_search(vi->values, before); /* which value gets spilled */
395 spill = be_new_Spill(raenv->cls, raenv->irg, blk, tospill, tospill); /* the corresponding spill node */
397 sched_add_before(before, spill);
399 /* the spill also points to the var_info of the spilled node */
400 set_var_info(spill, vi);
402 /* remember the spill */
403 pset_insert_ptr(vi->spills, spill);
409 * Adds a reload to a variable. Sets all pointers accordingly.
411 static INLINE var_info_t *var_add_reload(be_raext_env_t *raenv, int var_to_reload, int var_nr_for_reload, ir_node *before) {
412 var_info_t *vi = var_find_or_insert(raenv->vars, var_to_reload);
413 ir_node *blk, *spill, *reload;
415 assert(pset_count(vi->spills) && "There are no spills associated to this variable");
416 /* now we enter the reload phase, so no more spills are allowed */
417 vi->reload_phase = 1;
419 /* add reload to graph and schedule */
420 blk = get_nodes_block(before);
421 spill = pset_first(vi->spills); /* For now use an arbitrary spill node. This is corrected later in fix_reloads */
422 pset_break(vi->spills);
423 reload = be_new_Reload(raenv->cls, raenv->irg, blk, get_irn_mode(get_irn_n(spill, 0)), spill);
425 sched_add_before(before, reload);
427 /* create a new variable for the result of the reload */
428 assert(!var_find(raenv->vars, var_nr_for_reload) && "Each reload must define a new variable");
429 var_add_value(raenv, var_nr_for_reload, reload);
431 /* remember the reload */
432 pset_insert_ptr(vi->reloads, reload);
437 static INLINE pset *get_var_values(be_raext_env_t *raenv, int var_nr) {
438 var_info_t *vi = var_find(raenv->vars, var_nr);
439 assert(vi && "Variable does not (yet?) exist");
443 static INLINE pset *get_var_spills(be_raext_env_t *raenv, int var_nr) {
444 var_info_t *vi = var_find(raenv->vars, var_nr);
445 assert(vi && "Variable does not (yet?) exist");
449 static INLINE pset *get_var_reloads(be_raext_env_t *raenv, int var_nr) {
450 var_info_t *vi = var_find(raenv->vars, var_nr);
451 assert(vi && "Variable does not (yet?) exist");
456 * Define variables (numbers) for all SSA-values.
457 * All values in a phi class get assigned the same variable name.
458 * The link field maps values to the var-name
460 static void values_to_vars(ir_node *irn, void *env) {
461 be_raext_env_t *raenv = env;
466 vals = get_phi_class(irn);
469 /* not a phi class member, value == var */
470 vals = pset_new_ptr(1);
471 pset_insert_ptr(vals, irn);
474 /* values <--> var mapping */
475 n = pset_first(vals);
476 nr = get_irn_node_nr(n);
477 for (; n; n=pset_next(vals))
478 var_add_value(raenv, nr, n);
482 /******************************************************************************
485 | | | |_ _ _ __ ___ _ __ ___ _ __
486 | | | | | | | '_ ` _ \| '_ \ / _ \ '__|
487 | |__| | |_| | | | | | | |_) | __/ |
488 |_____/ \__,_|_| |_| |_| .__/ \___|_|
491 *****************************************************************************/
494 static INLINE ir_node *get_first_non_phi(pset *s) {
503 assert(0 && "There must be a non-phi-irn in this");
507 static void extract_vars_of_cls(be_raext_env_t *raenv) {
511 raenv->cls_vars = malloc(set_count(raenv->vars) * sizeof(*raenv->cls_vars));
512 assert(raenv->cls_vars);
514 set_foreach(raenv->vars, e) {
515 var_info_t *vi = (var_info_t *)e->dptr;
517 if (is_res_in_reg_class(get_first_non_phi(vi->values)))
518 raenv->cls_vars[count++] = vi;
521 raenv->cls_vars = realloc(raenv->cls_vars, count * sizeof(*raenv->cls_vars));
522 assert(raenv->cls_vars);
524 raenv->n_cls_vars = count;
529 * Check if node irn has a limited-constraint at position pos.
530 * If yes, dump it to FILE raenv->f
532 static INLINE void dump_constraint(be_raext_env_t *raenv, ir_node *irn, int pos) {
533 bitset_t *bs = bitset_alloca(raenv->cls->n_regs);
534 arch_register_req_t req;
536 arch_get_register_req(raenv->aenv, &req, irn, pos);
537 if (arch_register_req_is(&req, limited)) {
539 req.limited(req.limited_env, bs);
540 reg_nr = bitset_next_set(bs, 0);
541 fprintf(raenv->f, "<%d>", reg_nr);
542 assert(-1 == bitset_next_set(bs, reg_nr+1) && "Constraints with more than 1 possible register are not supported");
547 static void dump_nodes(be_raext_env_t *raenv) {
551 fprintf(f, "\nnodes {\n");
553 for (i=0; i<raenv->n_cls_vars; ++i) {
554 fprintf(f, "%d", raenv->cls_vars[i]->var_nr);
555 dump_constraint(raenv, get_first_non_phi(raenv->cls_vars[i]->values), -1);
563 static void dump_interferences(be_raext_env_t *raenv) {
565 var_info_t *vi1, *vi2;
566 ir_node *irn1, *irn2;
569 fprintf(f, "\ninterferences {\n");
571 for (i=0; i<raenv->n_cls_vars; ++i) {
572 vi1 = raenv->cls_vars[i];
574 for (o=i+1; o<raenv->n_cls_vars; ++o) {
575 vi2 = raenv->cls_vars[o];
577 pset_foreach(vi1->values, irn1)
578 pset_foreach(vi2->values, irn2)
579 if (values_interfere(irn1, irn2)) {
580 pset_break(vi1->values);
581 pset_break(vi2->values);
582 fprintf(f, "(%d %d)\n", vi1->var_nr, vi2->var_nr);
590 static void dump_affinities_walker(ir_node *irn, void *env) {
591 be_raext_env_t *raenv = env;
593 if (arch_irn_classify(raenv->aenv, irn) == arch_irn_class_copy) {
594 ir_node *src = get_irn_n(irn, 0);
595 var_info_t *vi1 = get_irn_link(irn);
596 var_info_t *vi2 = get_irn_link(src);
598 fprintf(raenv->f, "(%d %d)\n", vi1->var_nr, vi2->var_nr);
603 static void dump_affinities(be_raext_env_t *raenv) {
604 fprintf(raenv->f, "\ninterferences {\n");
605 irg_walk_graph(raenv->irg, NULL, dump_affinities_walker, raenv);
606 fprintf(raenv->f, "}\n");
610 * Dump all information needed by the external
611 * register allocator to a single file.
613 static void dump_to_file(be_raext_env_t *raenv, char *filename) {
616 if (!(f = fopen(filename, "wt"))) {
617 fprintf(stderr, "Could not open file %s for writing\n", filename);
622 /* dump register info */
623 fprintf(f, "regs %d\n", arch_register_class_n_regs(raenv->cls));
625 /* dump the interference graph */
627 dump_interferences(raenv);
628 dump_affinities(raenv);
633 /******************************************************************************
636 | |__ __ _____ ___ _ _| |_ ___
637 | __| \ \/ / _ \/ __| | | | __/ _ \
638 | |____ > < __/ (__| |_| | || __/
639 |______/_/\_\___|\___|\__,_|\__\___|
640 *****************************************************************************/
643 * Execute the external register allocator specified in the
644 * firm-option firm.be.ra.ext.callee
646 static void execute(char *prog_to_call, char *out_file, char *result_file) {
650 snprintf(cmd_line, sizeof(cmd_line), "%s %s %s", prog_to_call, out_file, result_file);
652 ret_status = system(cmd_line);
653 assert(ret_status != -1 && "Invokation of external register allocator failed");
656 /******************************************************************************
659 / \ _ __ _ __ | |_ _ | |__) |___ ___ _ _| | |_
660 / /\ \ | '_ \| '_ \| | | | | | _ // _ \/ __| | | | | __|
661 / ____ \| |_) | |_) | | |_| | | | \ \ __/\__ \ |_| | | |_
662 /_/ \_\ .__/| .__/|_|\__, | |_| \_\___||___/\__,_|_|\__|
665 *****************************************************************************/
667 #define INVALID_FILE_FORMAT assert(0 && "Invalid file format.")
669 static INLINE int is_before(const char *s, size_t len) {
670 if (!strncmp(s, "before", len))
672 if (!strncmp(s, "after", len))
678 static void fix_reloads(be_raext_env_t *raenv) {
680 set_foreach(raenv->vars, vi)
681 be_introduce_copies_pset(raenv->dom_info, vi->spills);
685 * Read in the actions performed by the external allocator.
686 * Apply these transformations to the irg.
687 * @return 1 if an allocation was read in. 0 otherwise.
689 static int read_and_apply_results(be_raext_env_t *raenv, char *filename) {
694 if (!(f = fopen(filename, "rt"))) {
695 fprintf(stderr, "Could not open file %s for reading\n", filename);
702 int loc, var_use_ident, var_def_ident, pos;
706 if (fscanf(f, " spill %6s %d %d ", &where, &loc, &var_use_ident) == 3) {
708 /* determine the node to insert the spill before */
709 ir_node *anchor = pmap_get_sth(raenv->nodes, loc);
710 assert(anchor && "insn-nr does not exist");
711 if (!is_before(where, sizeof(where)))
712 anchor = sched_next(anchor);
714 var_add_spill(raenv, var_use_ident, anchor);
717 /* handle a reload */
718 else if (fscanf(f, " reload %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
720 /* determine the node to insert the spill before */
721 ir_node *anchor = pmap_get_sth(raenv->nodes, loc);
722 assert(anchor && "insn-nr does not exist");
723 if (!is_before(where, sizeof(where)))
724 anchor = sched_next(anchor);
726 var_add_reload(raenv, var_use_ident, var_def_ident, anchor);
729 /* handle a set_irn_n */
730 else if (fscanf(f, " setarg %d %d %d ", &loc, &pos, &var_use_ident) == 3) {
731 ir_node *to_change, *new_arg;
732 var_info_t *vi = var_find(raenv->vars, var_use_ident);
733 assert(vi && vi->values && "New argument does not exist");
735 to_change = pmap_get_sth(raenv->nodes, loc);
736 assert(to_change && "insn-nr does not exist");
738 new_arg = dom_up_search(vi->values, to_change);
739 set_irn_n(to_change, pos, new_arg);
742 /* handle a copy insertion */
743 else if (fscanf(f, " copy %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
745 Ziel der Kopie ist Variable die bereits existiert
746 Ziel der Kopie ist eine neue Variable
757 int var_use_ident, reg_nr;
759 /* assign register */
760 if (fscanf(f, " assign %d %d ", &var_use_ident, ®_nr) == 2) {
761 pset *vals = get_var_values(raenv, var_use_ident);
764 assert(vals && "Variable does not (yet?) exist!");
765 pset_foreach(vals, irn)
766 arch_set_irn_register(raenv->aenv, irn, arch_register_for_index(raenv->cls, var_use_ident));
777 /* Free the psets held in the variable-infos */
778 set_foreach(raenv->vars, vi) {
779 del_pset(vi->values);
780 del_pset(vi->spills);
781 del_pset(vi->reloads);
785 /******************************************************************************
789 | |\/| |/ _` | | '_ \
790 | | | | (_| | | | | |
791 |_| |_|\__,_|_|_| |_|
792 *****************************************************************************/
795 * Default values for options
797 static void (*ssa_destr)(be_raext_env_t*) = ssa_destr_simple;
798 static char callee[128] = "echo";
802 * Allocate registers with an external program using a text-file interface.
804 * Do some computations (SSA-destruction and mapping of values--vars)
806 * Execute external program
807 * Read in results and apply them
810 static void be_ra_extern_main(const be_main_env_t *env, ir_graph *irg) {
811 be_raext_env_t raenv;
817 raenv.aenv = env->arch_env;
818 raenv.dom_info = be_compute_dominance_frontiers(irg);
819 raenv.vars = new_set(compare_var_infos, 64);
820 raenv.nodes = pmap_create();
826 /* SSA destruction */
829 /* Mapping of SSA-Values <--> Variables */
830 phi_class_compute(irg);
832 irg_walk_graph(irg, values_to_vars, NULL, &raenv);
834 dump_ir_block_graph_sched(irg, "-extern-ssadestr");
836 /* For all register classes */
837 for(clsnr = 0, clss = arch_isa_get_n_reg_class(raenv.aenv->isa); clsnr < clss; ++clsnr) {
839 char out[256], in[256];
841 raenv.cls = arch_isa_get_reg_class(raenv.aenv->isa, clsnr);
842 ir_snprintf(out, sizeof(out), "%F-%s.ra", irg, raenv.cls->name);
843 ir_snprintf(in, sizeof(in), "%F-%s.ra.res", irg, raenv.cls->name);
845 extract_vars_of_cls(&raenv);
848 dump_to_file(&raenv, out);
849 execute(callee, out, in);
850 done = read_and_apply_results(&raenv, in);
853 free(raenv.cls_vars);
857 pmap_destroy(raenv.nodes);
859 be_free_dominance_frontiers(raenv.dom_info);
863 /******************************************************************************
866 | | | |_ __ | |_ _ ___ _ __ ___
867 | | | | '_ \| __| |/ _ \| '_ \/ __|
868 | |__| | |_) | |_| | (_) | | | \__ \
869 \____/| .__/ \__|_|\___/|_| |_|___/
872 *****************************************************************************/
876 static const lc_opt_enum_const_ptr_items_t ssa_destr_items[] = {
877 { "simple", ssa_destr_simple },
878 { "rastello", ssa_destr_rastello },
882 static lc_opt_enum_const_ptr_var_t ssa_destr_var = {
883 (const void **) &ssa_destr, ssa_destr_items
886 static const lc_opt_table_entry_t be_ra_extern_options[] = {
887 LC_OPT_ENT_ENUM_FUNC_PTR("ssa_destr", "SSA destruction flavor", &ssa_destr_var),
888 LC_OPT_ENT_STR("callee", "The external program to call", callee, sizeof(callee)),
892 static void be_ra_extern_register_options(lc_opt_entry_t *root) {
893 lc_opt_entry_t *grp = lc_opt_get_grp(root, "ext");
895 lc_opt_add_table(grp, be_ra_extern_options);
898 #endif /* WITH_LIBCORE */
900 const be_ra_t be_ra_external_allocator = {
902 be_ra_extern_register_options,