1 /************************************************************************
2 * Program: Search_tree.c
3 * Project: SIMD optimization
4 * Function: Provides functions to build a search tree to
5 * select the patterns for rewrite
6 * Author: Andreas Schoesser
8 ************************************************************************/
17 #include "grs/match.h"
19 #include "simd_presets.h"
20 #include "search_tree_t.h"
21 #include "firm_node_ext.h"
24 struct pmap *applied_nodes;
25 static int st_number = 0;
28 /************************************************************************
29 * Builds a search tree
30 * TODO: Check if a match is valid, only then insert a search tree node,
31 * but insert it into the ignore list
32 ************************************************************************/
34 search_tree_node_t *build_search_tree(search_tree_env_t *search_tree_env, int prio_start)
35 //void build_search_tree(search_tree_env_t *search_tree_env)//, int struct pmap *vec_operations, struct pmap *keep_nodes, int start, statistics_t *statistics, struct pmap *replaced_ptrs)
37 plist_t **ignored_matches = alloca(search_tree_env->num_rules * sizeof(plist_t *));
38 search_tree_node_t *root;
40 char st_filename[255];
42 applied_nodes = pmap_create();
44 printf("\n\nBuilding search tree for priority %d:\n\n", search_tree_env->priorities[1]);
47 // Create "list of matches to ignore" for each rule type
48 for(i = 0; i < search_tree_env->num_rules; i++)
49 ignored_matches[i] = plist_new();
51 root = rec_search_patterns(search_tree_env, search_tree_env->priorities[1], ignored_matches);
53 // Free "list of matches to ignore" for each rule type
54 for(i = 0; i < search_tree_env->num_rules; i++)
56 plist_clear(ignored_matches[i]);
57 plist_free(ignored_matches[i]);
61 sprintf(st_filename, "%s-searchtree-%d.vcg", get_entity_name(get_irg_entity(search_tree_env->irg)), st_number++);
62 dump_search_tree(root, st_filename, "testtree", search_tree_env);
69 pmap_destroy(applied_nodes);
76 /************************************************************************
77 * Frees the memory occupied by the search tree data structure
78 * Params: root: The root node of the search tree
79 ************************************************************************/
81 void destroy_search_tree(search_tree_node_t *root)
84 if(root->memory_preds != NULL)
85 pmap_destroy(root->memory_preds);
87 // Free the match and free subsequent search nodes recursively
88 if(root->match != NULL)
90 destroy_search_tree(root->with);
91 destroy_search_tree(root->without);
92 ext_grs_free_match(root->match);
95 // Free the current search tree node itself
101 /************************************************************************
102 * Searches patterns recursively and tests what costs appear when
103 * the pattern we found would be applied or not.
104 ************************************************************************/
106 static search_tree_node_t *rec_search_patterns(search_tree_env_t *st_env, int prio, plist_t **ignored_matches)
108 int i, j, *prio_pos = st_env->priorities;
110 // Search all patterns in this priority
111 search_tree_node_t *st_node = malloc(sizeof(*st_node));
113 memset(st_node, 0, sizeof(*st_node));
115 for(; prio_pos[1] == prio; ) // TODO! Nach oben begrenzen!
117 int rule_nr = prio_pos[0];
118 ext_grs_match_t *match;
121 printf("\nSearching pattern %s (%d).", st_env->firmnode_names[rule_nr], rule_nr);
125 match = ext_grs_match(st_env->irg, st_env->m_plans[rule_nr], ext_grs_ALL, ext_grs_REGARDLESS);
126 assert(match != NULL && "Panic! No memory for match!");
127 st_env->statistics->num_matches += ext_grs_get_n_matches(match);
128 st_env->statistics->num_matched_nodes += ext_grs_get_n_matches(match) * ext_grs_get_match_max_node_aiid(match);
130 // Now find the first one not to be ignored;
131 for(i = 0; i < ext_grs_get_n_matches(match); i++)
133 if(!ignore_match(match, i, ignored_matches, rule_nr))
135 // Insert this match into ignore list
136 plist_element_t *inserted_match = add_ignored_match(match, i, ignored_matches, rule_nr);
137 plist_t *undo_vproj_info;
141 printf(" Found! %p", st_node);
144 // ** First look if we're allowed to apply the match **
145 // Look if the arguments are in dominating blocks
147 if((aa = analyze_arguments(st_env->rules[rule_nr], match, i, st_env->irg, NULL)) < 0)
152 printf(" Invalid arguments.");
154 printf(" Argument dependency.");
160 // Find the memory predecessors to be able to schedule the complex operation
161 st_node->memory_preds = find_memory_preds(st_env->irg, ext_grs_get_match_node_map(match, i), st_env->rules[rule_nr]->max_node_aiid);
163 // Do alias analysis and "LOAD usage" analysis" to see if pattern is really appliable.
164 if(test_alias_relation(match->nodes[i], match->max_node_id, st_node->memory_preds, st_env->replaced_ptrs) != 0)
167 printf(" Rejected: Alias conflict!");
173 // Arriving here means we're allowed to apply the match. Save information and look for
174 // following matches with or without the current match.
175 st_node->match = match;
176 st_node->which_match = i;
177 st_node->rule_nr = rule_nr;
180 st_node->without = rec_search_patterns(st_env, prio, ignored_matches);
182 // Delete this pattern from the ignored ones
183 delete_ignored_match(ignored_matches, inserted_match, rule_nr);
186 // Insert vProj nodes
187 undo_vproj_info = construct_vproj(st_env, st_node, rule_nr);
189 // call again recursively
191 printf("\nApplying %p ", st_node);
193 insert_inner_nodes(st_env, st_node);
194 st_node->with = rec_search_patterns(st_env, prio, ignored_matches);
195 remove_inner_nodes(st_env, st_node);
197 printf("\nFinished Applying %p\n", st_node);
200 // Destroy VProj nodes
201 deconstruct_vproj(undo_vproj_info);
204 // Build the search tree node for this match
206 st_node->this_matchs_costsavings = st_env->cost_savings[rule_nr] - ext_result_costs(st_node->match, st_node->which_match);
207 st_node->cost_savings = MAX((st_node->without->cost_savings), (st_node->with->cost_savings + st_node->this_matchs_costsavings));
221 (_) __ _ _ __ ___ _ __ ___ __| | _ __ ___ __| | ___ ___
222 | |/ _` | '_ \ / _ \| '__/ _ \/ _` | | '_ \ / _ \ / _` |/ _ \/ __|
223 | | (_| | | | | (_) | | | __/ (_| | | | | | (_) | (_| | __/\__ \
224 |_|\__, |_| |_|\___/|_| \___|\__,_| |_| |_|\___/ \__,_|\___||___/
228 /************************************************************************
229 * Adds a certain match to the list of ignored matches
230 * Prarms: match: The match object to be inserted
231 * which: The match number inside the match object to be inserted
232 * ignored_matches: Array of list of matches to be ignored
233 * rule_nr: The rule which found the match
234 * Returns: List element containing the ignored match
235 ************************************************************************/
237 static plist_element_t *add_ignored_match(ext_grs_match_t *match, int which, plist_t **ignored_matches, int rule_nr)
239 ignored_match_t *imatch = malloc(sizeof(*imatch));
240 //memset(imatch, 0, sizeof(*imatch));
242 imatch->nodes = generate_nodemap_hash(ext_grs_get_match_node_map(match, which), ext_grs_get_match_max_node_aiid(match));
243 // imatch->edges = ext_grs_get_match_edge_map(match, which);
245 plist_insert_back(ignored_matches[rule_nr], imatch);
246 return(plist_last(ignored_matches[rule_nr]));
251 /************************************************************************
252 * Removes a certain match to the list of ignored matches
253 * Params: ignored_matches: List of matches to be ignored
254 * match_to_delete: List element of ignored_matches to be deleted
255 ************************************************************************/
257 static void delete_ignored_match(plist_t **ignored_matches, plist_element_t *match_to_delete, int rule_nr)
259 ignored_match_t *imatch = match_to_delete->data;
260 pmap_destroy(imatch->nodes);
262 plist_erase(ignored_matches[rule_nr], match_to_delete);
267 /************************************************************************
268 * Test, if a certain match is in the ignore list
269 * Returns: 0 if the match is not in the list
270 * 1 if the match has to be ignored
271 * Prarms: match: The match object to be tested
272 * which: The match number inside the match object to be tested
273 * ignored_matches: Array of list of matches to be ignored
274 * rule_nr: The rule which found the match
275 ************************************************************************/
277 static int ignore_match(ext_grs_match_t *match, int which, plist_t **ignored_matches, int rule_nr)
281 pmap_entry *pen = NULL;
282 ir_node **node_map = ext_grs_get_match_node_map(match, which);
283 ir_edge_t **edge_map = ext_grs_get_match_edge_map(match, which);
284 int max_aiid = ext_grs_get_match_max_node_aiid(match);
286 // Iterate over all matches to be ignored of rule type "rule_nr"
287 foreach_plist(ignored_matches[rule_nr], el)
289 ignored_match_t *imatch = (ignored_match_t *) el->data;
292 for(j = 0; j <= max_aiid; j++)
293 // if((pen = pmap_get(imatch->nodes, node_map[j])) == NULL) /// HAEEE? Why does this not work????
294 if(!pmap_contains(imatch->nodes, node_map[j]))
296 difference = 1; // We have a difference. Proceed with next saved match
303 printf(" Ignoring: Already matched in %p", pen);
305 return(1); // There is no difference beetween the two, that means we found 2 identical matches
309 // Now look if match's nodes don't collide with inner nodes of already applied matches
310 for(j = 0; j <= max_aiid; j++)
311 if((pen = pmap_get(applied_nodes, node_map[j])) != 0)
314 printf(" Overlapping with %p", pen);
324 /************************************************************************
325 * Insert inner nodes of an applied pattern into a global pmap
326 ************************************************************************/
328 void insert_inner_nodes(search_tree_env_t *st_env, search_tree_node_t *st_node)
330 ir_node **nodes = ext_grs_get_match_node_map(st_node->match, st_node->which_match);
331 int max_id = ext_grs_get_match_max_node_aiid(st_node->match, st_node->which_match);
333 ext_grs_node_t **act_nodes = st_node->match->action->nodes;
334 int len = strlen(VECTOR_RESULT_NAME);
336 for(i = 0; i < max_id; i++)
338 // Ignore Agrument nodes of the pattern
339 if(act_nodes[i]->op == op_IrNode) // Generic argument nodes
341 if(strncmp(act_nodes[i]->name, "Arg_", 4) == 0) // explicit argument nodes, that is Vector Base
343 if(get_irn_opcode(nodes[i]) == iro_Const)
345 if(get_irn_opcode(nodes[i]) == iro_VProj)
347 if(get_irn_opcode(nodes[i]) == iro_Block)
349 pmap_insert(applied_nodes, nodes[i], (void *) st_node); // Annotate which node produced that node
355 /************************************************************************
357 ************************************************************************/
359 void remove_inner_nodes(search_tree_env_t *st_env, search_tree_node_t *st_node)
361 ir_node **nodes = ext_grs_get_match_node_map(st_node->match, st_node->which_match);
362 int max_id = ext_grs_get_match_max_node_aiid(st_node->match, st_node->which_match);
365 for(i = 0; i < max_id; i++)
366 if(pmap_contains(applied_nodes, nodes[i]))
367 pmap_insert(applied_nodes, nodes[i], 0); // Ugly, can't remove from pmap!
373 |_ _|_ __ ___ ___ _ __| |_ \ \ / / _ \ _ __ ___ (_)
374 | || '_ \/ __|/ _ \ '__| __| \ \ / /| |_) | '__/ _ \| |
375 | || | | \__ \ __/ | | |_ \ V / | __/| | | (_) | |
376 |___|_| |_|___/\___|_| \__| \_/ |_| |_| \___// |
379 /************************************************************************
380 * Insert "artificial" VProj and Complex Instruction nodes
381 * Annotate at these nodes which match "created" them.
382 ************************************************************************/
384 static plist_t *construct_vproj(search_tree_env_t *st_env, search_tree_node_t *st_node, int rule_nr)
387 int result_nr = 0, result_aiid;
388 plist_t *undo_info = plist_new();
389 ext_grs_match_t *match = st_node->match;
390 int which = st_node->which_match;
392 // Find out if the match has VProj results and how many
393 // This is done by looking for the node names Result_0_... - Result_n_...
394 // The right node names have to be created by the pattern creator before!
396 sprintf(node_name, "%s%d", VECTOR_RESULT_NAME, result_nr);
397 if((result_aiid = ext_grs_act_get_node_aiid_n(st_env->rules[rule_nr], node_name, strlen(node_name))) >= 0)
398 { // Yes, it has vector results
399 ir_node **nodes = ext_grs_get_match_node_map(match, which);
400 ir_node *ins[1], *dataproj, *block, *complex;
403 block = get_nodes_block(nodes[result_aiid]);
405 // Insert artificial complex instruction
407 pmap_foreach(st_node->memory_preds, pen)
409 ins[0] = get_irn_n(pen->key, 0); //(pen->key);
410 pmap_break(st_node->memory_preds);
412 complex = new_ir_node(NULL, st_env->irg, block, op_FakeComplex, mode_T, (ins[0] == NULL) ? 0 : 1, &ins[0]);
414 dataproj = new_ir_node_with_update(NULL, st_env->irg, block, op_Proj, mode_LLu, 1, ins);
415 insert_which_match_vproj(st_env, dataproj, st_node->match, st_node->which_match, -1);
418 // Insert the VProjs, connect them with the complex instruction node
421 ir_node *result_node = nodes[result_aiid];
423 ir_edge_t *res_succ, **outs;
425 undo_vproj_t *undo_vproj = malloc(sizeof(*undo_vproj));
427 // Create a new VProj node
428 new_vproj = new_ir_node_with_update(NULL, st_env->irg, get_nodes_block(result_node), op_VProj, get_irn_mode(result_node), 1, ins);
429 set_VProj_proj(new_vproj, result_nr);
431 // Save undo info for that VProj node
432 undo_vproj -> vproj_node = new_vproj;
433 undo_vproj -> org_result = result_node;
434 plist_insert_back(undo_info, undo_vproj);
436 // Save for each VProj, which match "created" them
437 //pmap_insert(st_env->which_match_vproj, new_vproj, st_node);
438 insert_which_match_vproj(st_env, new_vproj, st_node->match, st_node->which_match, result_aiid);
440 // Now connect the result's successors to the Vproj, remember the old connections
441 n_edges = get_irn_n_edges(result_node);
442 NEW_ARR_A(ir_edge_t *, outs, n_edges);
444 foreach_out_edge(result_node, res_succ)
447 outs[i++] = res_succ;
450 for(i = 0; i < n_edges; i++)
453 set_irn_n(outs[i]->src, outs[i]->pos, new_vproj);
457 // Search the next node.
458 sprintf(node_name, "%s%d", VECTOR_RESULT_NAME, ++result_nr);
459 } while((result_aiid = ext_grs_act_get_node_aiid_n(st_env->rules[rule_nr], node_name, strlen(node_name))) >= 0);
462 //dump_ir_block_graph(st_env->irg, "inserted_vproj");
470 /************************************************************************
471 * Connects the successors of the inserted VProjs with their original
472 * arguments again. Does NOT erase the VProj nodes from the graph,
473 * they are still needed.
474 * Frees the undo info
475 ************************************************************************/
477 static void deconstruct_vproj(plist_t *undo_vproj_info)
481 // Undo every VProj inserted
482 foreach_plist(undo_vproj_info, el)
484 undo_vproj_t *undo_vproj = el->data;
485 ir_edge_t **outs, *vproj_succ;
488 assert(get_irn_opcode(undo_vproj->vproj_node) == iro_VProj);
491 n_edges = get_irn_n_edges(undo_vproj->vproj_node);
492 NEW_ARR_A(ir_edge_t *, outs, n_edges);
493 foreach_out_edge(undo_vproj->vproj_node, vproj_succ)
496 outs[i++] = vproj_succ;
500 for(i = 0; i < n_edges; i++)
501 set_irn_n(outs[i]->src, outs[i]->pos, undo_vproj->org_result);
503 // TODO!! Remove VProjs from matchers nodes list!
510 plist_clear(undo_vproj_info);
511 plist_free(undo_vproj_info);
516 /************************************************************************
517 * Creates an entry in the which_match_vproj pmap to indicate
518 * which match created which vproj node and where to find the
519 * the REAL vproj node that was created by the replacement
520 ************************************************************************/
522 static void insert_which_match_vproj(search_tree_env_t *st_env, ir_node *vproj, ext_grs_match_t *match, int which, int aiid)
524 which_match_vproj_t *wmv = obstack_alloc(st_env->obst, sizeof(*wmv));
530 pmap_insert(st_env->which_match_vproj, vproj, wmv);
535 _ __ ___ _ __ | | __ _ ___ ___ _ __ ___ ___ _ __ | |_
536 | '__/ _ \ '_ \| |/ _` |/ __/ _ \ '_ ` _ \ / _ \ '_ \| __|
537 | | | __/ |_) | | (_| | (_| __/ | | | | | __/ | | | |_
538 |_| \___| .__/|_|\__,_|\___\___|_| |_| |_|\___|_| |_|\__|
541 /************************************************************************
542 * Walk over search tree
543 * Replace those patterns with the greates saving of costs
544 * Params: root: root of the search tree
545 ************************************************************************/
547 void replace_search_tree(search_tree_node_t *root, replace_st_env_t *rep_env)
549 char force_apply, suggestion;
551 if(root->match == NULL)
555 suggestion = ((root->without->cost_savings) > (root->with->cost_savings + root->this_matchs_costsavings)) ? 'n' : 'y';
556 printf("\nApply RULE %s? Suggested: %c (y/n): ", rep_env->firmnode_names[root->rule_nr], suggestion);
558 force_apply = getch();
563 #if VERBOSE_REWRITE && PROMPT_REWRITE
564 if(force_apply == 'n' || force_apply == 'N') // User driven
566 if((root->without->cost_savings) >= (root->with->cost_savings + root->this_matchs_costsavings)) // Cost driven
572 // Go on with the "not replaced" edge
573 replace_search_tree(root->without, rep_env);
578 char match_postfix[100];
584 // Manipulate the match to use the VProjs of its predecessor
585 manipulate_match(rep_env, root->match, root->which_match);
588 which[0] = root->which_match;
589 ext_grs_finish_match(root->match, 1, &which[0]);
591 connect_complex_memory(rep_env->rules[root->rule_nr], root->match, root->which_match, root->memory_preds);
592 save_complex_operation(rep_env->rules[root->rule_nr], root->match, root->which_match, rep_env->vec_operations, root->rule_nr);
593 save_keep_nodes(rep_env->rules[root->rule_nr], root->match, root->which_match, rep_env->keep_nodes);
594 set_complex_operation_block(rep_env->irg, root->match, root->which_match);
596 //sprintf(match_postfix, "-REWRITTEN-%d-%d", i, j);
597 //dump_ir_block_graph(irg, match_postfix);
598 rep_env->statistics -> num_instructions_inserted++;
599 rep_env->statistics -> num_replaced_nodes += root->match->n_nodes;
600 rep_env->statistics -> rewritten_patterns[root->rule_nr]++;
602 // Go on with the "replaced" edge
603 replace_search_tree(root->with, rep_env);
609 /************************************************************************
610 * Manipulate Match object before replacement to not use the
611 * temporarily created VProj nodes but the VProj nodes created by
612 * the previous replacement.
613 ************************************************************************/
615 static void manipulate_match(replace_st_env_t *rep_env, ext_grs_match_t *match, int which)
618 * Find out which nodes and edges have to be manipulated
619 - Iterate through matches array
620 - Look if a node is inside the which_match_vproj map
621 - Retrieve the preceeding match object
625 int max_aiid = ext_grs_get_match_max_node_aiid(match);
626 ir_node **node_map = ext_grs_get_match_node_map(match, which);
627 which_match_vproj_t *wmv;
631 for(i = 0; i < max_aiid; i++)
633 if((wmv = (which_match_vproj_t *) pmap_get(rep_env->which_match_vproj, node_map[i])) != NULL)
635 // We found an entry that has to be rewired.
638 // It's a retyped result node. Follow "kept" array that points to the replace_node_map
639 ir_node **repl_node_map = wmv->match->repl_nodes[wmv->which];
640 node_map[i] = repl_node_map[wmv->match->action->pattern_node_kept[wmv->aiid]];
644 // It's the vector proj, which is not in the "kept" array since it was newly inserted.
645 // Search for it by name in the replace_node_map
646 int aiid = ext_grs_act_get_node_aiid(wmv->match->action, VECTOR_OP_PROJDATA_NAME);
647 ir_node **repl_node_map = wmv->match->repl_nodes[wmv->which];
648 assert(aiid >= 0 && "Vector_Op_ProjData not found!");
649 node_map[i] = repl_node_map[aiid];
654 // Manipulate edges! Maybe not even necessary! As well as Vprojs, we just need the
655 // Vector_op_ProjData node!
660 /************************************************************************
661 * Find the block to place the complex operation in
662 * We have to think here:
663 * Maybe we should prefer the blocks of the memory nodes. If no memory
664 * nodes there, the algorithm should be correct.
665 ************************************************************************/
667 void set_complex_operation_block(ir_graph *irg, ext_grs_match_t *match, int which)
669 ir_node **nodes = ext_grs_get_replace_node_map(match, which);
670 int max_id = match->action->max_repl_node_aiid;
673 ir_node *current_block = NULL;
677 for(i = 0; i <= max_id; i++)
681 ir_opcode opc = get_irn_opcode(nodes[i]);
682 if(opc != iro_Conv && match->action->replacement_nodes[i]->op != op_IrNode /* Its a generic Vector Base */ && opc != iro_VProj && opc != iro_MultipleAdd && opc != iro_Block && opc != iro_Const && strncmp(match->action->replacement_nodes[i]->name, "Arg_", 4) != 0)
684 if(current_block == NULL)
685 current_block = get_nodes_block(nodes[i]);
688 ir_node *this_block = get_nodes_block(nodes[i]);
689 if(this_block && this_block != current_block && block_dominates(this_block, current_block))
690 current_block = this_block;
696 // Set the Block for the complex operation and it's projs
697 assert(current_block != NULL);
698 set_nodes_block(nodes[ext_grs_act_get_node_aiid(match->action, VECTOR_OP_PROJDATA_NAME)], current_block);
699 set_nodes_block(nodes[ext_grs_act_get_node_aiid(match->action, VECTOR_OP_NAME)], current_block);
700 if((aiid = ext_grs_act_get_node_aiid(match->action, VECTOR_OP_PROJM_NAME)) >= 0)
701 set_nodes_block(nodes[aiid], current_block);
708 ___ ___ __ _ _ __ ___| |__ | |_ _ __ ___ ___ __| |_ _ _ __ ___ _ __ ___ _ __
709 / __|/ _ \/ _` | '__/ __| '_ \ | __| '__/ _ \/ _ \ / _` | | | | '_ ` _ \| '_ \ / _ \ '__|
710 \__ \ __/ (_| | | | (__| | | | | |_| | | __/ __/ | (_| | |_| | | | | | | |_) | __/ |
711 |___/\___|\__,_|_| \___|_| |_| \__|_| \___|\___| \__,_|\__,_|_| |_| |_| .__/ \___|_|
714 /***********************************************************************
715 * Dumps search trees in VCG Format
716 ************************************************************************/
718 int glob_node_nr = 0;
719 void dump_search_tree(search_tree_node_t *root, char *file, char *graph_name, search_tree_env_t *st_env)
721 FILE *fp = fopen(file, "wt");
722 assert(fp && "Could not open file to dump");
726 "graph: { title: \"ir graph of %s\"\n"
727 "display_edge_labels: yes\n"
728 "layoutalgorithm: mindepth\n"
729 "manhattan_edges: yes\n"
731 //"orientation: %s\n"
732 "infoname 1: \"Test\"\n",
733 graph_name);//, label, orientation);
734 fprintf(fp, "\n"); /* a separator */
737 rec_dump_search_tree(root, fp, 0, st_env, 1);
746 /************************************************************************
747 * Called for each search tree node recursively and dumps its
749 * Params: bestcost: 1 If we're on the path with the best costs
750 ************************************************************************/
752 int rec_dump_search_tree(search_tree_node_t *node, FILE *fp, int this_node_nr, search_tree_env_t *st_env, int best_cost)
754 int next_node_nr = this_node_nr;
756 char args[1000], arg_name[20], tmp[1000];
757 int i = 0, aiid, replace;
760 if(node->match != NULL)
762 nodes = ext_grs_get_match_node_map(node->match, node->which_match);
766 sprintf(arg_name, "Arg_%d", i);
767 aiid = ext_grs_act_get_node_aiid(node->match->action, arg_name);
770 sprintf(tmp, "Arg_%d: %s %d ", i, get_irn_opname(nodes[aiid]), get_irn_node_nr(nodes[aiid]));
776 sprintf(tmp, "st_node: %p\n", node);
778 sprintf(tmp, "CostSavings: %d\n", node->cost_savings);
780 sprintf(tmp, "CostSavings this node %d\n", node->this_matchs_costsavings);
783 replace = ((node->without->cost_savings) > (node->with->cost_savings + node->this_matchs_costsavings)) ? 0 : 1;
785 fprintf(fp, "node: { title: \"n%d\" label: \"%s\" color:%s info1: \"%s\" }\n", this_node_nr, st_env->rules[node->rule_nr]->name, (replace && best_cost) ? "red" : "white", args);
787 if(node->with->match != NULL)
789 fprintf(fp, "edge: { sourcename: \"n%d\" targetname: \"n%d\" label: \"1\" color:%s}\n", this_node_nr, this_node_nr+1, (replace==1 && best_cost) ? "red" : "black");
790 next_node_nr = rec_dump_search_tree(node->with, fp, this_node_nr + 1, st_env, (replace==1 && best_cost));
793 if(node->without->match != NULL)
795 fprintf(fp, "edge: { sourcename: \"n%d\" targetname: \"n%d\" label: \"0\" color:%s}\n", this_node_nr, next_node_nr+1, (replace==0 && best_cost) ? "red" : "black");
796 next_node_nr = rec_dump_search_tree(node->without, fp, next_node_nr + 1, st_env, (replace==0 && best_cost));
800 return(next_node_nr);