Bugfixes
[libfirm] / ir / be / bespillilp.c
1 /**
2  * @file   bespillilp.c
3  * @date   15.07.2005
4  * @author Sebastian Hack
5  *
6  * ILP based spilling
7  *
8  * Copyright (C) 2005 Universitaet Karlsruhe
9  * Released under the GPL
10  */
11 #include <math.h>
12
13 #include "hashptr.h"
14 #include "debug.h"
15 #include "obst.h"
16 #include "set.h"
17 #include "list.h"
18 #include "pmap.h"
19
20 #include "irprintf.h"
21 #include "irgwalk.h"
22 #include "irnode_t.h"
23 #include "ircons_t.h"
24
25 #include <lpp/lpp.h>
26 #include <lpp/lpp_net.h>
27 #include <lpp/lpp_cplex.h>
28
29 #include "be_t.h"
30 #include "belive_t.h"
31 #include "besched_t.h"
32 #include "beirgmod.h"
33 #include "bearch.h"
34 #include "benode_t.h"
35 #include "beutil.h"
36
37 #define BIGM 1000.0
38
39 #define MAX(a,b) ((a) > (b) ? (a) : (b))
40
41 #define DBG_LEVEL SET_LEVEL_3
42
43 #undef DUMP_SOLUTION
44 #undef DUMP_ILP
45
46 #define LPP_SERVER "i44pc52"
47 #define LPP_SOLVER "cplex"
48
49 #define COST_LOAD      10
50 #define COST_STORE     50
51 #define COST_REMAT     (-9)
52
53 #define is_end_of_block_use(lr) (is_Block((lr)->user))
54
55 typedef struct _spill_ilp_t {
56   const be_main_session_env_t *session_env;
57   const arch_register_class_t *cls;
58         firm_dbg_module_t *dbg;
59   lpp_t *lpp;
60         set *irn_use_heads;
61   set *live_ranges;
62         set *spill_ctx;
63         pset *remove_phis;
64   struct obstack *obst;
65         int enable_store : 1;
66         int enable_remat : 1;
67 } spill_ilp_t;
68
69 typedef struct _live_range_t live_range_t;
70
71 typedef struct _irn_use_head_t {
72         struct list_head head;
73         ir_node *irn;
74         int spill_var;
75         int n_uses;
76         live_range_t *closest_use;
77 } irn_use_head_t;
78
79 struct _live_range_t {
80   struct list_head list;
81         irn_use_head_t *use_head;
82   ir_node *user;
83   ir_node *irn;
84         int pos;
85   int in_mem_var;
86   int is_remat_var;
87 };
88
89 typedef struct _spill_ctx_t {
90         ir_node *spilled;  /**< The spilled node. */
91         ir_node *user;     /**< The node this spill is for. */
92         ir_node *spill;    /**< The spill itself. */
93 } spill_ctx_t;
94
95 static int has_reg_class(const spill_ilp_t *si, const ir_node *irn)
96 {
97   return arch_irn_has_reg_class(si->session_env->main_env->arch_env,
98       irn, arch_pos_make_out(0), si->cls);
99 }
100
101 static int register_demand(spill_ilp_t *si, const ir_node *irn)
102 {
103         const arch_env_t *arch_env = si->session_env->main_env->arch_env;
104         int n_in = arch_get_n_operands(arch_env, irn, 0);
105         int n_out = arch_get_n_operands(arch_env, irn, -1);
106
107         return MAX(n_in, n_out);
108 }
109
110 static int cmp_spill_ctx(const void *a, const void *b, size_t n)
111 {
112         const spill_ctx_t *p = a;
113         const spill_ctx_t *q = b;
114   return !(p->user == q->user && p->spilled == q->spilled);
115 }
116
117 static int cmp_live_range(const void *a, const void *b, size_t n)
118 {
119   const live_range_t *p = a;
120   const live_range_t *q = b;
121
122   return !(p->user == q->user && p->irn == q->irn && p->pos == q->pos);
123 }
124
125 static int cmp_irn_use_head(const void *a, const void *b, size_t n)
126 {
127   const irn_use_head_t *p = a;
128   const irn_use_head_t *q = b;
129
130         return !(p->irn == q->irn);
131 }
132
133 /**
134  * Checks, if a vertain node can be recomputed at a certain position.
135  * @param si    The spill ILP environment.
136  * @param irn   The node to recompute.
137  * @param live  The nodes live at the place where @p irn shall be
138  *              recomputed.
139  * @return      1, if irn can be recomputed, 0 if not.
140  */
141 static INLINE int can_remat(const spill_ilp_t *si, const ir_node *irn, pset *live)
142 {
143         int i, n;
144   const arch_env_t *arch_env    = si->session_env->main_env->arch_env;
145         int remat = (arch_irn_get_flags(arch_env, irn) & arch_irn_flags_rematerializable) != 0;
146
147         for(i = 0, n = get_irn_arity(irn); i < n && remat; ++i) {
148                 ir_node *op = get_irn_n(irn, i);
149                 remat &= !has_reg_class(si, op) || pset_find_ptr(live, op);
150         }
151
152         return remat;
153 }
154
155 static spill_ctx_t *get_spill_ctx(spill_ilp_t *si, ir_node *spilled, ir_node *ctx_irn)
156 {
157         spill_ctx_t templ, *res;
158
159         templ.spilled = spilled;
160         templ.user    = ctx_irn;
161         templ.spill   = NULL;
162
163         res = set_insert(si->spill_ctx, &templ, sizeof(templ),
164                         HASH_COMBINE(HASH_PTR(spilled), HASH_PTR(ctx_irn)));
165
166         return res;
167 }
168
169 static live_range_t *get_live_range(spill_ilp_t *si, ir_node *irn, ir_node *user, int pos)
170 {
171   live_range_t lr, *res;
172         irn_use_head_t iuh, *head;
173         int is_new;
174   unsigned hash = HASH_COMBINE(HASH_PTR(irn), HASH_PTR(user));
175
176   lr.user    = user;
177   lr.irn     = irn;
178   lr.pos     = pos;
179   lr.in_mem_var = -1;
180         lr.is_remat_var = -1;
181
182   res = set_insert(si->live_ranges, &lr, sizeof(lr), hash);
183         is_new = res->in_mem_var == -1;
184
185   if(is_new) {
186     char buf[128];
187     ir_snprintf(buf, sizeof(buf), "m_%s%N_%N_%d",
188                                 is_Phi(irn) ? "phi_" : "", irn, user, MAX(pos, 0));
189     res->in_mem_var = lpp_add_var(si->lpp, buf, lpp_binary, pos >= 0 ? COST_LOAD : 0.0);
190   }
191
192         memset(&iuh, 0, sizeof(iuh));
193         iuh.irn = irn;
194         iuh.n_uses = -1;
195         head = set_insert(si->irn_use_heads, &iuh, sizeof(iuh), HASH_PTR(irn));
196         if(head->n_uses == -1) {
197                 head->n_uses = 0;
198                 INIT_LIST_HEAD(&head->head);
199         }
200
201         if(is_new) {
202                 list_add_tail(&res->list, &head->head);
203                 head->n_uses++;
204         }
205
206         res->use_head = head;
207
208   return res;
209 }
210
211 static live_range_t *lookup_live_range(const spill_ilp_t *si, ir_node *irn,
212                 ir_node *user, int pos)
213 {
214   live_range_t lr;
215   unsigned hash = HASH_COMBINE(HASH_PTR(irn), HASH_PTR(user));
216
217   lr.user    = user;
218   lr.irn     = irn;
219   lr.pos     = pos;
220   lr.in_mem_var = -1;
221
222   return set_find(si->live_ranges, &lr, sizeof(lr), hash);
223 }
224
225 static void create_block_live_range_sets(ir_node *bl, void *data)
226 {
227         assert(is_Block(bl));
228         set_irn_link(bl, pset_new_ptr_default());
229 }
230
231 static void delete_block_live_range_sets(ir_node *bl, void *data)
232 {
233         assert(is_Block(bl));
234
235         del_pset(get_irn_link(bl));
236         set_irn_link(bl, NULL);
237 }
238
239 #if 0
240 static void annotate_live_ranges(ir_node *irn, void *data)
241 {
242         const ir_edge_t *edge;
243
244         foreach_out_edge(irn, edge) {
245                 pset *lr_set;
246
247                 ir_node *user = edge->use;
248                 int pos       = edge->pos;
249                 ir_node *bl   = get_nodes_block(user);
250
251                 if(is_Phi(user))
252                         bl = get_Block_cfgpred_block(bl, pos);
253
254                 lr_set = get_irn_link(bl);
255
256         }
257 }
258 #endif
259
260
261 static void process_block(ir_node *bl, void *data)
262 {
263         char buf[128];
264         int i, n;
265   spill_ilp_t *si  = data;
266   int step         = 0;
267   int n_regs       = arch_register_class_n_regs(si->cls);
268         int n_preds      = get_irn_arity(bl);
269   pset *live       = pset_new_ptr_default();
270   irn_live_t *li;
271   ir_node *irn;
272
273   /* as always, bring the live end nodes to life here */
274   live_foreach(bl, li) {
275     if(live_is_end(li) && has_reg_class(si, li->irn)) {
276       ir_node *irn = (ir_node *) li->irn;
277       pset_insert_ptr(live, irn);
278
279       /*
280        * The "user" of the live range to the end of a block
281        * is the block itself. This is quite arbitrary.
282        */
283       set_irn_link(irn, get_live_range(si, irn, bl, -1));
284     }
285   }
286
287         sched_foreach_reverse(bl, irn) {
288                 ir_node *l;
289                 int cst;
290                 int demand;
291                 int n_live;
292                 int must_be_in_mem;
293
294                 /* We handle phi togther with live ins after this loop (see below). */
295                 if(is_Phi(irn))
296                         break;
297
298                 if(has_reg_class(si, irn))
299                         pset_remove_ptr(live, irn);
300
301                 demand = register_demand(si, irn);
302                 n_live = pset_count(live);
303
304                 /*
305                  * Determine, how many values (which are not used at the label)
306                  * must be in memory.
307                  * demand means the number of registers, the operation will consume.
308                  * So there are n_regs - demand registers available to store values
309                  * which are not used at this label. The rest must reside in memory.
310                  */
311                 must_be_in_mem = MAX(n_live - (n_regs - demand), 0);
312
313                 if(must_be_in_mem > 0) {
314
315                         /*
316                          * The constraint limiting the pressure at this label to
317                          * the number of free registers.
318                          */
319                         ir_snprintf(buf, sizeof(buf), "cp_%N_%d", bl, step);
320                         cst = lpp_add_cst(si->lpp, buf, lpp_greater, must_be_in_mem);
321
322                         for(l = pset_first(live); l; l = pset_next(live)) {
323                                 live_range_t *lr = get_irn_link(l);
324                                 lpp_set_factor_fast(si->lpp, cst, lr->in_mem_var, 1.0);
325                         }
326                 }
327
328                 for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
329                         ir_node *op = get_irn_n(irn, i);
330
331                         if(has_reg_class(si, op)) {
332                                 live_range_t *op_lr = get_live_range(si, op, irn, i);
333
334                                 set_irn_link(op, op_lr);
335
336                                 /*
337                                  * The operand is reloaded at its usage, so it must not occur
338                                  * in the constraint which determines which values live at the
339                                  * instruction must reside in memory.
340                                  */
341                                 if(must_be_in_mem > 0) {
342                                         lpp_set_factor_fast(si->lpp, cst, op_lr->in_mem_var, 0.0);
343                                 }
344
345                                 /*
346                                  * Check, if the node is a rematerializable node and
347                                  * if its operands are live here.
348                                  */
349                                 if(si->enable_remat && can_remat(si, op, live)) {
350                                         int cst;
351                                         int j, n;
352                                         int n_operands = 0;
353
354                                         for(j = 0, n = get_irn_arity(op); j < n; ++j)
355                                                 n_operands += has_reg_class(si, get_irn_n(op, j));
356
357                                         /* Make the remat constraint for this operand */
358                                         ir_snprintf(buf, sizeof(buf), "ce1_%N_%N_%d", op, irn, i);
359                                         cst = lpp_add_cst(si->lpp, buf, lpp_less, n_operands);
360
361                                         /* Make the rematerialize variable for the operand */
362                                         ir_snprintf(buf, sizeof(buf), "e_%N_%N_%d", op, irn, i);
363                                         op_lr->is_remat_var = lpp_add_var(si->lpp, buf, lpp_binary, COST_REMAT);
364                                         lpp_set_factor_fast(si->lpp, cst, op_lr->is_remat_var, n_operands);
365
366                                         for(j = 0, n = get_irn_arity(op); j < n; ++j) {
367                                                 ir_node *oop = get_irn_n(op, j);
368                                                 if(has_reg_class(si, oop)) {
369                                                         live_range_t *lr = get_irn_link(oop);
370                                                         lpp_set_factor_fast(si->lpp, cst, lr->in_mem_var, 1.0);
371                                                 }
372                                         }
373
374                                         ir_snprintf(buf, sizeof(buf), "ce2_%N_%N_%d", op, irn, i);
375                                         cst = lpp_add_cst(si->lpp, buf, lpp_less, 0.0);
376                                         lpp_set_factor_fast(si->lpp, cst, op_lr->is_remat_var, 1.0);
377                                         lpp_set_factor_fast(si->lpp, cst, op_lr->in_mem_var, -1.0);
378                                 }
379                         }
380                 }
381
382                         for(i = 0, n = get_irn_arity(irn); i < n; ++i) {
383                                 ir_node *op = get_irn_n(irn, i);
384                                 if(has_reg_class(si, op) && !is_Phi(irn))
385                                         pset_insert_ptr(live, op);
386                         }
387
388                 step++;
389         }
390
391         if(bl == get_irg_start_block(get_irn_irg(bl)))
392                 goto end;
393
394         /*
395          * Here, only the phis in the block and the values live in are in the
396          * live set.
397          *
398          * If a value is live in, it must be in a register in all predecessor
399          * blocks or in memory at the end of all predecessor blocks. Also, the
400          * closest use in the current block must then be from register or
401          * memory, respectively.
402          */
403         for(irn = pset_first(live); irn; irn = pset_next(live)) {
404                 live_range_t *lr = get_irn_link(irn);
405                 int is_phi = is_Phi(irn) && get_nodes_block(irn) == bl;
406                 int cst;
407
408                 if(is_phi)
409                         lr->use_head->closest_use = lr;
410
411                 assert(has_reg_class(si, irn));
412                 assert(is_Phi(irn) || is_live_in(bl, irn));
413
414 #if 0
415                 ir_snprintf(buf, sizeof(buf), "c%s_%N_%N", (is_phi ? "phi" : "li"), irn, bl);
416                 cst = lpp_add_cst(si->lpp, buf, lpp_equal, 0.0);
417                 lpp_set_factor_fast(si->lpp, cst, lr->in_mem_var, -n_preds);
418
419                 for(i = 0; i < n_preds; ++i) {
420                         ir_node *pred_bl     = get_Block_cfgpred_block(bl, i);
421                         ir_node *end_node    = is_phi ? get_irn_n(irn, i) : irn;
422                         live_range_t *op_lr  = get_live_range(si, end_node, pred_bl, -1);
423
424                         lpp_set_factor_fast(si->lpp, cst, op_lr->in_mem_var, 1.0);
425                 }
426 #endif
427
428                 for(i = 0; i < n_preds; ++i) {
429                         ir_node *pred_bl     = get_Block_cfgpred_block(bl, i);
430                         ir_node *end_node    = is_phi ? get_irn_n(irn, i) : irn;
431                         live_range_t *op_lr  = get_live_range(si, end_node, pred_bl, -1);
432
433                         ir_snprintf(buf, sizeof(buf), "cpred_%N_%N_%d", lr->irn, bl, i);
434                         cst = lpp_add_cst(si->lpp, buf, lpp_equal, 0.0);
435                         lpp_set_factor_fast(si->lpp, cst, op_lr->in_mem_var, 1.0);
436                         lpp_set_factor_fast(si->lpp, cst, lr->in_mem_var, -1.0);
437                 }
438         }
439
440 end:
441
442   del_pset(live);
443 }
444
445 /**
446  * Add the costs for a store.
447  *
448  * If one of the uses is from memory, add additional costs for the
449  * spill.
450  *
451  * m_1 + ... + m_n - M * s <= 0
452  *
453  * @param si The ILP spilling environment.
454  */
455 static void add_store_costs(spill_ilp_t *si)
456 {
457         char buf[64];
458         irn_use_head_t *uh;
459         double costs = si->enable_store ? COST_STORE : 0.0;
460
461         for(uh = set_first(si->irn_use_heads); uh; uh = set_next(si->irn_use_heads)) {
462                 int cst;
463                 live_range_t *lr;
464
465                 ir_snprintf(buf, sizeof(buf), "cs_%N", uh->irn);
466                 cst = lpp_add_cst(si->lpp, buf, lpp_less, 0);
467
468                 ir_snprintf(buf, sizeof(buf), "s_%N", uh->irn);
469                 uh->spill_var = lpp_add_var(si->lpp, buf, lpp_binary, costs);
470                 lpp_set_factor_fast(si->lpp, cst, uh->spill_var, -BIGM);
471
472     list_for_each_entry(live_range_t, lr, &uh->head, list)
473                         lpp_set_factor_fast(si->lpp, cst, lr->in_mem_var, 1.0);
474         }
475 }
476
477 static INLINE int is_zero(double x)
478 {
479   return fabs(x) < 0.00001;
480 }
481
482 static int is_spilled(const spill_ilp_t *si, const live_range_t *lr)
483 {
484         return !is_zero(lpp_get_var_sol(si->lpp, lr->in_mem_var));
485 }
486
487 static ir_node *spill_irn(spill_ilp_t *si, ir_node *irn, ir_node *ctx_irn)
488 {
489   const be_node_factory_t *fact = si->session_env->main_env->node_factory;
490   const arch_env_t *arch_env    = si->session_env->main_env->arch_env;
491         spill_ctx_t *ctx;
492
493         ctx = get_spill_ctx(si, irn, ctx_irn);
494         if(ctx->spill)
495                 return ctx->spill;
496
497         ctx->spill = be_spill(fact, arch_env, irn);
498         return ctx->spill;
499 }
500
501 static ir_node *spill_phi(spill_ilp_t *si, ir_node *phi, ir_node *ctx_irn, pset *rem_phis)
502 {
503         int i, n;
504         ir_mode *mode = get_irn_mode(phi);
505         ir_node **ins;
506         ir_node *bl = get_nodes_block(phi);
507         ir_graph *irg = get_irn_irg(bl);
508         spill_ctx_t *ctx;
509
510         assert(is_Phi(phi));
511
512         ctx = get_spill_ctx(si, phi, ctx_irn);
513         if(ctx->spill)
514                 return ctx->spill;
515
516         n    = get_irn_arity(phi);
517         ins  = malloc(n * sizeof(ins[0]));
518
519         for(i = 0; i < n; ++i)
520                 ins[i]  = new_r_Unknown(irg, mode_M);
521
522         ctx->spill = new_r_Phi(irg, bl, n, ins, mode_M);
523         free(ins);
524
525         for(i = 0; i < n; ++i) {
526                 ir_node *arg = get_irn_n(phi, i);
527                 ir_node *res;
528
529                 if(is_Phi(arg))
530                         res = spill_phi(si, arg, ctx_irn, rem_phis);
531                 else
532                         res = spill_irn(si, arg, ctx_irn);
533
534                 set_irn_n(ctx->spill, i, res);
535         }
536
537         return ctx->spill;
538 }
539
540 static ir_node *spill_live_range(spill_ilp_t *si, live_range_t *lr, pset *rem_phis)
541 {
542         const live_range_t *closest = lr->use_head->closest_use;
543
544         if(is_Phi(lr->irn) && closest && is_spilled(si, closest))
545                 return spill_phi(si, lr->irn, lr->irn, rem_phis);
546         else
547                 return spill_irn(si, lr->irn, lr->irn);
548 }
549
550
551 static void writeback_results(spill_ilp_t *si)
552 {
553   const be_node_factory_t *fact = si->session_env->main_env->node_factory;
554   const arch_env_t *arch_env    = si->session_env->main_env->arch_env;
555         ir_node *irn;
556         irn_use_head_t *uh;
557         pset *rem_phis = pset_new_ptr_default();
558
559         for(uh = set_first(si->irn_use_heads); uh; uh = set_next(si->irn_use_heads)) {
560                 if(is_Phi(uh->irn) && is_spilled(si, uh->closest_use))
561                         pset_insert_ptr(rem_phis, uh->irn);
562         }
563
564         /* Look at each node and examine the usages. */
565         for(uh = set_first(si->irn_use_heads); uh; uh = set_next(si->irn_use_heads)) {
566     live_range_t *lr;
567     ir_node **reloads;
568
569     int n_reloads           = 0;
570     ir_node *irn            = uh->irn;
571                 ir_mode *mode           = get_irn_mode(irn);
572
573                 /* Go through all live ranges of the node. */
574     list_for_each_entry(live_range_t, lr, &uh->head, list) {
575       int spilled = is_spilled(si, lr);
576                         // int rematd  = !is_zero(lpp_get_var_sol(si->lpp, lr->is_remat_var));
577
578                         if(spilled && !is_end_of_block_use(lr)) {
579                                 ir_node *bl      = get_nodes_block(lr->user);
580                                 ir_node *spill   = spill_live_range(si, lr, rem_phis);
581                                 ir_node *reload  = new_Reload(fact, si->cls,
582                                                 si->session_env->irg, bl, mode, spill);
583
584                                 obstack_ptr_grow(si->obst, reload);
585                                 n_reloads++;
586
587                                 sched_add_before(lr->user, reload);
588                         }
589
590     }
591
592                 if(n_reloads > 0) {
593                         reloads = obstack_finish(si->obst);
594                         be_introduce_copies_ignore(si->session_env->dom_front, irn,
595                                         n_reloads, reloads, rem_phis);
596                         obstack_free(si->obst, reloads);
597                 }
598   }
599
600         for(irn = pset_first(rem_phis); irn; irn = pset_next(rem_phis)) {
601                 int i, n;
602
603                 for(i = 0, n = get_irn_arity(irn); i < n; ++i)
604                         set_irn_n(irn, i, new_r_Bad(si->session_env->irg));
605                 sched_remove(irn);
606         }
607 }
608
609 void be_spill_ilp(const be_main_session_env_t *session_env,
610     const arch_register_class_t *cls)
611 {
612         char buf[256];
613         char problem_name[256];
614   struct obstack obst;
615   spill_ilp_t si;
616
617         ir_snprintf(problem_name, sizeof(problem_name), "%F_%s", session_env->irg, cls->name);
618
619   obstack_init(&obst);
620   si.obst           = &obst;
621         si.dbg            = firm_dbg_register("be.ra.spillilp");
622   si.session_env    = session_env;
623   si.cls            = cls;
624   si.lpp            = new_lpp(problem_name, lpp_minimize);
625   si.irn_use_heads  = new_set(cmp_irn_use_head, 4096);
626   si.live_ranges    = new_set(cmp_live_range, 16384);
627   si.spill_ctx      = new_set(cmp_spill_ctx, 4096);
628         si.enable_remat   = 1;
629         si.enable_store   = 0;
630
631         firm_dbg_set_mask(si.dbg, DBG_LEVEL);
632         irg_block_walk_graph(session_env->irg, process_block, NULL, &si);
633         if(si.enable_store)
634                 add_store_costs(&si);
635
636 #ifdef DUMP_ILP
637         {
638                 FILE *f;
639
640                 ir_snprintf(buf, sizeof(buf), "spill-%s.ilp", problem_name);
641                 if((f = fopen(buf, "wt")) != NULL) {
642                         lpp_dump_plain(si.lpp, f);
643                         fclose(f);
644                 }
645         }
646 #endif
647
648         DBG((si.dbg, LEVEL_1, "%F\n", session_env->irg));
649 //      lpp_solve_net(si.lpp, LPP_SERVER, LPP_SOLVER);
650         lpp_solve_cplex(si.lpp);
651         assert(lpp_is_sol_valid(si.lpp) && "ILP not feasible");
652
653         assert(lpp_is_sol_valid(si.lpp) && "solution of ILP must be valid");
654
655         DBG((si.dbg, LEVEL_1, "\tnodes: %d, vars: %d, csts: %d\n",
656                                 set_count(si.irn_use_heads), si.lpp->var_next, si.lpp->cst_next));
657         DBG((si.dbg, LEVEL_1, "\titerations: %d, solution time: %g\n",
658                                 si.lpp->iterations, si.lpp->sol_time));
659
660 #ifdef DUMP_SOLUTION
661         {
662                 FILE *f;
663
664                 ir_snprintf(buf, sizeof(buf), "spill-%s.sol", problem_name);
665                 if((f = fopen(buf, "wt")) != NULL) {
666                         int i;
667                         for(i = 0; i < si.lpp->var_next; ++i) {
668                                 lpp_name_t *name = si.lpp->vars[i];
669                                 fprintf(f, "%10s %4d %10f\n", name->name, name->nr, name->value);
670                         }
671                         fclose(f);
672                 }
673         }
674 #endif
675   writeback_results(&si);
676
677   del_set(si.irn_use_heads);
678   del_set(si.live_ranges);
679   free_lpp(si.lpp);
680   obstack_free(&obst, NULL);
681 }