873350e36b04edb142179ff30847bd886e4b88b3
[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 nodes interf affinities .
19
20 regs            ::= 'regs' regcount .                                           // Anzahl der register (0..regcount-1), die zur Verfuegung stehen
21
22 nodes           ::= 'nodes' '{' node* '}' .                                     // All nodes in the graph
23
24 interf          ::= 'interferences' '{' edge* '}' .                     // Interference edges of the graph
25
26 affinities      ::= 'affinities' '{' edge* '}' .                        // Affinity edges of the graph
27
28 node            ::= node-nr
29                           | node-nr '<' reg-nr '>' .                            // Reg-nr is present in case of constraints
30
31 edge            ::= '(' node-nr node-nr ')' .
32
33
34 regcount, node-nr ::= integer .
35
36
37 The output file format
38 -----------------------
39
40 outputfile      ::= spills | allocs .
41
42 spills          ::= 'spills' '{' node-nr+ '}' .
43
44 allocs          ::= 'allocs' '{' alloc* '}' .
45
46 alloc           ::= node-nr reg-nr .
47
48
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
57
58
59
60 ******** End of file format docu ********/
61
62 #ifdef HAVE_CONFIG_H
63 #include "config.h"
64 #endif
65
66 #ifdef WIN32
67 #include <malloc.h>
68 #else
69 #include <alloca.h>
70 #endif
71
72 #include <stdio.h>
73 #include <stdlib.h>
74 #ifdef WITH_LIBCORE
75 #include <libcore/lc_opts.h>
76 #include <libcore/lc_opts_enum.h>
77 #endif
78
79 #include "set.h"
80 #include "pset.h"
81 #include "pmap.h"
82 #include "bitset.h"
83
84 #include "irprintf_t.h"
85 #include "irnode_t.h"
86 #include "irgraph_t.h"
87 #include "irgwalk.h"
88 #include "irdom_t.h"
89 #include "phiclass.h"
90
91 #include "beraextern.h"
92 #include "bearch.h"
93 #include "benode_t.h"
94 #include "beirgmod.h"
95 #include "besched.h"
96 #include "beutil.h"
97
98 typedef struct _var_info_t var_info_t;
99
100 /**
101  * Environment with all the needed stuff
102  */
103 typedef struct _be_raext_env_t {
104         arch_env_t *aenv;
105         const arch_register_class_t *cls;
106         ir_graph *irg;
107         dom_front_info_t *dom_info;
108
109         FILE *f;                                /**< file handle used for out- and input file */
110         set *vars;                              /**< contains all var_info_t */
111         int n_cls_vars;
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 */
115 } be_raext_env_t;
116
117
118
119 /******************************************************************************
120     _    _      _
121    | |  | |    | |
122    | |__| | ___| |_ __   ___ _ __ ___
123    |  __  |/ _ \ | '_ \ / _ \ '__/ __|
124    | |  | |  __/ | |_) |  __/ |  \__ \
125    |_|  |_|\___|_| .__/ \___|_|  |___/
126                  | |
127                  |_|
128  *****************************************************************************/
129
130
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))
133
134
135 /**
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.
139  */
140 #define is_res_in_reg_class(irn) arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls)
141
142
143 /**
144  * Checks if the irn uses or defines values of the
145  * current register class (raenv->cls)
146  */
147 static INLINE int is_sth_in_reg_class(be_raext_env_t *raenv, const ir_node *irn) {
148         int max, i;
149
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))
153                         return 1;
154
155         /* check result(s) */
156         if (get_irn_mode(irn) == mode_T) {
157                 ir_node *proj;
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))
160                                 return 1;
161                 return 0;
162         } else {
163                 return arch_irn_has_reg_class(raenv->aenv, irn, -1, raenv->cls);
164         }
165
166         assert(0 && "Where did you come from???");
167 }
168
169 /******************************************************************************
170      _____ _____              _____            _
171     / ____/ ____|  /\        |  __ \          | |
172    | (___| (___   /  \ ______| |  | | ___  ___| |_ _ __
173     \___ \\___ \ / /\ \______| |  | |/ _ \/ __| __| '__|
174     ____) |___) / ____ \     | |__| |  __/\__ \ |_| |
175    |_____/_____/_/    \_\    |_____/ \___||___/\__|_|
176
177  *****************************************************************************/
178
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)
181
182 /**
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.
186  *
187  * 1) Simplest case (phi with a non-phi arg):
188  *     A single copy is inserted.
189  *
190  * 2) Phi chain (phi (with phi-arg)* with non=phi arg):
191  *     Several copies are placed, each after returning from recursion.
192  *
193  * 3) Phi-loop:
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.
197  *
198  * The values of @p start_phi and @p pos never change during recursion.
199  *
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
204  *
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.
209  */
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;
215
216         assert(is_Phi(start_phi) && is_Phi(curr_phi));
217
218         if (has_been_done(start_phi, pos))
219                 return NULL;
220
221         /* In case this is a 'normal' phi we insert into
222          * the schedule before the pred_blk irn */
223         last_cpy = pred_blk;
224
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 */
230                         return NULL;
231                 }
232
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);
237
238                 arg = loop_breaker;
239         }
240
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);
244
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);
250         return curr_cpy;
251 }
252
253
254 /**
255  * Perform simple SSA-destruction with copies.
256  * The order of processing _must_ be
257  *  for all positions {
258  *    for all phis {
259  *      doit
260  *    }
261  *  }
262  * else the magic to keep track of processed phi-positions will fail in
263  * function 'insert_copies'
264  */
265 static void ssa_destr_simple_walker(ir_node *blk, void *env) {
266         be_raext_env_t *raenv = env;
267         int pos, max;
268         ir_node *phi;
269
270         /* for all argument positions of the phis */
271         for (pos=0, max=get_irn_arity(blk); pos<max; ++pos) {
272
273                 /* for all phi nodes (which are scheduled first) */
274                 sched_foreach(blk, phi) {
275                         if (!is_Phi(phi))
276                                 break;
277
278                         raenv->cls = arch_get_irn_reg_class(raenv->aenv, phi, -1);
279                         insert_copies(raenv, phi, pos, phi);
280                 }
281         }
282 }
283
284
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);
288 }
289
290
291 static void ssa_destr_rastello(be_raext_env_t *raenv) {
292         assert(0 && "NYI");
293         /* TODO
294         phi_class_compute(raenv->irg);
295         irg_block_walk_graph(irg, ssa_destr_rastello, NULL, &raenv);
296         */
297 }
298
299 /******************************************************************************
300    __      __   _       ___   __      __
301    \ \    / /  | |     |__ \  \ \    / /
302     \ \  / /_ _| |___     ) |  \ \  / /_ _ _ __ ___
303      \ \/ / _` | / __|   / /    \ \/ / _` | '__/ __|
304       \  / (_| | \__ \  / /_     \  / (_| | |  \__ \
305        \/ \__,_|_|___/ |____|     \/ \__,_|_|  |___/
306  *****************************************************************************/
307
308 /**
309  * This struct maps a variable (nr) to
310  *  1) the values belonging to this variable
311  *  2) the spills of this variable
312  */
313 struct _var_info_t {
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 */
319 };
320
321 /**
322  * The link field of an irn points to the var_info struct
323  * representing the corresponding variable.
324  */
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))
327
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)
331
332
333 #define HASH_VAR_NR(var_nr) var_nr
334
335
336
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;
340
341         return v1->var_nr != v2->var_nr;
342 }
343
344 static INLINE var_info_t *var_find(set *vars, int var_nr) {
345         var_info_t vi;
346         vi.var_nr = var_nr;
347
348         return set_find(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
349 }
350
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));
354         vi.var_nr = var_nr;
355
356         found = set_insert(vars, &vi, sizeof(vi), HASH_VAR_NR(var_nr));
357
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);
362         }
363
364         return found;
365 }
366
367 /**
368  * Adds a value to a variable. Sets all pointers accordingly.
369  */
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);
372
373         /* var 2 value mapping */
374         pset_insert_ptr(vi->values, irn);
375
376         /* value 2 var mapping */
377         set_var_info(irn, vi);
378
379         return vi;
380 }
381
382 /**
383  * Adds a spill to a variable. Sets all pointers accordingly.
384  */
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;
388
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!");
391
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 */
396
397         sched_add_before(before, spill);
398
399         /* the spill also points to the var_info of the spilled node */
400         set_var_info(spill, vi);
401
402         /* remember the spill */
403         pset_insert_ptr(vi->spills, spill);
404
405         return vi;
406 }
407
408 /**
409  * Adds a reload to a variable. Sets all pointers accordingly.
410  */
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;
414
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;
418
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);
424
425         sched_add_before(before, reload);
426
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);
430
431         /* remember the reload */
432         pset_insert_ptr(vi->reloads, reload);
433
434         return vi;
435 }
436
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");
440         return vi->values;
441 }
442
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");
446         return vi->spills;
447 }
448
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");
452         return vi->reloads;
453 }
454
455 /**
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
459  */
460 static void values_to_vars(ir_node *irn, void *env) {
461         be_raext_env_t *raenv = env;
462         ir_node *n;
463         int nr;
464         pset *vals;
465
466         vals = get_phi_class(irn);
467
468         if (!vals) {
469                 /* not a phi class member, value == var */
470                 vals = pset_new_ptr(1);
471                 pset_insert_ptr(vals, irn);
472         }
473
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);
479 }
480
481
482 /******************************************************************************
483     _____
484    |  __ \
485    | |  | |_   _ _ __ ___  _ __   ___ _ __
486    | |  | | | | | '_ ` _ \| '_ \ / _ \ '__|
487    | |__| | |_| | | | | | | |_) |  __/ |
488    |_____/ \__,_|_| |_| |_| .__/ \___|_|
489                           | |
490                           |_|
491  *****************************************************************************/
492
493
494 static INLINE ir_node *get_first_non_phi(pset *s) {
495         ir_node *irn;
496
497         pset_foreach(s, irn)
498                 if (!is_Phi(irn)) {
499                         pset_break(s);
500                         return irn;
501                 }
502
503         assert(0 && "There must be a non-phi-irn in this");
504         return NULL;
505 }
506
507 static void extract_vars_of_cls(be_raext_env_t *raenv) {
508         int count = 0;
509         set_entry *e;
510
511         raenv->cls_vars = malloc(set_count(raenv->vars) * sizeof(*raenv->cls_vars));
512         assert(raenv->cls_vars);
513
514         set_foreach(raenv->vars, e) {
515                 var_info_t *vi = (var_info_t *)e->dptr;
516
517                 if (is_res_in_reg_class(get_first_non_phi(vi->values)))
518                         raenv->cls_vars[count++] = vi;
519         }
520
521         raenv->cls_vars = realloc(raenv->cls_vars, count * sizeof(*raenv->cls_vars));
522         assert(raenv->cls_vars);
523
524         raenv->n_cls_vars = count;
525 }
526
527
528 /**
529  * Check if node irn has a limited-constraint at position pos.
530  * If yes, dump it to FILE raenv->f
531  */
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;
535
536         arch_get_register_req(raenv->aenv, &req, irn, pos);
537         if (arch_register_req_is(&req, limited)) {
538                 int reg_nr;
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");
543         }
544 }
545
546
547 static void dump_nodes(be_raext_env_t *raenv) {
548         FILE *f = raenv->f;
549         int i;
550
551         fprintf(f, "\nnodes {\n");
552
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);
556                 fprintf(f, "\n");
557         }
558
559         fprintf(f, "}\n");
560 }
561
562
563 static void dump_interferences(be_raext_env_t *raenv) {
564         int i,o;
565         var_info_t *vi1, *vi2;
566         ir_node *irn1, *irn2;
567         FILE *f = raenv->f;
568
569         fprintf(f, "\ninterferences {\n");
570
571         for (i=0; i<raenv->n_cls_vars; ++i) {
572                 vi1 = raenv->cls_vars[i];
573
574                 for (o=i+1; o<raenv->n_cls_vars; ++o) {
575                         vi2 = raenv->cls_vars[o];
576
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);
583                                         }
584                 }
585         }
586         fprintf(f, "}\n");
587 }
588
589
590 static void dump_affinities_walker(ir_node *irn, void *env) {
591         be_raext_env_t *raenv = env;
592
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);
597
598                 fprintf(raenv->f, "(%d %d)\n",  vi1->var_nr, vi2->var_nr);
599         }
600 }
601
602
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");
607 }
608
609 /**
610  * Dump all information needed by the external
611  * register allocator to a single file.
612  */
613 static void dump_to_file(be_raext_env_t *raenv, char *filename) {
614         FILE *f;
615
616         if (!(f = fopen(filename, "wt"))) {
617                 fprintf(stderr, "Could not open file %s for writing\n", filename);
618                 exit(0xdeadbeef);
619         }
620         raenv->f = f;
621
622         /* dump register info */
623         fprintf(f, "regs %d\n", arch_register_class_n_regs(raenv->cls));
624
625         /* dump the interference graph */
626         dump_nodes(raenv);
627         dump_interferences(raenv);
628         dump_affinities(raenv);
629
630         fclose(f);
631 }
632
633 /******************************************************************************
634     ______                     _
635    |  ____|                   | |
636    | |__  __  _____  ___ _   _| |_ ___
637    |  __| \ \/ / _ \/ __| | | | __/ _ \
638    | |____ >  <  __/ (__| |_| | ||  __/
639    |______/_/\_\___|\___|\__,_|\__\___|
640  *****************************************************************************/
641
642 /**
643  * Execute the external register allocator specified in the
644  * firm-option firm.be.ra.ext.callee
645  */
646 static void execute(char *prog_to_call, char *out_file, char *result_file) {
647         char cmd_line[1024];
648         int ret_status;
649
650         snprintf(cmd_line, sizeof(cmd_line), "%s %s %s", prog_to_call, out_file, result_file);
651
652         ret_status = system(cmd_line);
653         assert(ret_status != -1 && "Invokation of external register allocator failed");
654 }
655
656 /******************************************************************************
657                          _         _____                 _ _
658        /\               | |       |  __ \               | | |
659       /  \   _ __  _ __ | |_   _  | |__) |___  ___ _   _| | |_
660      / /\ \ | '_ \| '_ \| | | | | |  _  // _ \/ __| | | | | __|
661     / ____ \| |_) | |_) | | |_| | | | \ \  __/\__ \ |_| | | |_
662    /_/    \_\ .__/| .__/|_|\__, | |_|  \_\___||___/\__,_|_|\__|
663             | |   | |       __/ |
664             |_|   |_|      |___/
665  *****************************************************************************/
666
667 #define INVALID_FILE_FORMAT assert(0 && "Invalid file format.")
668
669 static INLINE int is_before(const char *s, size_t len) {
670         if (!strncmp(s, "before", len))
671                 return 1;
672         if (!strncmp(s, "after", len))
673                 return 0;
674         INVALID_FILE_FORMAT;
675         return -1;
676 }
677
678 static void fix_reloads(be_raext_env_t *raenv) {
679         var_info_t *vi;
680         set_foreach(raenv->vars, vi)
681                 be_introduce_copies_pset(raenv->dom_info, vi->spills);
682 }
683
684 /**
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.
688  */
689 static int read_and_apply_results(be_raext_env_t *raenv, char *filename) {
690         FILE *f;
691         var_info_t *vi;
692         int phase=0;
693
694         if (!(f = fopen(filename, "rt"))) {
695                 fprintf(stderr, "Could not open file %s for reading\n", filename);
696                 exit(0xdeadbeef);
697         }
698         raenv->f = f;
699
700         /* parse the file */
701         while (phase == 0) {
702                 int loc, var_use_ident, var_def_ident, pos;
703                 char where[16];
704
705                 /* handle a spill */
706                 if (fscanf(f, " spill %6s %d %d ", &where, &loc, &var_use_ident) == 3) {
707
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);
713
714                         var_add_spill(raenv, var_use_ident, anchor);
715                 }
716
717                 /* handle a reload */
718                 else if (fscanf(f, " reload %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
719
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);
725
726                         var_add_reload(raenv, var_use_ident, var_def_ident, anchor);
727                 }
728
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");
734
735                         to_change = pmap_get_sth(raenv->nodes, loc);
736                         assert(to_change && "insn-nr does not exist");
737
738                         new_arg = dom_up_search(vi->values, to_change);
739                         set_irn_n(to_change, pos, new_arg);
740                 }
741
742                 /* handle a copy insertion */
743                 else if (fscanf(f, " copy %s %d %d %d ", &where, &loc, &var_def_ident, &var_use_ident) == 4) {
744                         /* TODO
745                                 Ziel der Kopie ist Variable die bereits existiert
746                                 Ziel der Kopie ist eine neue Variable
747                         */
748                 }
749
750                 else
751                         phase++;
752         }
753
754         fix_reloads(raenv);
755
756         while (phase == 1) {
757                 int var_use_ident, reg_nr;
758
759                 /* assign register */
760                 if (fscanf(f, " assign %d %d ", &var_use_ident, &reg_nr) == 2) {
761                         pset *vals = get_var_values(raenv, var_use_ident);
762                         ir_node *irn;
763
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));
767                 }
768                 else
769                         phase++;
770         }
771
772         if (!feof(f))
773                 INVALID_FILE_FORMAT;
774
775         fclose(f);
776
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);
782         }
783 }
784
785 /******************************************************************************
786     __  __       _
787    |  \/  |     (_)
788    | \  / | __ _ _ _ __
789    | |\/| |/ _` | | '_ \
790    | |  | | (_| | | | | |
791    |_|  |_|\__,_|_|_| |_|
792  *****************************************************************************/
793
794 /**
795  * Default values for options
796  */
797 static void (*ssa_destr)(be_raext_env_t*) = ssa_destr_simple;
798 static char callee[128] = "echo";
799
800
801 /**
802  * Allocate registers with an external program using a text-file interface.
803  *
804  * Do some computations (SSA-destruction and mapping of values--vars)
805  * Write file
806  * Execute external program
807  * Read in results and apply them
808  *
809  */
810 static void be_ra_extern_main(const be_main_env_t *env, ir_graph *irg) {
811         be_raext_env_t raenv;
812         int clsnr, clss;
813
814         compute_doms(irg);
815
816         raenv.irg      = irg;
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();
821
822         /* Insert copies */
823
824         //TODO
825
826         /* SSA destruction */
827         ssa_destr(&raenv);
828
829         /* Mapping of SSA-Values <--> Variables */
830         phi_class_compute(irg);
831         be_clear_links(irg);
832         irg_walk_graph(irg, values_to_vars, NULL, &raenv);
833
834         dump_ir_block_graph_sched(irg, "-extern-ssadestr");
835
836         /* For all register classes */
837         for(clsnr = 0, clss = arch_isa_get_n_reg_class(raenv.aenv->isa); clsnr < clss; ++clsnr) {
838                 int done = 0;
839                 char out[256], in[256];
840
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);
844
845                 extract_vars_of_cls(&raenv);
846
847                 while (!done) {
848                         dump_to_file(&raenv, out);
849                         execute(callee, out, in);
850                         done = read_and_apply_results(&raenv, in);
851                 }
852
853                 free(raenv.cls_vars);
854         }
855
856         /* Clean up */
857         pmap_destroy(raenv.nodes);
858         del_set(raenv.vars);
859         be_free_dominance_frontiers(raenv.dom_info);
860
861 }
862
863 /******************************************************************************
864      ____        _   _
865     / __ \      | | (_)
866    | |  | |_ __ | |_ _  ___  _ __  ___
867    | |  | | '_ \| __| |/ _ \| '_ \/ __|
868    | |__| | |_) | |_| | (_) | | | \__ \
869     \____/| .__/ \__|_|\___/|_| |_|___/
870           | |
871           |_|
872  *****************************************************************************/
873
874 #ifdef WITH_LIBCORE
875
876 static const lc_opt_enum_const_ptr_items_t ssa_destr_items[] = {
877         { "simple",    ssa_destr_simple },
878         { "rastello",  ssa_destr_rastello },
879         { NULL,      NULL }
880 };
881
882 static lc_opt_enum_const_ptr_var_t ssa_destr_var = {
883         (const void **) &ssa_destr, ssa_destr_items
884 };
885
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)),
889         { NULL }
890 };
891
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");
894
895         lc_opt_add_table(grp, be_ra_extern_options);
896 }
897
898 #endif /* WITH_LIBCORE */
899
900 const be_ra_t be_ra_external_allocator = {
901 #ifdef WITH_LIBCORE
902         be_ra_extern_register_options,
903 #endif
904         be_ra_extern_main
905 };