moved firmext code into the backend dir
[libfirm] / ir / be / grgen / simd / create_pattern.c
1 /***************************************************************************
2  * Program:  create_pattern.c
3  * Function: Transforms the given ir_graph into the pattern (search) graph.
4  *                      Extracts nodes to be dumped by the grgen_dumper and other
5  *                      information into a graph_ana structure.
6  * Author:   Andreas Schoesser
7  * Date:     2006-12-07
8  ***************************************************************************/
9
10 #include <dos.h>
11 #include <assert.h>
12 #include <malloc.h>
13 #include <time.h>
14 #include <stdlib.h>
15
16 #include "simd_presets.h"
17
18 #include "obstack.h"
19 #include "pmap.h"
20 #include "irgmod.h"
21 #include "irprog_t.h"
22 #include "irdump.h"
23 #include "iredges.h"
24 #include "irgopt.h"
25 #include "irgwalk.h"
26 #include "iroptimize.h"
27 #include "tv.h"
28 #include "irtools.h"
29
30 #include "simd_presets.h"
31 #include "firm_node_ext.h"
32 #include "create_pattern_t.h"
33 #include "grgen_dumper.h"
34 #include "be_spec_dumper.h"
35 #include "normalize.h"
36 #include "rule_info_dumper.h"
37
38
39
40 /************************************************************************
41  * Generates pattern for one given function
42  * representing the C-specification of a complex instruction
43  ************************************************************************/
44
45 void ext_grs_create_pattern() {
46         graph_ana_info_t graph_ana_info;
47         char c, grgen_commandline[1000] = "";
48         int i, variants, rule_nr = 0;
49         struct obstack obst;                                                     // General obst for objects generated during analysis
50         int last_priority = 0;
51
52         // Environments of the used modules
53         be_spec_env_t *be_spec_env;
54         grgen_dumper_env_t *grgen_dumper_env;
55         rule_info_env_t *rule_info_env;
56
57         clock_t start_time, end_time;
58
59         #ifdef DUMP_EVERYTHING
60                 for(i = 0; i < get_irp_n_irgs(); i++)
61                 {
62                         char filename[1000];
63                         sprintf(filename, "%s.grg", get_entity_name(get_irg_entity(irg)));
64                         dump_irgraph_complete_grgen(get_irp_irg(i), filename, 0);
65                 }
66                 return;
67         #endif
68
69         // Generate Header of rule pointers file
70         rule_info_env = init_rule_info_dumper(get_irp_n_irgs() * MAX_ADDRESS_VARIANTS);
71         be_spec_env = init_be_spec();
72         grgen_dumper_env = init_grgen_dumper(GRGEN_GRAPH_FILE, 0);
73
74         // Create VProj FIRM nodes etc.
75         ext_firm_nodes();
76
77         start_time = clock();
78         for(i = 0; i < get_irp_n_irgs(); i++)
79         {
80                 struct pmap *nodes_to_dump = pmap_create();      // Saves all nodes that have to be dumped after analysis
81                 struct pmap *register_access = pmap_create();    // Saves LOAD and STORE nodes that access registers instead of memory,
82                                                                                                                  // along with their array index.
83                 struct pmap *memory_access = pmap_create();      // Saves LOAD and STORE nodes that access memory along
84                 struct pmap *argument_nodes = pmap_create();     // Saves nodes that deliver pointers for memory access
85
86                 obstack_init(&obst);
87
88                 // Init the walker_info structure, which contains data needed or filled during
89                 // the analysis of the graph
90                 graph_ana_info.irg = get_irp_irg(i);
91                 graph_ana_info.nodes_to_dump = nodes_to_dump;
92                 graph_ana_info.register_access = register_access;
93                 graph_ana_info.memory_access = memory_access;
94                 graph_ana_info.argument_nodes = argument_nodes;
95                 graph_ana_info.destroyed_regs = pmap_create();
96                 graph_ana_info.obst = &obst;
97                 graph_ana_info.num_simd_arguments = 0;
98                 graph_ana_info.complex_operation_block = NULL;
99                 graph_ana_info.node_to_match_block = NULL;
100                 graph_ana_info.emit_statement = NULL;
101                 graph_ana_info.has_result = 0;
102                 graph_ana_info.variant_nr = 0;
103                 graph_ana_info.priority = last_priority; // Maybe the user did not specify a priority in this pattern. Use the last priority then.
104                 graph_ana_info.cost_savings = 3;
105                 graph_ana_info.dump_everything = 0;
106
107                 printf("*** %s ***:\n", get_entity_name(get_irg_entity(graph_ana_info.irg)));
108
109                 // Dump the graph before we change anything
110                 dump_ir_block_graph(graph_ana_info.irg, "-pre-create-pattern");
111
112                 // Normalize the Address calculation for LOADs and STOREs
113                 set_irg_memory_disambiguator_options(graph_ana_info.irg, aa_opt_no_alias);
114                 optimize_load_store(graph_ana_info.irg);
115                 remove_critical_cf_edges(graph_ana_info.irg);
116                 normalize_address_calculation(graph_ana_info.irg, 0);
117
118
119                 // Dump the graph before we change anything
120                 dump_ir_block_graph(graph_ana_info.irg, "-post-norm-pattern");
121
122
123                 // Analyze graph
124                 irg_walk_graph(graph_ana_info.irg, walk_pre, walk_post, &graph_ana_info);
125                 if(graph_ana_info.emit_statement == NULL)
126                         assert(0 && "No emit statement given!");
127
128                 edges_activate(graph_ana_info.irg);
129                 for(variants = 0; variants < MAX_ADDRESS_VARIANTS; variants++)
130                 {
131                         int uses_memory; // TODO: Maybe find the out during analysis.
132
133                         // Dump rule information
134                         dump_rule_info(rule_info_env, &graph_ana_info, graph_ana_info.num_simd_arguments);
135                         rule_nr++;
136
137                         // Dump graph (that is pattern) in grGen format
138                         uses_memory = dump_irgraph_grgen(grgen_dumper_env, &graph_ana_info);
139
140                         // Dump the backend specification
141                         dump_be_spec(be_spec_env, &graph_ana_info, uses_memory);
142
143                         // Add an address variant
144                         if(variants < MAX_ADDRESS_VARIANTS - 1)
145                         {
146                                 if(!add_address_variant(&graph_ana_info))
147                                         break;
148                                 graph_ana_info.variant_nr++;
149                         }
150                 }
151
152                 // New code placement
153                 //      set_opt_global_cse(1);
154                 //      optimize_graph_df(walker_info.irg);
155                 //      place_code(walker_info.irg);
156                 //      set_opt_global_cse(0);
157
158                 // Dump graph in .vcg format
159                 dump_ir_block_graph(graph_ana_info.irg, "-post-create-pattern");
160
161                 //dump_type_graph (walker_info.irg, "-TYPES");
162
163                 // Clean up
164                 pmap_destroy(nodes_to_dump);
165                 pmap_destroy(register_access);
166                 pmap_destroy(argument_nodes);
167                 pmap_destroy(memory_access);
168                 pmap_destroy(graph_ana_info.destroyed_regs);
169
170                 obstack_free(&obst, NULL);
171                 obstack_finish(&obst);
172                 printf("\n");
173
174                 last_priority = graph_ana_info.priority;
175         }
176
177         deinit_rule_info_dumper(rule_info_env);
178         deinit_grgen_dumper(grgen_dumper_env);
179         deinit_be_spec(be_spec_env);
180         end_time = clock();
181
182         printf("*******************************\n* Pattern Creation Statistics *\n*******************************\n\n");
183
184         printf("Time elapsed:   %g s\n", ((double) (end_time - start_time)) / CLOCKS_PER_SEC);
185         printf("Rules created:  %d\n", rule_nr);
186
187         printf("\n\n ** Finished pattern creation **\n\n");
188
189         printf("Run grGen now? (Y/N) ");
190         c = getchar();
191         if(c == 'y' || c == 'Y')
192                 run_grgen();
193 }
194
195
196
197 /************************************************************************
198  * Build a command line in order to run grgen
199  * Parameters for the GrGen call are globally set in simd_presets.h
200  ************************************************************************/
201
202 static void run_grgen()
203 {
204         char grgen_commandline[1000];
205
206         strcpy(grgen_commandline, "java -classpath \"");
207         strcat(grgen_commandline, GRGEN_LOCATION);
208         strcat(grgen_commandline, "grgen.jar;");
209         strcat(grgen_commandline, GRGEN_LOCATION);
210         strcat(grgen_commandline, "jars/jargs.jar;");
211         strcat(grgen_commandline, GRGEN_LOCATION);
212         strcat(grgen_commandline, "jars/antlr.jar\" de.unika.ipd.grgen.Main -n -j -i -b de.unika.ipd.grgen.be.C.SearchPlanBackend -o \"");
213         strcat(grgen_commandline, GENERATION_DEST);
214         strcat(grgen_commandline, "\" \"");
215         strcat(grgen_commandline, GRGEN_GRAPH_FILE);
216         strcat(grgen_commandline, "\"");
217
218         printf("%s\n", grgen_commandline);
219
220         // Call grGen to create C source for searching the pattern
221         system(grgen_commandline);
222 }
223
224
225
226 /*                                         _                         _           _
227   __ _ _ __ __ _ _ __ | |__     __ _ _ __   __ _| |_   _ ___(_)___
228  / _` | '__/ _` | '_ \| '_ \   / _` | '_ \ / _` | | | | / __| / __|
229 | (_| | | | (_| | |_) | | | | | (_| | | | | (_| | | |_| \__ \ \__ \
230  \__, |_|  \__,_| .__/|_| |_|  \__,_|_| |_|\__,_|_|\__, |___/_|___/
231  |___/          |_|                                |___/               */
232
233
234
235 /************************************************************************
236  * Analyze LOAD and STORE nodes, mark nodes for dumping
237  ************************************************************************/
238
239 static void walk_pre(ir_node *n, void * env)
240 {
241         graph_ana_info_t *graph_ana_info = (graph_ana_info_t *) env;
242         struct pmap *nodes_to_dump = graph_ana_info->nodes_to_dump;
243         struct pmap *register_access = graph_ana_info->register_access;
244         struct pmap *memory_access = graph_ana_info->memory_access;
245         struct pmap *argument_nodes = graph_ana_info->argument_nodes;
246
247         ir_graph *host_irg = graph_ana_info->irg;
248         //nodes_list_t *node_to_dump;
249
250         // **** Special case: We have a Store Node
251         if(get_irn_opcode(n) == iro_Store)
252         {
253                 ir_node *call_node = NULL, *add_node = NULL, *pointer_root = NULL;
254                 unsigned int array_index = 0;
255
256                 call_node = search_call(n, &array_index, &add_node, &pointer_root);
257                 if(is_memory_access(call_node))
258                 {
259                         memory_access_descr_t *memory_access_descr = obstack_alloc(graph_ana_info->obst, sizeof(memory_access_descr_t));
260
261                         // Operations on memory vectors HAVE to access the vector index 0!
262                         if(array_index == 0)
263                                 mark_argument_node(graph_ana_info, call_node, pointer_root, add_node);
264
265                         // Memory STORE, nothing has to be done
266                         memory_access_descr->load_store = MEMORY_STORE;
267                         memory_access_descr->array_index = array_index;
268                         pmap_insert(memory_access, n, (void *) memory_access_descr);
269                 }
270                 else
271                 {
272                         register_access_descr_t *register_access_descr = obstack_alloc(graph_ana_info->obst, sizeof(register_access_descr_t));
273
274                         // Store information about the argument node
275                         mark_argument_node(graph_ana_info, call_node, pointer_root, add_node);
276
277                         // Fill the register access descriptor
278                         register_access_descr -> array_index = array_index;
279                         register_access_descr -> load_store  = REGISTER_STORE;
280                         register_access_descr -> replace_node_name = NULL;
281                         register_access_descr -> pointer_base = pointer_root;
282
283                         // Mark the predecessor of the store node as the result to be stored in a register
284                         if(get_irn_opcode(get_irn_n(n, 2)) == iro_Conv)
285                         {
286                                 /* Hack */
287                                 ir_node *conv = get_irn_n(n, 2);
288                                 exchange(conv, get_irn_n(conv, 0));
289                         }
290
291                         pmap_insert(register_access, get_irn_n(n, 2), (void *) register_access_descr);
292
293                         // Prevent the Address of the STORE node to be dumped.
294                         set_irn_visited(get_irn_n(n, 1), get_irg_visited(get_irn_irg(n)));
295
296                         // Don't dump the STORE NODE
297                         return;
298                 }
299         }
300
301
302         // **** Special case: We have a Load node
303         if(get_irn_opcode(n) == iro_Load)
304         {
305                 ir_node *call_node = NULL, *add_node = NULL, *pointer_root = NULL;
306                 unsigned int array_index = 0;
307
308                 //      kill_mem_pred(n);
309                 call_node = search_call(n, &array_index, &add_node, &pointer_root);
310
311                 if(is_memory_access(call_node))
312                 {
313                         memory_access_descr_t *memory_access_descr = obstack_alloc(graph_ana_info->obst, sizeof(memory_access_descr_t));
314
315                         // Operations on memory vectors HAVE to access the vector index 0!
316                         if(array_index == 0)
317                                 mark_argument_node(graph_ana_info, call_node, pointer_root, add_node);
318
319                         // Memory access, nothing has to be done
320
321                         memory_access_descr->load_store = MEMORY_LOAD;
322                         memory_access_descr->array_index = array_index;
323                         pmap_insert(memory_access, n, (void *) memory_access_descr);
324                 }
325                 else
326                 {
327                         // Register access, save information about this load
328                         register_access_descr_t *register_access_descr = obstack_alloc(graph_ana_info->obst, sizeof(register_access_descr_t));
329
330                         mark_argument_node(graph_ana_info, call_node, pointer_root, add_node);
331
332                         // Fill the register access descriptor
333                         register_access_descr->load_store  = REGISTER_LOAD;
334                         register_access_descr->array_index = array_index;
335                         register_access_descr -> replace_node_name = NULL;
336                         register_access_descr -> pointer_base = pointer_root;
337
338                         // Mark this LOAD node, which has to be exchanged by a VProj node
339                         pmap_insert(register_access, n, (void *) (register_access_descr));
340
341                         if(add_node != NULL)
342                                 set_irn_visited(add_node, get_irg_visited(get_irn_irg(add_node)));
343
344                         pmap_insert(nodes_to_dump, pointer_root, NULL); // TODO: If the value is already there, will it be overwritten?
345
346                         // Don't dump this LOAD node.
347                         return;
348                 }
349         }
350
351         // Mark the current node for Dumping
352         switch(get_irn_opcode(n))
353         {
354
355                 case iro_Call:
356                         search_emit_statement(n, graph_ana_info);
357                         break;
358                 case iro_End: //We match also the end node.
359                 case iro_Start:
360                 case iro_Return:
361                 case iro_Block:
362                 case iro_SymConst:
363                 //case iro_Jmp:
364                 case iro_Sync:
365                 case iro_Bad:
366                         break;
367
368                 case iro_Phi:
369                         if(get_irn_modecode(n) != irm_M)
370                                 mark_node_for_dumping(n, graph_ana_info);
371                         break;
372
373                 case iro_Proj:
374                         // Proj's beyond LOADs and STOREs will be dumped in walk-post method
375                         // to be sure that all information about the LOAD and STORE has been already computed.
376                         if(get_irn_opcode(get_irn_n(n, 0)) == iro_Load || get_irn_opcode(get_irn_n(n, 0)) == iro_Store)
377                                 break;
378                         if(get_irn_opcode(get_irn_n(n, 0)) == iro_Call || get_irn_opcode(get_irn_n(n, 0)) == iro_Start)
379                                 break;
380                         if(get_irn_modecode(n) == irm_X && get_irg_start_block(graph_ana_info->irg) == get_nodes_block(n)) // We don't need the initial ProjX
381                                 break; // TODO: This is only valid of only one block is there!!!
382
383                         // Else Fall through
384
385                 default:
386                         mark_node_for_dumping(n, graph_ana_info);
387                         break;
388         }
389 }
390
391
392
393 /************************************************************************
394  * Take special care of Proj nodes beyond LOAD and STORE
395  * Here we can be sure that the LOAD or STORE node has already been
396  * analyzed.
397  ************************************************************************/
398
399 static void walk_post(ir_node *n, void * env)
400 {
401         graph_ana_info_t *graph_ana_info = (graph_ana_info_t *) env;
402         struct pmap *nodes_to_dump = graph_ana_info->nodes_to_dump;
403         struct pmap *register_access = graph_ana_info->register_access;
404         struct pmap *memory_access = graph_ana_info->memory_access;
405         ir_graph *host_irg = graph_ana_info->irg;
406
407         if(get_irn_opcode(n) == iro_Proj)
408         {
409                 ir_node *proj_pred = get_irn_n(n, 0);
410
411
412                 if(get_irn_opcode(proj_pred) == iro_Store)
413                 {
414                         ir_mode *store_mode = get_irn_mode(get_Store_value(proj_pred));
415
416                         if(pmap_contains(memory_access, proj_pred))
417                         {
418                                 memory_access_descr_t *memory_access_descr = pmap_get(memory_access, proj_pred);
419                                 memory_access_descr->projm = n;
420                                 memory_access_descr->array_index /= get_mode_size_bytes(store_mode);
421
422                                 printf("MEMORY STORE at array index %d\n", memory_access_descr->array_index);
423
424                                 // Mark the current proj for dumping.
425                                 mark_node_for_dumping(n, graph_ana_info);
426                                 //pmap_insert(memory_access, n, memory_access_descr);
427                         }
428                         else
429                         {
430                                 // Adapt array index
431                                 register_access_descr_t *register_access_descr = pmap_get(register_access, get_Store_value(proj_pred));
432                                 register_access_descr->array_index /= get_mode_size_bytes(store_mode);
433                                 printf("REGISTER STORE at array index %d\n", register_access_descr->array_index);
434                                 // Register STORE, don't dump it's ProjM
435                                 return;
436                         }
437                 }
438
439                 if(get_irn_opcode(proj_pred) == iro_Load)
440                 {
441                         ir_mode *load_mode = get_irn_mode(n);
442
443                         if(pmap_contains(register_access, proj_pred))
444                         {
445                                 // Register LOAD: Take special care of proj's
446
447
448                                 if(get_irn_modecode(n) != irm_M)
449                                 {
450                                         ir_node *vproj_node;
451                                         register_access_descr_t *register_access_descr = pmap_get(register_access, proj_pred);
452                                         register_access_descr -> array_index /= get_mode_size_bytes(load_mode);
453                                         printf("REGISTER LOAD at array index %d\n", register_access_descr->array_index);
454
455                                         // We cannot use 'exchange' here, because the node n could already be in
456                                         // the register_access or memory_access list. Exchanging would result in a wrong pointer
457                                         // in those lists. Luckily Proj an VProj use the same node data, so we can just
458                                         // retype the proh to vproj without danger.
459
460                                         set_irn_n(n, 0, register_access_descr->pointer_base);
461                                         set_irn_op(n, op_VProj);
462                                         vproj_node = n;
463                                         set_VProj_proj(n, register_access_descr->array_index);
464                                 }
465                                 else
466                                 {
467                                         // It's the memory proj. Just don't dump it
468                                         return;
469                                 }
470                         }
471                         else
472                         {
473                                 if(get_irn_modecode(n) != irm_M)
474                                 {
475                                         memory_access_descr_t *memory_access_descr = pmap_get(memory_access, proj_pred);
476                                         memory_access_descr -> array_index /= get_mode_size_bytes(load_mode);
477                                         printf("MEMORY LOAD at array index %d\n", memory_access_descr->array_index);
478                                 }
479                         }
480
481                         // Mark the current proj for dumping.
482                         mark_node_for_dumping(n, graph_ana_info);
483                 }
484         }
485 }
486
487 void mark_node_for_dumping(ir_node *n, graph_ana_info_t *graph_ana_info)
488 {
489         analyze_complex_operation_block(n, graph_ana_info);
490         pmap_insert(graph_ana_info->nodes_to_dump, n, NULL);
491         if(get_irn_opcode(n) != iro_Block && get_irn_opcode(n) != iro_Const)
492         {
493                 ir_node *block = get_nodes_block(n);
494                 pmap_insert(graph_ana_info->nodes_to_dump, block, NULL);
495         }
496 }
497
498
499
500 /************************************************************************
501  * Analyzes the behavior of a LOAD or STORE node
502  * Also detects ConvP node and prevents further dumping
503  * start_node:  LOAD or STORE node to analyze
504  * array_index: Returns the array index of the LOAD or STORE
505  * result:      CALL node defining the behavior of the LOAD OR STORE
506  ************************************************************************/
507
508 static ir_node *search_call(ir_node *start_node, unsigned int *array_index, ir_node **add, ir_node **pointer_root)
509 {
510         ir_node *add_node;
511         //ir_node *convP_node;  // If there's convP involved, replace proj_node by conP_node
512         ir_node *proj_node;
513         ir_node *call_node;
514         ir_node *proj_pred_node;
515         int     aindex = 0;
516
517         assert(get_irn_opcode(start_node) == iro_Load || get_irn_opcode(start_node) == iro_Store);
518
519         add_node = get_irn_n(start_node, 1);
520
521         if(get_irn_opcode(add_node) != /*iro_Add*/ iro_MultipleAdd)
522         {
523                 // Add node is not there if array Index is 0
524                 proj_node = add_node;
525                 add_node = NULL;
526                 assert(0); // Must not happen when multiple Adds are there
527         }
528         else
529         {
530                 // Analyze MultipleAdd predecessors
531                 if(get_irn_opcode(get_irn_n(add_node, 0)) == iro_Proj)
532                 {
533                         proj_node = get_irn_n(add_node, 0);
534                         aindex = get_tarval_long(get_Const_tarval(get_irn_n(add_node, 1))); // get_mode_size_bytes(get_irn_mode()) /*4*/;  // TODO: varibale TARVALS
535                 }
536                 else
537                 {
538                         proj_node = get_irn_n(add_node, 1);
539                         aindex = get_tarval_long(get_Const_tarval(get_irn_n(add_node, 0)));// / 4;  // TODO: varibale TARVALS
540                 }
541         }
542
543         assert(get_irn_opcode(proj_node) == iro_Proj);
544         //call_node = get_irn_n(get_irn_n(get_irn_n(convP_node, 0), 0), 0); // ConvP -> ProjIs -> ProjT -> Call
545         call_node = get_irn_n(get_irn_n(proj_node, 0), 0); // ProjIs -> ProjT -> Call
546         assert(get_irn_opcode(call_node) == iro_Call && "Call node not found! Pattern not valid.");
547
548         *array_index = aindex;
549         *add = add_node;
550         *pointer_root = proj_node;
551
552         // Prevent further dumping of nodes starting from that convP Node
553         proj_pred_node = get_irn_n(proj_node, 0);
554         set_irn_visited(proj_pred_node, get_irg_visited(get_irn_irg(proj_pred_node)));
555
556         return(call_node);
557 }
558
559
560
561 /************************************************************************
562  * Marks a vector base pointer to be used as an argument for the
563  * complex operation afterwards
564  ************************************************************************/
565
566 static void mark_argument_node(graph_ana_info_t *graph_ana_info, ir_node *call_node, ir_node *argument_node, ir_node *add_node)
567 {
568         const char *arg_name;
569         int  arg_nr = -1, i;
570
571         // Look if we marked that node already
572         if(!pmap_contains(graph_ana_info->argument_nodes, argument_node))
573         {
574                 // No. Find out which argument number this node will be
575                 // for complex operation
576                 arg_name = get_entity_name(get_SymConst_entity(get_irn_n(call_node, 1)));
577
578                 // Is it the result pointer?
579                 if(strcmp(arg_name, RESULT_NAME) == 0)
580                 {
581                         // Arg nr is -1 since we don't know how much
582                         char *register_class;
583                         argument_descr_t *argument_descr = obstack_alloc(graph_ana_info->obst, sizeof(argument_descr_t));
584
585                         register_class = obstack_alloc(graph_ana_info->obst, get_SymConst_strlen(get_irn_n(call_node, 4)));
586                         get_SymConst_string(get_irn_n(call_node, 4), register_class);
587
588                         argument_descr -> arg_nr = -1;
589                         argument_descr -> argument_location = ARGUMENT_RESULT;                  // TODO: This is wrong, Memory or Register here
590                         argument_descr -> argument_type = (is_vector(call_node) ? ARGUMENT_VECTOR : ARGUMENT_SCALAR);
591                         argument_descr -> register_class = register_class;
592                         argument_descr -> vec_op_input = add_node; // Only important for memory access nodes
593
594                         pmap_insert(graph_ana_info->argument_nodes, argument_node, (void *) argument_descr);
595                         graph_ana_info->has_result = 1;
596                         return;
597                 }
598
599                 for(i = 0; i < MAX_SIMD_ARGUMENTS; i++)
600                         if(strcmp(arg_name, SIMD_ARGUMENTS[i]) == 0)
601                         {
602                                 char *register_class;
603                                 argument_descr_t *argument_descr = obstack_alloc(graph_ana_info->obst, sizeof(argument_descr_t));
604
605                                 register_class = obstack_alloc(graph_ana_info->obst, get_SymConst_strlen(get_irn_n(call_node, 4)));
606                                 get_SymConst_string(get_irn_n(call_node, 4), register_class);
607
608                                 argument_descr -> arg_nr = i;
609                                 argument_descr -> argument_location = (!is_memory_access(call_node) ? ARGUMENT_SIMD_REGISTER : ARGUMENT_MEMORY);
610                                 argument_descr -> argument_type = (is_vector(call_node) ? ARGUMENT_VECTOR : ARGUMENT_SCALAR);
611                                 argument_descr -> register_class = register_class;
612                                 argument_descr -> vec_op_input = add_node;
613
614                                 pmap_insert(graph_ana_info->argument_nodes, argument_node, (void *) argument_descr);
615                                 graph_ana_info->num_simd_arguments = MAX(i, graph_ana_info->num_simd_arguments);
616                                 break;
617                         }
618         }
619 }
620
621
622
623 /************************************************************************
624  * Tests, if the given call_node is the emit-statement
625  * If so, saves the emit-statement for dumping later in the process.
626  ************************************************************************/
627
628 void search_emit_statement(ir_node *call_node, graph_ana_info_t *graph_ana_info)
629 {
630         ir_node *symC_name;
631         ir_node *symC_arg;
632         const char *function_name;
633         int i;
634
635         assert(get_irn_opcode(call_node) == iro_Call);
636
637         // Prevent walker to consider arguments of the call node.
638         for(i = 1; i < get_irn_arity(call_node); i++)
639                 set_irn_visited(get_irn_n(call_node, i), get_irg_visited(get_irn_irg(call_node)));
640
641         // Check the function name
642         symC_name = get_irn_n(call_node, 1);
643         function_name = get_entity_name(get_SymConst_entity(symC_name));
644
645         // Save the emit statement
646         if(strcmp(function_name, EMIT) == 0)
647         {
648                 // Allocate space for the emit statement and save it.
649                 char *emit_statement;
650                 symC_arg = get_irn_n(call_node, 2);
651                 emit_statement = obstack_alloc(graph_ana_info->obst, get_SymConst_strlen(symC_arg));
652                 get_SymConst_string(symC_arg, emit_statement);
653                 graph_ana_info->emit_statement = emit_statement;
654                 return;
655         }
656
657         // Save the extra registers, the complex operation destroys
658         if(strcmp(function_name, DESTROYS) == 0)
659         {
660                 char *destroy_statement;
661                 symC_arg = get_irn_n(call_node, 2);
662                 destroy_statement = obstack_alloc(graph_ana_info->obst, get_SymConst_strlen(symC_arg));
663
664                 get_SymConst_string(symC_arg, destroy_statement);
665                 pmap_insert(graph_ana_info->destroyed_regs, call_node, destroy_statement);
666         }
667
668         if(strcmp(function_name, PRIORITY) == 0)
669         {
670                 ir_node *c = get_irn_n(call_node, 2);           // Get the constant argument
671                 assert(get_irn_opcode(c) == iro_Const && "Something is wrong with the priority node");
672                 graph_ana_info->priority = get_tarval_long(get_Const_tarval(c));
673         }
674
675         if(strcmp(function_name, COST_SAVINGS) == 0)
676         {
677                 ir_node *c = get_irn_n(call_node, 2);           // Get the constant argument
678                 assert(get_irn_opcode(c) == iro_Const && "Something is wrong with the CostSavings node");
679
680                 graph_ana_info->cost_savings = get_tarval_long(get_Const_tarval(c));
681         }
682 }
683
684
685 #if 0
686
687 Not needed any more
688
689 /************************************************************************/
690 /* Cut's of the Memory predecessor of a LOAD node                       */
691 /* We don't need that node in the final pattern.                        */
692 /************************************************************************/
693
694 static void kill_mem_pred(ir_node *load)
695 {
696         assert(get_irn_opcode(load) == iro_Load);
697
698         // TODO: Think about this. Is this really enough?
699         if(get_irn_opcode(get_irn_n(get_irn_n(load, 0), 0)) == iro_Call)
700                 set_irn_visited(get_irn_n(load, 0), get_irg_visited(get_irn_irg(load)));
701 }
702
703 #endif
704
705
706
707 /************************************************************************
708  * Returns for a given call node if the underlying LOAD or STORE access
709  * memory (1) or not (0)
710  ************************************************************************/
711 static int is_memory_access(ir_node *call)
712 {
713         char symC_string[255];
714         ir_node *symC;
715
716         assert(get_irn_opcode(call) == iro_Call);
717         symC = get_irn_n(call, 3);
718         assert(get_irn_opcode(symC) == iro_SymConst);
719
720         get_SymConst_string(symC, symC_string);
721         if(strstr(symC_string, MEMORY_ARRAY) != 0)
722                 return(1);
723         return(0);
724 }
725
726
727 /************************************************************************/
728 /* Returns 1 if the given argument represents a vector                  */
729 /************************************************************************/
730
731 static int is_vector(ir_node *call)
732 {
733         char symC_string[255];
734         ir_node *symC;
735
736         assert(get_irn_opcode(call) == iro_Call);
737         symC = get_irn_n(call, 2);
738         assert(get_irn_opcode(symC) == iro_SymConst);
739         get_SymConst_string(symC, symC_string);
740         if(strstr(symC_string, "vector") != 0)
741                 return(1);
742         return(0);
743 }
744
745
746
747 /************************************************************************
748  * Analyze, if the current pattern node is in the immediate post
749  * dominator block of the start block
750  ************************************************************************/
751
752 /*
753  Der Block jedes aufgenommenen Knotens wird ueberprueft.
754  Falls dieser der direkte Nachdominator des Startblocks ist, ist das der Block, in den der komplexe Befehl soll.
755
756  Problem:
757  Wird der Block dann auch wirklich mit einem Knoten des Musters verbunden?
758  Beim Component-Fall anscheinend nicht.
759  */
760
761 void analyze_complex_operation_block(ir_node *n, graph_ana_info_t *graph_ana_info)
762 {
763         if(graph_ana_info->complex_operation_block == NULL && get_irn_opcode(n) != iro_Block)
764         {
765                 ir_node *block = get_nodes_block(n);
766                 if(block != get_irg_start_block(graph_ana_info->irg))
767                 {
768                         ir_node *block_pred = get_irn_n(block, 0);
769                         if(get_irn_opcode(block_pred) != iro_Block)
770                                 block_pred = get_nodes_block(block_pred);
771                         if(block_pred == get_irg_start_block(graph_ana_info->irg))
772                         {
773                                 if(!pmap_contains(graph_ana_info->argument_nodes, n))
774                                 {
775                                         graph_ana_info->complex_operation_block = block;
776                                         graph_ana_info->node_to_match_block = n;
777                                         //pmap_insert(walker_info->nodes_to_dump, block, NULL);
778                                 }
779                         }
780                 }
781         }
782 }
783
784
785
786 /*               _             _
787 __   ____ _ _ __(_) __ _ _ __ | |_ ___
788 \ \ / / _` | '__| |/ _` | '_ \| __/ __|
789  \ V / (_| | |  | | (_| | | | | |_\__ \
790   \_/ \__,_|_|  |_|\__,_|_| |_|\__|___/  */
791
792 /************************************************************************
793  * Generates an address mode variant
794  * Returns 0 if no variant was generated because no address calculation
795  * is made.
796  ************************************************************************/
797
798 int add_address_variant(graph_ana_info_t *graph_ana_info)
799 {
800         int i;
801         struct pmap *argument_nodes = graph_ana_info->argument_nodes;
802         int found = 0;
803
804         pmap_entry *entry;
805
806         pmap_foreach(argument_nodes, entry)
807         {
808                 ir_node *arg = (ir_node *) entry->key;
809                 argument_descr_t *arg_descr = entry->value;
810                 const ir_edge_t *edge;
811                 ir_node *generic_node;
812
813                 if(arg_descr -> argument_type == ARGUMENT_VECTOR && arg_descr -> argument_location == ARGUMENT_MEMORY)
814                 {
815                         generic_node = new_ir_node(NULL, graph_ana_info->irg, get_nodes_block(arg), op_IrNode, mode_ANY, 0, NULL);
816                         set_irn_mode(generic_node, mode_ANY);
817                         pmap_insert(graph_ana_info->nodes_to_dump, generic_node, NULL);
818                         foreach_out_edge_kind(arg, edge, EDGE_KIND_NORMAL)
819                         {
820                                 ir_node *mult_add = get_edge_src_irn(edge);
821                                 int new_arity = get_irn_arity(mult_add) + 1;
822                                 ir_node **new_ins = alloca(new_arity * sizeof(ir_node *));
823
824                                 found = 1;
825                                 assert(get_irn_opcode(mult_add) == iro_MultipleAdd);
826
827                                 for(i = 0; i < get_irn_arity(mult_add); i++)
828                                         new_ins[i] = get_irn_n(mult_add, i);
829                                 new_ins[i] = generic_node;
830                                 set_irn_in(mult_add, new_arity, new_ins);
831                         }
832
833                 }
834         }
835         return(found);
836 }
837
838
839
840 /*                  _
841   _ __ ___ (_)___  ___
842  | '_ ` _ \| / __|/ __|
843  | | | | | | \__ \ (__
844  |_| |_| |_|_|___/\___| */
845
846
847 /************************************************************************
848  * Concatenates the rule name out of the irg name and the variant
849  * number
850  ************************************************************************/
851
852 void get_rule_name(graph_ana_info_t *graph_ana_info, char *rule_name)
853 {
854         ir_graph *irg = graph_ana_info->irg;
855         sprintf(rule_name, "%s_variant%d", get_entity_name(get_irg_entity(irg)), graph_ana_info->variant_nr);
856 }
857
858
859
860 /************************************************************************
861  * Gets the number of characters contained in a string SymConst
862  * including the trailing 0-Character
863  ************************************************************************/
864
865 int get_SymConst_strlen(ir_node *symC)
866 {
867         ir_entity *ent = get_SymConst_entity(symC);
868         return(get_compound_ent_n_values(ent) + 1);
869 }
870
871
872
873 /************************************************************************
874  * Reads the string assiciated with a sym_const and stores it in
875  * 'string'
876  ************************************************************************/
877
878 void get_SymConst_string(ir_node *symC, char *string)
879 {
880         ir_entity *ent = get_SymConst_entity(symC);
881         int i, n;
882
883         n = get_compound_ent_n_values(ent);
884
885         for (i = 0; i < n-1; i++) {
886                 ir_node *irn;
887                 int c;
888
889                 irn = get_compound_ent_value(ent, i);
890                 c = (int) get_tarval_long(get_Const_tarval(irn));
891                 string[i] = c;
892         }
893         string[i] = 0;
894 }