added get_next_ir_opcodes() to allow allocation of cosecutive opcodes
[libfirm] / ir / be / beraextern.c
1 /**
2  * Author:      Daniel Grund
3  * Date:                17.01.2006
4  * Copyright:   (c) Universitaet Karlsruhe
5  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
6  *
7  * Implementation of the RA-Interface for an external, (non-SSA) register allocator.
8  *
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
12  *
13
14
15 The input file format
16 ----------------------
17
18 inputfile       ::= regs cfg .
19
20 regs            ::= 'regs' regcount 'saved-by-caller' reg-list 'saved-by-callee' reg-list .                                             // Anzahl der register (0..regcount-1), die zur Verfuegung stehen
21
22 reg-list        ::= reg-nr
23                           | reg-nr reg-list
24
25 cfg                     ::= 'cfg' ident '{' block* edge* '}' .          // Steuerflussgraph der Prozedur
26
27 block           ::= 'block' block-nr '{' insn* '}' .            // Grundblock im cfg versehen mit einer nummer
28
29 edge            ::= 'cf-edge' block-nr block-nr .                       // Steuerflusskante src-->tgt
30
31 insn            ::= gen-insn                                                            // Befehl in einem block
32                           | copy-insn .
33
34 gen-insn        ::= 'insn' insn-nr '{' uses defs '}' .
35 copy-insn       ::= 'copy' insn-nr '{' uses defs '}' .
36 call-insn       ::= 'call' insn-nr '{' uses defs '}' .
37
38 defs            ::= 'def' var-list .                                            // Liste der definierten/verwendeten Variablen
39 uses            ::= 'use' var-list .
40
41 var-list        ::= var-ref
42                           | var-ref var-list .
43
44 var-ref         ::= var-nr
45                           | var-nr '<' reg-nr '>' .                                     // reg-nr gibt register constraint an.
46
47
48 ident           ::= non-whitespace-char* .
49 regcount, block-nr, insn-nr, reg-nr, var-nr ::= integer .
50
51
52 The output file format
53 -----------------------
54
55 outputfile      ::= action* assign*.
56
57 action          ::= 'spill'  loc var-nr                                 // insert a spill    spill(var-nr);
58                           | 'reload' loc new-var-nr  var-nr             // insert a reload   new-var-nr := reload(var-nr);
59                           | 'setarg' insn-nr pos var-nr                 // change a usage to insn(..., var-nr, ...)  (equals set_irn_n)
60                           | 'copy'   loc var-nr var-nr                  // insert a copy     var-nr[1] := var-nr[2];
61
62 assign          ::= 'assign' var-nr reg-nr .                    // assign var-nr the register reg-nr
63
64 loc                     ::= 'before' insn-nr
65                           | 'after'  insn-nr .
66
67
68 Constraints for output file
69 ---------------------------
70 1) The returned actions must result in a non-ssa-program
71    equivalent to the former input.
72 2) All names (numbers) must be defined before their first use.
73    Numbers already occuring in the input file are implicitly defined in the output file.
74 3) All spills of a variable must precede the first reload of this variable
75 4) Each reload must define a new variable name
76
77
78
79 ******** End of file format docu ********/
80
81 #ifdef HAVE_CONFIG_H
82 #include "config.h"
83 #endif
84
85 #ifdef WIN32
86 #include <malloc.h>
87 #else
88 #include <alloca.h>
89 #endif
90
91 #include <stdio.h>
92 #include <stdlib.h>
93 #ifdef WITH_LIBCORE
94 #include <libcore/lc_opts.h>
95 #include <libcore/lc_opts_enum.h>
96 #endif
97
98 #include "set.h"
99 #include "pset.h"
100 #include "pmap.h"
101 #include "bitset.h"
102
103 #include "irprintf_t.h"
104 #include "irnode_t.h"
105 #include "irgraph_t.h"
106 #include "irgwalk.h"
107 #include "irdom_t.h"
108 #include "phiclass.h"
109
110 #include "beraextern.h"
111 #include "bearch.h"
112 #include "benode_t.h"
113 #include "beirgmod.h"
114 #include "besched.h"
115 #include "beutil.h"
116
117 typedef struct _var_info_t var_info_t;
118
119 /**
120  * Environment with all the needed stuff
121  */
122 typedef struct _be_raext_env_t {
123         arch_env_t *aenv;
124         const arch_register_class_t *cls;
125         ir_graph *irg;
126         dom_front_info_t *dom_info;
127
128         FILE *f;                /**< file handle used for out- and input file */
129         set *vars;              /**< contains all var_info_t */
130         pmap *nodes;    /**< maps nodes numbers (int) to the node (ir_node*) having that node_nr */
131 } be_raext_env_t;
132
133
134
135 /******************************************************************************
136     _    _      _
137    | |  | |    | |
138    | |__| | ___| |_ __   ___ _ __ ___
139    |  __  |/ _ \ | '_ \ / _ \ '__/ __|
140    | |  | |  __/ | |_) |  __/ |  \__ \
141    |_|  |_|\___|_| .__/ \___|_|  |___/
142                  | |
143                  |_|
144  *****************************************************************************/
145
146
147 #define pset_foreach(pset, irn)  for(irn=pset_first(pset); irn; irn=pset_next(pset))
148 #define set_foreach(set, e)  for(e=set_first(set); e; e=set_next(set))
149
150
151 /**
152  * Checks if _the_ result of the irn belongs to the
153  * current register class (raenv->cls)
154  * NOTE: Only the first result is checked.
155  */
156 #define is_res_in_reg_class(irn) arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls)
157
158
159 /**
160  * Checks if the irn uses or defines values of the
161  * current register class (raenv->cls)
162  */
163 static INLINE int is_sth_in_reg_class(be_raext_env_t *raenv, const ir_node *irn) {
164         int max, i;
165
166         /* check arguments */
167         for (i=0, max=get_irn_arity(irn); i<max; ++i)
168                 if (arch_irn_has_reg_class(raenv->aenv, get_irn_n(irn, i), -1, raenv->cls))
169                         return 1;
170
171         /* check result(s) */
172         if (get_irn_mode(irn) == mode_T) {
173                 ir_node *proj;
174                 for (proj = sched_next(irn); is_Proj(proj); proj = sched_next(proj))
175                         if (arch_irn_has_reg_class(raenv->aenv, proj, -1, raenv->cls))
176                                 return 1;
177                 return 0;
178         } else {
179                 return arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls);
180         }
181
182         assert(0 && "Where did you come from???");
183 }
184
185 /******************************************************************************
186      _____ _____              _____            _
187     / ____/ ____|  /\        |  __ \          | |
188    | (___| (___   /  \ ______| |  | | ___  ___| |_ _ __
189     \___ \\___ \ / /\ \______| |  | |/ _ \/ __| __| '__|
190     ____) |___) / ____ \     | |__| |  __/\__ \ |_| |
191    |_____/_____/_/    \_\    |_____/ \___||___/\__|_|
192
193  *****************************************************************************/
194
195 #define mark_as_done(irn, pos)                  set_irn_link(irn, INT_TO_PTR(pos+1))
196 #define has_been_done(irn, pos)                 (PTR_TO_INT(get_irn_link(irn)) > pos)
197
198 /**
199  * Insert a copy for the argument of @p start_phi found at position @p pos.
200  * Also searches a phi-loop of arbitrary length to detect and resolve
201  *   the class of phi-swap-problems. To search for a loop recursion is used.
202  *
203  * 1) Simplest case (phi with a non-phi arg):
204  *     A single copy is inserted.
205  *
206  * 2) Phi chain (phi (with phi-arg)* with non=phi arg):
207  *     Several copies are placed, each after returning from recursion.
208  *
209  * 3) Phi-loop:
210  *     On detection a loop breaker is inserted, which is a copy of the start_phi.
211  *     This copy then pretends beeing the argumnent of the last phi.
212  *     Now case 2) can be used.
213  *
214  * The values of @p start_phi and @p pos never change during recursion.
215  *
216  * @p raenv      Environment with all the stuff needed
217  * @p start_phi  Phi node to process
218  * @p pos        Argument position to insert copy/copies for
219  * @p curr_phi   Phi node currently processed during recursion. Equals start_phi on initial call
220  *
221  * @return NULL  If no copy is necessary
222  *         NULL  If the phi has already been processed at this pos
223  *               Link field is used to keep track of processed positions
224  *         In all other cases the ir_node *copy which was placed is returned.
225  */
226 static ir_node *insert_copies(be_raext_env_t *raenv, ir_node *start_phi, int pos, ir_node *curr_phi) {
227         ir_node *arg = get_irn_n(curr_phi, pos);
228         ir_node *arg_blk = get_nodes_block(arg);
229         ir_node *pred_blk = get_Block_cfgpred_block(get_nodes_block(curr_phi), pos);
230         ir_node *curr_cpy, *last_cpy;
231
232         assert(is_Phi(start_phi) && is_Phi(curr_phi));
233
234         if (has_been_done(start_phi, pos))
235                 return NULL;
236
237         /* In case this is a 'normal' phi we insert into
238          * the schedule before the pred_blk irn */
239         last_cpy = pred_blk;
240
241         /* If we detect a loop stop recursion. */
242         if (arg == start_phi) {
243                 ir_node *loop_breaker;
244                 if (start_phi == curr_phi) {
245                         /* Phi directly uses itself. No copy necessary */
246                         return NULL;
247                 }
248
249                 /* At least 2 phis are involved */
250                 /* Insert a loop breaking copy (an additional variable T) */
251                 loop_breaker = be_new_Copy(raenv->cls, raenv->irg, pred_blk, start_phi);
252                 sched_add_before(pred_blk, loop_breaker);
253
254                 arg = loop_breaker;
255         }
256
257         /* If arg is a phi in the same block we have to continue search */
258         if (is_Phi(arg) && arg_blk == get_nodes_block(start_phi))
259                 last_cpy = insert_copies(raenv, start_phi, pos, arg);
260
261         /* Insert copy of argument (may be the loop-breaker) */
262         curr_cpy = be_new_Copy(raenv->cls, raenv->irg, pred_blk, arg);
263         set_irn_n(curr_phi, pos, curr_cpy);
264         mark_as_done(curr_phi, pos);
265         sched_add_before(last_cpy, curr_cpy);
266         return curr_cpy;
267 }
268
269
270 /**
271  * Perform simple SSA-destruction with copies.
272  * The order of processing _must_ be
273  *  for all positions {
274  *    for all phis {
275  *      doit
276  *    }
277  *  }
278  * else the magic to keep track of processed phi-positions will fail in
279  * function 'insert_copies'
280  */
281 static void ssa_destr_simple_walker(ir_node *blk, void *env) {
282         be_raext_env_t *raenv = env;
283         int pos, max;
284         ir_node *phi;
285
286         /* for all argument positions of the phis */
287         for (pos=0, max=get_irn_arity(blk); pos<max; ++pos) {
288
289                 /* for all phi nodes (which are scheduled first) */
290                 sched_foreach(blk, phi) {
291                         if (!is_Phi(phi))
292                                 break;
293
294                         raenv->cls = arch_get_irn_reg_class(raenv->aenv, phi, -1);
295                         insert_copies(raenv, phi, pos, phi);
296                 }
297         }
298 }
299
300
301 static void ssa_destr_simple(be_raext_env_t *raenv) {
302         be_clear_links(raenv->irg);
303         irg_block_walk_graph(raenv->irg, ssa_destr_simple_walker, NULL, raenv);
304 }
305
306
307 static void ssa_destr_rastello(be_raext_env_t *raenv) {
308         assert(0 && "NYI");
309         /* TODO
310         phi_class_compute(raenv->irg);
311         irg_block_walk_graph(irg, ssa_destr_rastello, NULL, &raenv);
312         */
313 }
314
315 /******************************************************************************
316    __      __   _       ___   __      __
317    \ \    / /  | |     |__ \  \ \    / /
318     \ \  / /_ _| |___     ) |  \ \  / /_ _ _ __ ___
319      \ \/ / _` | / __|   / /    \ \/ / _` | '__/ __|
320       \  / (_| | \__ \  / /_     \  / (_| | |  \__ \
321        \/ \__,_|_|___/ |____|     \/ \__,_|_|  |___/
322  *****************************************************************************/
323
324 /**
325  * This struct maps a variable (nr) to
326  *  1) the values belonging to this variable
327  *  2) the spills of this variable
328  */
329 struct _var_info_t {
330         int var_nr;             /* the key for comparesion */
331         pset *values;   /* the ssa-values belonging to this variable */
332         pset *spills;   /* the spills of this variable */
333         pset *reloads;  /* the relaods of this variable */
334         unsigned reload_phase:1;        /* 0 initially, 1 if a reload of this var has been inserted */
335 };
336
337 /**
338  * The link field of an irn points to the var_info struct
339  * representing the corresponding variable.
340  */
341 #define set_var_info(irn, vi)                           set_irn_link(irn, vi)
342 #define get_var_info(irn)                                       ((var_info_t *)get_irn_link(irn))
343
344 /* TODO insn-nr handling if ext defines new ones */
345 #define pmap_insert_sth(pmap, key, val) pmap_insert(pmap, (void *)key, (void *)val)
346 #define pmap_get_sth(pmap, key)                 pmap_get(pmap, (void *)key)
347
348
349 #define HASH_VAR_NR(var_nr) var_nr
350
351
352
353 static int compare_var_infos(const void *e1, const void *e2, size_t size) {
354         const var_info_t *v1 = e1;
355         const var_info_t *v2 = e2;
356
357         return v1->var_nr != v2->var_nr;
358 }
359
360 static INLINE var_info_t *var_find(set *vars, int var_nr) {
361         var_info_t vi;
362         vi.var_nr = var_nr;
363
364         return set_find(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
365 }
366
367 static INLINE var_info_t *var_find_or_insert(set *vars, int var_nr) {
368         var_info_t vi, *found;
369         memset(&vi, 0, sizeof(vi));
370         vi.var_nr = var_nr;
371
372         found = set_insert(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
373
374         if (!found->values) {
375                 found->values  = pset_new_ptr(1);
376                 found->spills  = pset_new_ptr(1);
377                 found->reloads = pset_new_ptr(1);
378         }
379
380         return found;
381 }
382
383 /**
384  * Adds a value to a variable. Sets all pointers accordingly.
385  */
386 static INLINE var_info_t *var_add_value(be_raext_env_t *raenv, int var_nr, ir_node *irn) {
387         var_info_t *vi = var_find_or_insert(raenv->vars, var_nr);
388
389         /* var 2 value mapping */
390         pset_insert_ptr(vi->values, irn);
391
392         /* value 2 var mapping */
393         set_var_info(irn, vi);
394
395         return vi;
396 }
397
398 /**
399  * Adds a spill to a variable. Sets all pointers accordingly.
400  */
401 static INLINE var_info_t *var_add_spill(be_raext_env_t *raenv, int var_to_spill, ir_node *before) {
402         var_info_t *vi = var_find_or_insert(raenv->vars, var_to_spill);
403         ir_node *blk, *tospill, *spill;
404
405         assert(pset_count(vi->values) && "There are no values associated to this variable (yet?)");
406         assert(!vi->reload_phase && "I have already seen a reload for this variable, so you cant spill anymore!");
407
408         /* add spill to graph and schedule */
409         blk     = get_nodes_block(before);
410         tospill = dom_up_search(vi->values, before); /* which value gets spilled */
411         spill   = be_new_Spill(raenv->cls, raenv->irg, blk, tospill, tospill); /* the corresponding spill node */
412
413         sched_add_before(before, spill);
414
415         /* the spill also points to the var_info of the spilled node */
416         set_var_info(spill, vi);
417
418         /* remember the spill */
419         pset_insert_ptr(vi->spills, spill);
420
421         return vi;
422 }
423
424 /**
425  * Adds a reload to a variable. Sets all pointers accordingly.
426  */
427 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) {
428         var_info_t *vi = var_find_or_insert(raenv->vars, var_to_reload);
429         ir_node *blk, *spill, *reload;
430
431         assert(pset_count(vi->spills) && "There are no spills associated to this variable (yet?)");
432         /* now we enter the reload phase, so no more spills are allowed */
433         vi->reload_phase = 1;
434
435         /* add reload to graph and schedule */
436         blk    = get_nodes_block(before);
437         spill  = pset_first(vi->spills); /* For now use an arbitrary spill node. This is corrected later in fix_reloads */
438         pset_break(vi->spills);
439         reload = be_new_Reload(raenv->cls, raenv->irg, blk, get_irn_mode(get_irn_n(spill, 0)), spill);
440
441         sched_add_before(before, reload);
442
443         /* create a new variable for the result of the reload */
444         assert(!var_find(raenv->vars, var_nr_for_reload) && "Each reload must define a new variable");
445         var_add_value(raenv, var_nr_for_reload, reload);
446
447         /* remember the reload */
448         pset_insert_ptr(vi->reloads, reload);
449
450         return vi;
451 }
452
453 static INLINE pset *get_var_values(be_raext_env_t *raenv, int var_nr) {
454         var_info_t *vi = var_find(raenv->vars, var_nr);
455         assert(vi && "Variable does not (yet?) exist");
456         return vi->values;
457 }
458
459 static INLINE pset *get_var_spills(be_raext_env_t *raenv, int var_nr) {
460         var_info_t *vi = var_find(raenv->vars, var_nr);
461         assert(vi && "Variable does not (yet?) exist");
462         return vi->spills;
463 }
464
465 static INLINE pset *get_var_reloads(be_raext_env_t *raenv, int var_nr) {
466         var_info_t *vi = var_find(raenv->vars, var_nr);
467         assert(vi && "Variable does not (yet?) exist");
468         return vi->reloads;
469 }
470
471 /**
472  * Define variables (numbers) for all SSA-values.
473  * All values in a phi class get assigned the same variable name.
474  * The link field maps values to the var-name
475  */
476 static void values_to_vars(ir_node *irn, void *env) {
477         be_raext_env_t *raenv = env;
478         ir_node *n;
479         int nr;
480         pset *vals;
481
482         vals = get_phi_class(irn);
483
484         if (!vals) {
485                 /* not a phi class member, value == var */
486                 vals = pset_new_ptr(1);
487                 pset_insert_ptr(vals, irn);
488         }
489
490         /* values <--> var mapping */
491         n = pset_first(vals);
492         nr = get_irn_node_nr(n);
493         for (; n; n=pset_next(vals))
494                 var_add_value(raenv, nr, n);
495 }
496
497 /******************************************************************************
498                          _         _____                 _ _
499        /\               | |       |  __ \               | | |
500       /  \   _ __  _ __ | |_   _  | |__) |___  ___ _   _| | |_
501      / /\ \ | '_ \| '_ \| | | | | |  _  // _ \/ __| | | | | __|
502     / ____ \| |_) | |_) | | |_| | | | \ \  __/\__ \ |_| | | |_
503    /_/    \_\ .__/| .__/|_|\__, | |_|  \_\___||___/\__,_|_|\__|
504             | |   | |       __/ |
505             |_|   |_|      |___/
506  *****************************************************************************/
507
508 #define INVALID_FILE_FORMAT assert(0 && "Invalid file format.")
509
510 static INLINE int is_before(const char *s, size_t len) {
511         if (!strncmp(s, "before", len))
512                 return 1;
513         if (!strncmp(s, "after", len))
514                 return 0;
515         INVALID_FILE_FORMAT;
516         return -1;
517 }
518
519 static void fix_reloads(be_raext_env_t *raenv) {
520         var_info_t *vi;
521         set_foreach(raenv->vars, vi)
522                 be_introduce_copies_pset(raenv->dom_info, vi->spills);
523 }
524
525 /**
526  * Read in the actions performed by the external allocator.
527  * Apply these transformations to the irg.
528  */
529 static void read_and_apply_results(be_raext_env_t *raenv, char *filename) {
530         FILE *f;
531         var_info_t *vi;
532         int phase=0;
533
534         if (!(f = fopen(filename, "rt"))) {
535                 fprintf(stderr, "Could not open file %s for reading\n", filename);
536                 exit(0xdeadbeef);
537         }
538         raenv->f = f;
539
540
541
542         /* parse the file */
543         while (phase == 0) {
544                 int loc, var_use_ident, var_def_ident, pos;
545                 char where[16];
546
547                 /* handle a spill */
548                 if (fscanf(f, " spill %6s %d %d ", &where, &loc, &var_use_ident) == 3) {
549
550                         /* determine the node to insert the spill before */
551                         ir_node *anchor = pmap_get_sth(raenv->nodes, loc);
552                         assert(anchor && "insn-nr does not exist");
553                         if (!is_before(where, sizeof(where)))
554                                 anchor = sched_next(anchor);
555
556                         var_add_spill(raenv, var_use_ident, anchor);
557                 }
558
559                 /* handle a reload */
560                 else if (fscanf(f, " reload %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
561
562                         /* determine the node to insert the spill before */
563                         ir_node *anchor = pmap_get_sth(raenv->nodes, loc);
564                         assert(anchor && "insn-nr does not exist");
565                         if (!is_before(where, sizeof(where)))
566                                 anchor = sched_next(anchor);
567
568                         var_add_reload(raenv, var_use_ident, var_def_ident, anchor);
569                 }
570
571                 /* handle a set_irn_n */
572                 else if (fscanf(f, " setarg %d %d %d ", &loc, &pos, &var_use_ident) == 3) {
573                         ir_node *to_change, *new_arg;
574                         var_info_t *vi = var_find(raenv->vars, var_use_ident);
575                         assert(vi && vi->values && "New argument does not exist");
576
577                         to_change = pmap_get_sth(raenv->nodes, loc);
578                         assert(to_change && "insn-nr does not exist");
579
580                         new_arg = dom_up_search(vi->values, to_change);
581                         set_irn_n(to_change, pos, new_arg);
582                 }
583
584                 /* handle a copy insertion */
585                 else if (fscanf(f, " copy %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
586                         /* TODO
587                                 Ziel der Kopie ist Variable die bereits existiert
588                                 Ziel der Kopie ist eine neue Variable
589                         */
590                 }
591
592                 else
593                         phase++;
594         }
595
596         fix_reloads(raenv);
597
598         while (phase == 1) {
599                 int var_use_ident, reg_nr;
600
601                 /* assign register */
602                 if (fscanf(f, " assign %d %d ", &var_use_ident, &reg_nr) == 2) {
603                         pset *vals = get_var_values(raenv, var_use_ident);
604                         ir_node *irn;
605
606                         assert(vals && "Variable does not (yet?) exist!");
607                         pset_foreach(vals, irn)
608                                 arch_set_irn_register(raenv->aenv, irn, arch_register_for_index(raenv->cls, var_use_ident));
609                 }
610                 else
611                         phase++;
612         }
613
614         if (!feof(f))
615                 INVALID_FILE_FORMAT;
616
617         fclose(f);
618
619         /* Free the psets held in the variable-infos */
620         set_foreach(raenv->vars, vi) {
621                 del_pset(vi->values);
622                 del_pset(vi->spills);
623                 del_pset(vi->reloads);
624         }
625 }
626
627 /******************************************************************************
628     _____
629    |  __ \
630    | |  | |_   _ _ __ ___  _ __   ___ _ __
631    | |  | | | | | '_ ` _ \| '_ \ / _ \ '__|
632    | |__| | |_| | | | | | | |_) |  __/ |
633    |_____/ \__,_|_| |_| |_| .__/ \___|_|
634                           | |
635                           |_|
636  *****************************************************************************/
637
638
639 /**
640  * Check if node irn has a limited-constraint at position pos.
641  * If yes, dump it to FILE raenv->f
642  */
643 static INLINE void dump_constraint(be_raext_env_t *raenv, ir_node *irn, int pos) {
644         bitset_t *bs = bitset_alloca(raenv->cls->n_regs);
645         arch_register_req_t req;
646
647         arch_get_register_req(raenv->aenv, &req, irn, pos);
648         if (arch_register_req_is(&req, limited)) {
649                 int reg_nr;
650                 req.limited(req.limited_env, bs);
651                 reg_nr = bitset_next_set(bs, 0);
652                 fprintf(raenv->f, " <%d>", reg_nr);
653                 assert(-1 == bitset_next_set(bs, reg_nr+1) && "Constraints with more than 1 possible register are not supported");
654         }
655 }
656
657
658 /**
659  * Dump all blocks and instructions in that block
660  */
661 static void dump_blocks(ir_node *blk, void *env) {
662         be_raext_env_t *raenv = env;
663         ir_node *irn;
664         FILE *f = raenv->f;
665         int nr = get_irn_node_nr(blk);
666
667         pmap_insert_sth(raenv->nodes, nr, blk);
668
669         /* begin block scope */
670         fprintf(f, "\n");
671         fprintf(f, "  block %d {\n", nr);
672
673         /* for each instruction */
674         for(irn=sched_first(blk); !sched_is_end(irn); irn=sched_next(irn)) {
675                 int max, i;
676                 int node_nr;
677
678                 if (is_Phi(irn) || !is_sth_in_reg_class(raenv, irn))
679                         continue;
680
681                 /* kind of instruction */
682                 if (arch_irn_classify(raenv->aenv, irn) == arch_irn_class_copy)
683                         fprintf(f, "    copy");
684                 else if (arch_irn_classify(raenv->aenv, irn) == arch_irn_class_call)
685                         fprintf(f, "    call");
686                 else
687                         fprintf(f, "    insn");
688
689                 /* number */
690                 node_nr = get_irn_node_nr(irn);
691                 fprintf(f, " %ld {\n", node_nr);
692
693                 pmap_insert_sth(raenv->nodes, node_nr, irn);
694
695
696                 /*
697                  * print all uses
698                  */
699                 fprintf(f, "      use");
700                 for (i=0, max=get_irn_arity(irn); i<max; ++i) {
701                         ir_node *arg = get_irn_n(irn, i);
702                         if (arch_irn_has_reg_class(raenv->aenv, arg, -1, raenv->cls)) {
703                                 fprintf(f, " %d", get_var_info(arg)->var_nr);
704                                 dump_constraint(raenv, irn, i);
705                         }
706                 }
707                 fprintf(f,"\n");
708
709                 /*
710                  * print all defs
711                  */
712                 fprintf(f, "      def");
713                 /* special handling of projs */
714                 if (get_irn_mode(irn) == mode_T) {
715                         for (irn = sched_next(irn); is_Proj(irn); irn = sched_next(irn))
716                                 if (arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls)) {
717                                         fprintf(f, " %d", get_var_info(irn)->var_nr);
718                                         dump_constraint(raenv, irn, -1);
719                                 }
720                         irn = sched_prev(irn); /* for outer loop */
721                 } else {
722                         if (arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls)) {
723                                 fprintf(f, " %d", get_var_info(irn)->var_nr);
724                                 dump_constraint(raenv, irn, -1);
725                         }
726                 }
727                 fprintf(f,"\n");
728
729                 /* end of insn scope */
730                 fprintf(f, "    }\n");
731         }
732
733         /* end the block scope */
734         fprintf(f, "  }\n");
735 }
736
737
738 /**
739  * Dump all control flow edges of this irg
740  */
741 static void dump_edges(ir_node *blk, void *env) {
742         be_raext_env_t *raenv = env;
743         int i, max;
744
745         if (get_irg_start_block(get_irn_irg(blk)) == blk)
746                 return;
747
748         /* dump cf edges in the flow-order "pred succ" */
749         for (i=0, max=get_irn_arity(blk); i<max; ++i) {
750                 ir_node *pred = get_Block_cfgpred_block(blk, i);
751                 fprintf(raenv->f, "  cf_edge %ld %ld\n", get_irn_node_nr(pred), get_irn_node_nr(blk));
752         }
753 }
754
755
756 /**
757  * Dump all information needed by the external
758  * register allocator to a single file.
759  */
760 static void dump_to_file(be_raext_env_t *raenv, char *filename) {
761         FILE *f;
762         int i, reg_count;
763
764         if (!(f = fopen(filename, "wt"))) {
765                 fprintf(stderr, "Could not open file %s for writing\n", filename);
766                 exit(0xdeadbeef);
767         }
768         raenv->f = f;
769
770         /* dump register info */
771         reg_count = arch_register_class_n_regs(raenv->cls);
772         fprintf(f, "regs %d", reg_count);
773
774         fprintf(f, " saved-by-caller");
775         for (i=0; i<reg_count; ++i)
776                 if (arch_register_type_is(arch_register_for_index(raenv->cls, i), caller_saved))
777                         fprintf(f, " %d", i);
778
779         fprintf(f, " saved-by-callee");
780         for (i=0; i<reg_count; ++i)
781                 if (arch_register_type_is(arch_register_for_index(raenv->cls, i), callee_saved))
782                         fprintf(f, " %d", i);
783
784         fprintf(f, "\n");
785
786         /* dump the cfg */
787
788         fprintf(f, "cfg %s {\n", filename);
789         irg_block_walk_graph(raenv->irg, NULL, dump_blocks, raenv);
790         irg_block_walk_graph(raenv->irg, NULL, dump_edges, raenv);
791         fprintf(f, "}\n");
792
793         fclose(f);
794 }
795
796
797 /******************************************************************************
798     ______                     _
799    |  ____|                   | |
800    | |__  __  _____  ___ _   _| |_ ___
801    |  __| \ \/ / _ \/ __| | | | __/ _ \
802    | |____ >  <  __/ (__| |_| | ||  __/
803    |______/_/\_\___|\___|\__,_|\__\___|
804  *****************************************************************************/
805
806 /**
807  * Execute the external register allocator specified in the
808  * firm-option firm.be.ra.ext.callee
809  */
810 static void execute(char *prog_to_call, char *out_file, char *result_file) {
811         char cmd_line[1024];
812         int ret_status;
813
814         snprintf(cmd_line, sizeof(cmd_line), "%s %s %s", prog_to_call, out_file, result_file);
815
816         ret_status = system(cmd_line);
817         assert(ret_status != -1 && "Invokation of external register allocator failed");
818 }
819
820 /******************************************************************************
821     __  __       _
822    |  \/  |     (_)
823    | \  / | __ _ _ _ __
824    | |\/| |/ _` | | '_ \
825    | |  | | (_| | | | | |
826    |_|  |_|\__,_|_|_| |_|
827  *****************************************************************************/
828
829 /**
830  * Default values for options
831  */
832 static void (*ssa_destr)(be_raext_env_t*) = ssa_destr_simple;
833 static char callee[128] = "echo";
834
835
836 /**
837  * Allocate registers with an external program using a text-file interface.
838  *
839  * Do some computations (SSA-destruction and mapping of values--vars)
840  * Write file
841  * Execute external program
842  * Read in results and apply them
843  *
844  */
845 static void be_ra_extern_main(const be_main_env_t *env, ir_graph *irg) {
846         be_raext_env_t raenv;
847         int clsnr, clss;
848
849         compute_doms(irg);
850
851         raenv.irg      = irg;
852         raenv.aenv     = env->arch_env;
853         raenv.dom_info = be_compute_dominance_frontiers(irg);
854         raenv.vars     = new_set(compare_var_infos, 64);
855         raenv.nodes    = pmap_create();
856         /* SSA destruction */
857         ssa_destr(&raenv);
858
859         be_clear_links(irg);
860         phi_class_compute(irg);
861         irg_walk_graph(irg, values_to_vars, NULL, &raenv);
862
863         dump_ir_block_graph_sched(irg, "-extern-ssadestr");
864
865         /* For all register classes */
866         for(clsnr = 0, clss = arch_isa_get_n_reg_class(raenv.aenv->isa); clsnr < clss; ++clsnr) {
867                 char out[256], in[256];
868
869                 raenv.cls = arch_isa_get_reg_class(raenv.aenv->isa, clsnr);
870                 ir_snprintf(out, sizeof(out), "%F-%s.ra", irg, raenv.cls->name);
871                 ir_snprintf(in, sizeof(in), "%F-%s.ra.res", irg, raenv.cls->name);
872
873                 dump_to_file(&raenv, out);
874
875                 execute(callee, out, in);
876
877                 read_and_apply_results(&raenv, in);
878         }
879
880         /* Clean up */
881         pmap_destroy(raenv.nodes);
882         del_set(raenv.vars);
883         be_free_dominance_frontiers(raenv.dom_info);
884
885 }
886
887 /******************************************************************************
888      ____        _   _
889     / __ \      | | (_)
890    | |  | |_ __ | |_ _  ___  _ __  ___
891    | |  | | '_ \| __| |/ _ \| '_ \/ __|
892    | |__| | |_) | |_| | (_) | | | \__ \
893     \____/| .__/ \__|_|\___/|_| |_|___/
894           | |
895           |_|
896  *****************************************************************************/
897
898 #ifdef WITH_LIBCORE
899
900 static const lc_opt_enum_const_ptr_items_t ssa_destr_items[] = {
901         { "simple",    ssa_destr_simple },
902         { "rastello",  ssa_destr_rastello },
903         { NULL,      NULL }
904 };
905
906 static lc_opt_enum_const_ptr_var_t ssa_destr_var = {
907         (const void **) &ssa_destr, ssa_destr_items
908 };
909
910 static const lc_opt_table_entry_t be_ra_extern_options[] = {
911         LC_OPT_ENT_ENUM_FUNC_PTR("ssa_destr", "SSA destruction flavor", &ssa_destr_var),
912         LC_OPT_ENT_STR("callee", "The external program to call", callee, sizeof(callee)),
913         { NULL }
914 };
915
916 static void be_ra_extern_register_options(lc_opt_entry_t *root) {
917         lc_opt_entry_t *grp = lc_opt_get_grp(root, "ext");
918
919         lc_opt_add_table(grp, be_ra_extern_options);
920 }
921
922 #endif /* WITH_LIBCORE */
923
924 const be_ra_t be_ra_external_allocator = {
925 #ifdef WITH_LIBCORE
926         be_ra_extern_register_options,
927 #endif
928         be_ra_extern_main
929 };