1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "gg.h"
6
7 static void subnode(Node *nr, Node *ni, Node *nc);
8 static void minus(Node *nl, Node *res);
9 void complexminus(Node*, Node*);
10 void complexadd(int op, Node*, Node*, Node*);
11 void complexmul(Node*, Node*, Node*);
12
13 #define CASE(a,b) (((a)<<16)|((b)<<0))
14
15 static int
16 overlap(Node *f, Node *t)
17 {
18 // check whether f and t could be overlapping stack references.
19 // not exact, because it's hard to check for the stack register
20 // in portable code. close enough: worst case we will allocate
21 // an extra temporary and the registerizer will clean it up.
22 return f->op == OINDREG &&
23 t->op == OINDREG &&
24 f->xoffset+f->type->width >= t->xoffset &&
25 t->xoffset+t->type->width >= f->xoffset;
26 }
27
28 /*
29 * generate:
30 * res = n;
31 * simplifies and calls gmove.
32 */
33 void
34 complexmove(Node *f, Node *t)
35 {
36 int ft, tt;
37 Node n1, n2, n3, n4;
38
39 if(debug['g']) {
40 dump("\ncomplexmove-f", f);
41 dump("complexmove-t", t);
42 }
43
44 if(!t->addable)
45 fatal("complexmove: to not addable");
46
47 ft = simsimtype(f->type);
48 tt = simsimtype(t->type);
49 switch(CASE(ft,tt)) {
50
51 default:
52 fatal("complexmove: unknown conversion: %T -> %T\n",
53 f->type, t->type);
54
55 case CASE(TCOMPLEX64,TCOMPLEX64):
56 case CASE(TCOMPLEX64,TCOMPLEX128):
57 case CASE(TCOMPLEX128,TCOMPLEX64):
58 case CASE(TCOMPLEX128,TCOMPLEX128):
59 // complex to complex move/convert.
60 // make f addable.
61 // also use temporary if possible stack overlap.
62 if(!f->addable || overlap(f, t)) {
63 tempname(&n1, f->type);
64 complexmove(f, &n1);
65 f = &n1;
66 }
67
68 subnode(&n1, &n2, f);
69 subnode(&n3, &n4, t);
70
71 cgen(&n1, &n3);
72 cgen(&n2, &n4);
73 break;
74 }
75 }
76
77 int
78 complexop(Node *n, Node *res)
79 {
80 if(n != N && n->type != T)
81 if(iscomplex[n->type->etype]) {
82 goto maybe;
83 }
84 if(res != N && res->type != T)
85 if(iscomplex[res->type->etype]) {
86 goto maybe;
87 }
88
89 if(n->op == OREAL || n->op == OIMAG)
90 goto yes;
91
92 goto no;
93
94 maybe:
95 switch(n->op) {
96 case OCONV: // implemented ops
97 case OADD:
98 case OSUB:
99 case OMUL:
100 case OMINUS:
101 case OCOMPLEX:
102 case OREAL:
103 case OIMAG:
104 goto yes;
105
106 case ODOT:
107 case ODOTPTR:
108 case OINDEX:
109 case OIND:
110 case ONAME:
111 goto yes;
112 }
113
114 no:
115 //dump("\ncomplex-no", n);
116 return 0;
117 yes:
118 //dump("\ncomplex-yes", n);
119 return 1;
120 }
121
122 void
123 complexgen(Node *n, Node *res)
124 {
125 Node *nl, *nr;
126 Node tnl, tnr;
127 Node n1, n2, tmp;
128 int tl, tr;
129
130 if(debug['g']) {
131 dump("\ncomplexgen-n", n);
132 dump("complexgen-res", res);
133 }
134
135 // pick off float/complex opcodes
136 switch(n->op) {
137 case OCOMPLEX:
138 if(res->addable) {
139 subnode(&n1, &n2, res);
140 tempname(&tmp, n1.type);
141 cgen(n->left, &tmp);
142 cgen(n->right, &n2);
143 cgen(&tmp, &n1);
144 return;
145 }
146 break;
147
148 case OREAL:
149 case OIMAG:
150 nl = n->left;
151 if(!nl->addable) {
152 tempname(&tmp, nl->type);
153 complexgen(nl, &tmp);
154 nl = &tmp;
155 }
156 subnode(&n1, &n2, nl);
157 if(n->op == OREAL) {
158 cgen(&n1, res);
159 return;
160 }
161 cgen(&n2, res);
162 return;
163 }
164
165 // perform conversion from n to res
166 tl = simsimtype(res->type);
167 tl = cplxsubtype(tl);
168 tr = simsimtype(n->type);
169 tr = cplxsubtype(tr);
170 if(tl != tr) {
171 if(!n->addable) {
172 tempname(&n1, n->type);
173 complexmove(n, &n1);
174 n = &n1;
175 }
176 complexmove(n, res);
177 return;
178 }
179
180 if(!res->addable) {
181 igen(res, &n1, N);
182 cgen(n, &n1);
183 regfree(&n1);
184 return;
185 }
186 if(n->addable) {
187 complexmove(n, res);
188 return;
189 }
190
191 switch(n->op) {
192 default:
193 dump("complexgen: unknown op", n);
194 fatal("complexgen: unknown op %O", n->op);
195
196 case ODOT:
197 case ODOTPTR:
198 case OINDEX:
199 case OIND:
200 case ONAME: // PHEAP or PPARAMREF var
201 case OCALLFUNC:
202 igen(n, &n1, res);
203 complexmove(&n1, res);
204 regfree(&n1);
205 return;
206
207 case OCONV:
208 case OADD:
209 case OSUB:
210 case OMUL:
211 case OMINUS:
212 case OCOMPLEX:
213 case OREAL:
214 case OIMAG:
215 break;
216 }
217
218 nl = n->left;
219 if(nl == N)
220 return;
221 nr = n->right;
222
223 // make both sides addable in ullman order
224 if(nr != N) {
225 if(nl->ullman > nr->ullman && !nl->addable) {
226 tempname(&tnl, nl->type);
227 cgen(nl, &tnl);
228 nl = &tnl;
229 }
230 if(!nr->addable) {
231 tempname(&tnr, nr->type);
232 cgen(nr, &tnr);
233 nr = &tnr;
234 }
235 }
236 if(!nl->addable) {
237 tempname(&tnl, nl->type);
238 cgen(nl, &tnl);
239 nl = &tnl;
240 }
241
242 switch(n->op) {
243 default:
244 fatal("complexgen: unknown op %O", n->op);
245 break;
246
247 case OCONV:
248 complexmove(nl, res);
249 break;
250
251 case OMINUS:
252 complexminus(nl, res);
253 break;
254
255 case OADD:
256 case OSUB:
257 complexadd(n->op, nl, nr, res);
258 break;
259
260 case OMUL:
261 complexmul(nl, nr, res);
262 break;
263 }
264 }
265
266 void
267 complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
268 {
269 Node tnl, tnr;
270 Node n1, n2, n3, n4;
271 Node na, nb, nc;
272
273 // make both sides addable in ullman order
274 if(nr != N) {
275 if(nl->ullman > nr->ullman && !nl->addable) {
276 tempname(&tnl, nl->type);
277 cgen(nl, &tnl);
278 nl = &tnl;
279 }
280 if(!nr->addable) {
281 tempname(&tnr, nr->type);
282 cgen(nr, &tnr);
283 nr = &tnr;
284 }
285 }
286 if(!nl->addable) {
287 tempname(&tnl, nl->type);
288 cgen(nl, &tnl);
289 nl = &tnl;
290 }
291
292 // build tree
293 // real(l) == real(r) && imag(l) == imag(r)
294
295 subnode(&n1, &n2, nl);
296 subnode(&n3, &n4, nr);
297
298 memset(&na, 0, sizeof(na));
299 na.op = OANDAND;
300 na.left = &nb;
301 na.right = &nc;
302 na.type = types[TBOOL];
303
304 memset(&nb, 0, sizeof(na));
305 nb.op = OEQ;
306 nb.left = &n1;
307 nb.right = &n3;
308 nb.type = types[TBOOL];
309
310 memset(&nc, 0, sizeof(na));
311 nc.op = OEQ;
312 nc.left = &n2;
313 nc.right = &n4;
314 nc.type = types[TBOOL];
315
316 if(op == ONE)
317 true = !true;
318
319 bgen(&na, true, to);
320 }
321
322 void
323 nodfconst(Node *n, Type *t, Mpflt* fval)
324 {
325 memset(n, 0, sizeof(*n));
326 n->op = OLITERAL;
327 n->addable = 1;
328 ullmancalc(n);
329 n->val.u.fval = fval;
330 n->val.ctype = CTFLT;
331 n->type = t;
332
333 if(!isfloat[t->etype])
334 fatal("nodfconst: bad type %T", t);
335 }
336
337 // break addable nc-complex into nr-real and ni-imaginary
338 static void
339 subnode(Node *nr, Node *ni, Node *nc)
340 {
341 int tc;
342 Type *t;
343
344 if(!nc->addable)
345 fatal("subnode not addable");
346
347 tc = simsimtype(nc->type);
348 tc = cplxsubtype(tc);
349 t = types[tc];
350
351 if(nc->op == OLITERAL) {
352 nodfconst(nr, t, &nc->val.u.cval->real);
353 nodfconst(ni, t, &nc->val.u.cval->imag);
354 return;
355 }
356
357 *nr = *nc;
358 nr->type = t;
359
360 *ni = *nc;
361 ni->type = t;
362 ni->xoffset += t->width;
363 }
364
365 // generate code res = -nl
366 static void
367 minus(Node *nl, Node *res)
368 {
369 Node ra;
370
371 memset(&ra, 0, sizeof(ra));
372 ra.op = OMINUS;
373 ra.left = nl;
374 ra.type = nl->type;
375 cgen(&ra, res);
376 }
377
378 // build and execute tree
379 // real(res) = -real(nl)
380 // imag(res) = -imag(nl)
381 void
382 complexminus(Node *nl, Node *res)
383 {
384 Node n1, n2, n5, n6;
385
386 subnode(&n1, &n2, nl);
387 subnode(&n5, &n6, res);
388
389 minus(&n1, &n5);
390 minus(&n2, &n6);
391 }
392
393
394 // build and execute tree
395 // real(res) = real(nl) op real(nr)
396 // imag(res) = imag(nl) op imag(nr)
397 void
398 complexadd(int op, Node *nl, Node *nr, Node *res)
399 {
400 Node n1, n2, n3, n4, n5, n6;
401 Node ra;
402
403 subnode(&n1, &n2, nl);
404 subnode(&n3, &n4, nr);
405 subnode(&n5, &n6, res);
406
407 memset(&ra, 0, sizeof(ra));
408 ra.op = op;
409 ra.left = &n1;
410 ra.right = &n3;
411 ra.type = n1.type;
412 cgen(&ra, &n5);
413
414 memset(&ra, 0, sizeof(ra));
415 ra.op = op;
416 ra.left = &n2;
417 ra.right = &n4;
418 ra.type = n2.type;
419 cgen(&ra, &n6);
420 }
421
422 // build and execute tree
423 // tmp = real(nl)*real(nr) - imag(nl)*imag(nr)
424 // imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
425 // real(res) = tmp
426 void
427 complexmul(Node *nl, Node *nr, Node *res)
428 {
429 Node n1, n2, n3, n4, n5, n6;
430 Node rm1, rm2, ra, tmp;
431
432 subnode(&n1, &n2, nl);
433 subnode(&n3, &n4, nr);
434 subnode(&n5, &n6, res);
435 tempname(&tmp, n5.type);
436
437 // real part -> tmp
438 memset(&rm1, 0, sizeof(ra));
439 rm1.op = OMUL;
440 rm1.left = &n1;
441 rm1.right = &n3;
442 rm1.type = n1.type;
443
444 memset(&rm2, 0, sizeof(ra));
445 rm2.op = OMUL;
446 rm2.left = &n2;
447 rm2.right = &n4;
448 rm2.type = n2.type;
449
450 memset(&ra, 0, sizeof(ra));
451 ra.op = OSUB;
452 ra.left = &rm1;
453 ra.right = &rm2;
454 ra.type = rm1.type;
455 cgen(&ra, &tmp);
456
457 // imag part
458 memset(&rm1, 0, sizeof(ra));
459 rm1.op = OMUL;
460 rm1.left = &n1;
461 rm1.right = &n4;
462 rm1.type = n1.type;
463
464 memset(&rm2, 0, sizeof(ra));
465 rm2.op = OMUL;
466 rm2.left = &n2;
467 rm2.right = &n3;
468 rm2.type = n2.type;
469
470 memset(&ra, 0, sizeof(ra));
471 ra.op = OADD;
472 ra.left = &rm1;
473 ra.right = &rm2;
474 ra.type = rm1.type;
475 cgen(&ra, &n6);
476
477 // tmp ->real part
478 cgen(&tmp, &n5);
479 }