moved firmext code into the backend dir
[libfirm] / ir / be / grgen / simd / firm_node_ext.c
1 /*************************************************************************
2 * Program:  firm_node_ext.c
3 * Function: Provides functions to extend firm by nodes needed by the
4 *           SIMD optimizer
5 * Author:   Andreas Schoesser
6 * Date:     2007-02-01
7 *************************************************************************/
8
9 #include <stdio.h>
10 #include <assert.h>
11 #include <stdlib.h>
12
13 #include "simd_presets.h"
14
15 #include "irnode.h"
16 #include "irtools.h"
17 #include "irmemory.h"
18
19 #include "ia32/gen_ia32_regalloc_if.h"
20 #include "grs/base_t.h"
21
22 ir_opcode iro_VProj;
23 ir_op  *op_VProj;
24
25 ir_opcode iro_MultipleAdd;
26 ir_op *op_MultipleAdd;
27
28 ir_opcode iro_IrNode;
29 ir_op *op_IrNode;
30
31 ir_opcode iro_Complex;
32 ir_op *op_Complex;
33
34 ir_opcode iro_FakeComplex;
35 ir_op *op_FakeComplex;
36
37
38 ir_opcode iro_be_Keep;
39 extern ir_op *op_be_Keep;
40
41
42
43 /************************************************************************
44  * Initialize the pattern creation.
45  * - Creates new Firm opcodes needed by the transformation
46  ************************************************************************/
47
48 void ext_firm_nodes()
49 {
50         // The SIMD optimization inserts ia32 specific nodes
51         // Create the opcodes for those nodes here
52         // Reason: We need those opcodes when inserting ia32_nodes anyway.
53         ia32_register_init(NULL);
54         ia32_create_opcodes();
55         be_node_init();
56
57         iro_VProj = get_next_ir_opcode();
58         op_VProj = new_ir_op(iro_VProj, "VProj", op_pin_state_pinned, 0, oparity_unary, 0, sizeof(long), NULL);
59
60         iro_MultipleAdd = get_next_ir_opcode();
61         op_MultipleAdd = new_ir_op(iro_MultipleAdd, "MultipleAdd", op_pin_state_pinned, 0, oparity_dynamic, 0, 0, NULL);
62
63         iro_IrNode = get_next_ir_opcode();
64         op_IrNode = new_ir_op(iro_IrNode, "IR_node", op_pin_state_pinned, 0, oparity_dynamic, 0, 0, NULL);
65
66         iro_Complex = get_next_ir_opcode();
67         op_Complex = new_ir_op(iro_Complex, "Complex", op_pin_state_pinned, irop_flag_none, oparity_dynamic,  0, 0, NULL);
68
69         iro_FakeComplex = get_next_ir_opcode();
70         op_FakeComplex = new_ir_op(iro_FakeComplex, "FakeComplex", op_pin_state_pinned, irop_flag_none, oparity_dynamic,  0, 0, NULL);
71
72         iro_be_Keep = get_op_code(op_be_Keep);
73
74         // Mode LLu now exists:
75         //      mode_DLu = new_ir_vector_mode("DLu", irms_int_number, 128, 4, 0, irma_none, 128);
76 }
77
78
79
80 /************************************************************************
81  * Inserts a new ir_node an also updates the opcode lists of the GRS
82  ************************************************************************/
83
84 ir_node *new_ir_node_with_update(dbg_info *db, ir_graph *irg, ir_node *block, ir_op *op, ir_mode *mode, int arity, ir_node *in[])
85 {
86         ir_node *new_node = new_ir_node(db, irg, block, op, mode, arity, in);
87
88         // Update the GRS' node list
89         ext_grs_irn_private_t *pr_n = _ext_grs_get_irn_private(new_node);
90         ext_grs_irg_private_t *pr_g = _ext_grs_get_irg_private(irg);
91
92         memset(pr_n, 0, sizeof(*pr_n));
93
94         // Do we have to initialize pr_n?
95
96         lc_list_add(&pr_n->node_list, &_ext_grs_NODE_LIST(pr_g, get_op_code(op), get_mode_modecode(mode)));
97
98         // Do we have to call this?
99         // (_ext_grs_N_INSTANCES(pr_g, get_op_code(op), get_mode_modecode(mode)))++;
100
101         return(new_node);
102 }
103
104
105
106
107 /* __  __       _ _      _       _     _
108   |  \/  |_   _| | |_   / \   __| | __| |
109   | |\/| | | | | | __| / _ \ / _` |/ _` |
110   | |  | | |_| | | |_ / ___ \ (_| | (_| |
111   |_|  |_|\__,_|_|\__/_/   \_\__,_|\__,_| */
112
113 /************************************************************************
114  * Returns 1 if the given node is a MultipleAdd operation
115  ************************************************************************/
116
117 int is_MultipleAdd(ir_node *n)
118 {
119         return(get_irn_opcode(n) == iro_MultipleAdd);
120 }
121
122
123
124 /************************************************************************
125  * Returns 1 if the 2 MultipeAdd nodes have the same base addresses
126  * but different offsets > size -> no alias
127  * 0 otherwise -> may alias
128  ************************************************************************/
129
130 ir_alias_relation get_multadd_alias_relation(ir_node *n1, ir_node *n2)
131 {
132 #if 1
133         int i, offset_diff, same_base = 1, pos1, pos2, summands_not_equal = 0, size;
134         ir_node *const1 = NULL, *const2 = NULL, *base1 = NULL, *base2 = NULL, *ma1, *ma2;
135         ir_mode *mode1, *mode2;
136
137
138         switch(get_irn_opcode(n1))
139         {
140                 case iro_Store: ma1 = get_Store_ptr(n1); mode1 = get_irn_mode(get_Store_value(n1)); break;
141                 case iro_Load:  ma1 = get_Load_ptr(n1);  mode1 = get_Load_mode(n1); /*mode_F;*/ /* Hack */ break;               // TODO: Get Load mode
142                 default: return(no_alias);
143         }
144
145         switch(get_irn_opcode(n2))
146         {
147                 case iro_Store: ma2 = get_Store_ptr(n2); mode2 = get_irn_mode(get_Store_value(n1)); break;
148                 case iro_Load:  ma2 = get_Load_ptr(n2);  mode2 = get_Load_mode(n1); /*mode_F;*/ /* Hack */ break;                // TODO: Get LOAD mode
149                 default: return(no_alias);
150         }
151
152         assert(is_MultipleAdd(ma1) && is_MultipleAdd(ma2));
153
154         size = MAX(get_mode_size_bytes(mode1), get_mode_size_bytes(mode2));
155
156         // Different number of summands. Return "may alias"
157         // Rethink. If they contain different Sel's or restrict pointers
158         if(get_irn_arity(ma1) != get_irn_arity(ma2))
159                 return(may_alias);
160
161         // Since MultipleAdd ins are ordered, the constant value has to be in_0 in both cases
162         const1 = get_irn_n(ma1, 0);
163         const2 = get_irn_n(ma2, 0);
164         if(!is_Const(const1) && !is_Const(const2))
165                 return(may_alias);
166
167         offset_diff = abs(get_tarval_long(get_Const_tarval(const1)) - get_tarval_long(get_Const_tarval(const2)));
168
169         // Go through both in-arrays simultaneously and search for the base pointers
170         // Also check the rest of the ins for equalness
171
172         for(pos1 = 1, pos2 = 1; pos1 < get_irn_arity(ma1) && pos2 <  get_irn_arity(ma1); )
173         {
174                 ir_node *n1, *n2;
175
176                 if((n1 = get_irn_n(ma1, pos1)) == (n2 = get_irn_n(ma2, pos2)))
177                 {
178                         pos1++;
179                         pos2++;
180                         continue;
181                 }
182
183                 summands_not_equal = 1;
184
185                 n1 = get_irn_n(ma1, pos1);
186                 n2 = get_irn_n(ma2, pos2);
187
188                 // Look if we have the base pointer
189                 if((get_irn_opcode(n1) == iro_Proj || get_irn_opcode(n1) == iro_Sel))
190                 {
191                         assert(base1 == NULL);
192                         base1 = n1;
193                         pos1++;
194                 }
195
196                 if((get_irn_opcode(n2) == iro_Proj || get_irn_opcode(n2) == iro_Sel))
197                 {
198                         assert(base2 == NULL);
199                         base2 = n2;
200                         pos2++;
201                 }
202         }
203
204         /*if(summands_not_equal)
205                 return(may_alias); */
206
207         if(base1 == NULL || base2 == NULL)
208         {
209                 if(!summands_not_equal)
210                 {
211                         // Summands are exaclty the same (including the base) so check the constant
212                         if(offset_diff < size)
213                                 return(sure_alias);  // Offsets are overlapping
214                         return(no_alias);                // Offsets are not overlapping
215                 }
216                 else
217                 {
218                         // Summands not the same and no (or just 1) base found. Bad luck, bail out
219                         return(may_alias);
220                 }
221         }
222         else
223         {
224                 // Summands are different, but 2 bases were found. check them:
225                 // Alias relation depends on the alias relation of the base addresses
226                 assert(base1 != NULL && base2 != NULL && "We should have found 2 bases!");
227                 return(get_alias_relation(get_irn_irg(base1), base1, mode_F, base2, mode_F));
228         }
229 #else
230         return(may_alias);
231 #endif
232 }
233
234
235
236 /*__     ______            _
237   \ \   / /  _ \ _ __ ___ (_)
238    \ \ / /| |_) | '__/ _ \| |
239     \ V / |  __/| | | (_) | |
240      \_/  |_|   |_|  \___// |
241                         |__/ */
242
243 /************************************************************************
244  * Gets and sets the vproj number
245  ************************************************************************/
246
247 int get_VProj_proj(ir_node *node)
248 {
249         int *pa = (int *) get_irn_generic_attr(node);
250         return *pa;
251 }
252
253 void set_VProj_proj(ir_node *node, int proj)
254 {
255         int *pa = get_irn_generic_attr(node);
256         *pa = proj;
257 }
258
259 ir_opcode get_VProj_op()
260 {
261         return(iro_VProj);
262 }