FreeBASIC  0.91.0
ast-optimize.bas
Go to the documentation of this file.
1 '' AST optimizations
2 ''
3 '' chng: sep/2004 written [v1ctor]
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "ir.bi"
9 #include once "rtl.bi"
10 #include once "ast.bi"
11 #include once "hlp.bi"
12 
13 
14 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
15 '' constant folding optimizations
16 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
17 
18 sub hOptConstRemNeg( byval n as ASTNODE ptr )
19 
20  dim as ASTNODE ptr l = any, r = any, ll = any
21 
22  '' walk
23  l = n->l
24  if( l <> NULL ) then
26  end if
27 
28  r = n->r
29  if( r <> NULL ) then
30  hOptConstRemNeg( r )
31  end if
32 
33  ''
34  '' -var + const -> const - var
35  ''
36  '' BOP(+) BOP(-)
37  '' / \ / \
38  '' UOP(-) CONST -> CONST VAR
39  '' /
40  '' VAR
41  ''
42 
43  if( astIsBOP( n, AST_OP_ADD ) ) then
44  l = n->l
45  r = n->r
46  if( astIsUOP( l, AST_OP_NEG ) and astIsCONST( r ) ) then
47  ll = n->l->l
48  if( astIsVAR( ll ) ) then
49  '' BOP(+) -> BOP(-)
50  n->op.op = AST_OP_SUB
51  n->l = r
52  n->r = ll
53  astDelNode( l )
54  end if
55  end if
56  end if
57 
58 end sub
59 
60 function hConstAccumADDSUB _
61  ( _
62  byval n as ASTNODE ptr, _
63  byref accumval as ASTNODE ptr, _
64  byval sign as integer _
65  ) as ASTNODE ptr
66 
67  dim as ASTNODE ptr l = any, r = any
68  dim as integer dtype = any, o = any, rsign = any
69 
70  if( n = NULL ) then
71  return NULL
72  end if
73 
74  if( n->class <> AST_NODECLASS_BOP ) then
75  return n
76  end if
77 
78  o = n->op.op
79 
80  select case o
81  case AST_OP_ADD, AST_OP_SUB
82  l = n->l
83  r = n->r
84 
85  '' Inverse operation (+ vs. -) for rhs tree of '-' BOPs
86  if( o = AST_OP_SUB ) then
87  rsign = -sign
88  else
89  rsign = sign
90  end if
91 
92  if( astIsCONST( r ) ) then
93  '' re-using 'r'
94  if( accumval ) then
95  '' Do inverse op if inside the rhs tree of a '-' BOP
96  if( rsign < 0 ) then
97  if( o = AST_OP_ADD ) then
98  o = AST_OP_SUB
99  else
100  o = AST_OP_ADD
101  end if
102  end if
103  accumval = astNewBOP( o, accumval, r )
104  else
105  accumval = r
106 
107  '' Negate if inside the rhs of a '-' BOP
108  if( rsign < 0 ) then
109  accumval = astNewUOP( AST_OP_NEG, accumval )
110  end if
111  end if
112 
113  '' Delete the BOP node, while 'l' and 'r' are re-used
114  astDelNode( n )
115 
116  '' 'l' becomes the new top node
117  n = hConstAccumADDSUB( l, accumval, sign )
118  else
119  '' walk
120  n->l = hConstAccumADDSUB( l, accumval, sign )
121  n->r = hConstAccumADDSUB( r, accumval, rsign )
122  end if
123  end select
124 
125  function = n
126 end function
127 
128 '':::::
129 function hConstAccumMUL _
130  ( _
131  byval n as ASTNODE ptr, _
132  byref accumval as ASTNODE ptr _
133  ) as ASTNODE ptr
134 
135  dim as ASTNODE ptr l = any, r = any
136  dim as integer dtype = any
137 
138  if( n = NULL ) then
139  return NULL
140  end if
141 
142  if( astIsBOP( n, AST_OP_MUL ) ) then
143  l = n->l
144  r = n->r
145 
146  if( astIsCONST( r ) ) then
147  '' re-using 'r'
148  if( accumval ) then
149  accumval = astNewBOP( AST_OP_MUL, accumval, r )
150  else
151  accumval = r
152  end if
153 
154  '' Delete the BOP node, while 'l' and 'r' are re-used
155  astDelNode( n )
156 
157  '' 'l' becomes the new top node
158  n = hConstAccumMUL( l, accumval )
159  else
160  '' walk
161  n->l = hConstAccumMUL( l, accumval )
162  n->r = hConstAccumMUL( r, accumval )
163  end if
164  end if
165 
166  function = n
167 end function
168 
169 function hOptConstAccum1( byval n as ASTNODE ptr ) as ASTNODE ptr
170  dim as ASTNODE ptr l = any, r = any, accumval = any
171  dim as integer o = any
172 
173  '' walk
174  if( n->l ) then
175  n->l = hOptConstAccum1( n->l )
176  end if
177 
178  if( n->r ) then
179  n->r = hOptConstAccum1( n->r )
180  end if
181 
182  '' check any ADD|SUB|MUL BOP node with a constant at the right leaf and
183  '' then begin accumulating the other constants at the nodes below the
184  '' current, deleting any constant leaf that was added
185  '' (this will handle for ex. a+1+b+2-3, that will become a+b
186  if( n->class = AST_NODECLASS_BOP ) then
187  r = n->r
188  if( astIsCONST( r ) ) then
189  accumval = NULL
190  o = n->op.op
191 
192  select case( o )
193  case AST_OP_ADD, AST_OP_SUB
194  n = hConstAccumADDSUB( n, accumval, 1 )
195 
196  '' We checked astIsCONST( r ) above, so we'll always have an accumulated value here,
197  '' but just for safety...
198  if( accumval ) then
199  '' (shouldn't pass hConstAccumADDSUB() as argument to astNewBOP() directly,
200  '' because that could cause problems due to argument evaluation order)
201  n = astNewBOP( o, n, accumval )
202  end if
203 
204  case AST_OP_MUL
205  n = hConstAccumMUL( n, accumval )
206  if( accumval ) then
207  n = astNewBOP( AST_OP_MUL, n, accumval )
208  end if
209 
210  end select
211  end if
212  end if
213 
214  function = n
215 end function
216 
217 function hOptConstAccum2( byval n as ASTNODE ptr ) as ASTNODE ptr
218  dim as ASTNODE ptr l = any, r = any, accumval = any
219 
220  '' walk
221  if( n->l ) then
222  n->l = hOptConstAccum2( n->l )
223  end if
224 
225  if( n->r ) then
226  n->r = hOptConstAccum2( n->r )
227  end if
228 
229  '' check any ADD|SUB|MUL BOP node and then go to child leafs accumulating
230  '' any constants found there, deleting those nodes and then add the
231  '' result to a new node, at right side of the current one
232  '' (this will handle for ex. a+1+(b+2)+(c+3), that will become a+b+c+6)
233  if( n->class = AST_NODECLASS_BOP ) then
234  accumval = NULL
235 
236  select case n->op.op
237  case AST_OP_ADD
238  '' don't mess with strings..
239  select case as const astGetDataType( n )
240  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
241  FB_DATATYPE_WCHAR
242 
243  case else
244  n = hConstAccumADDSUB( n, accumval, 1 )
245  if( accumval ) then
246  n = astNewBOP( AST_OP_ADD, n, accumval )
247  end if
248  end select
249 
250  case AST_OP_MUL
251  n = hConstAccumMUL( n, accumval )
252  if( accumval ) then
253  n = astNewBOP( AST_OP_MUL, n, accumval )
254  end if
255 
256  end select
257  end if
258 
259  function = n
260 end function
261 
262 function hConstDistMUL _
263  ( _
264  byval n as ASTNODE ptr, _
265  byref accumval as ASTNODE ptr _
266  ) as ASTNODE ptr
267 
268  dim as ASTNODE ptr l = any, r = any
269  dim as integer dtype = any
270 
271  if( n = NULL ) then
272  return NULL
273  end if
274 
275  if( astIsBOP( n, AST_OP_ADD ) ) then
276  l = n->l
277  r = n->r
278 
279  if( astIsCONST( r ) ) then
280  if( accumval ) then
281  accumval = astNewBOP( AST_OP_ADD, accumval, r )
282  else
283  accumval = r
284  end if
285 
286  '' Delete the BOP node, while 'l' and 'r' are re-used
287  astDelNode( n )
288 
289  '' 'l' becomes the new top node
290  n = hConstDistMUL( l, accumval )
291  else
292  n->l = hConstDistMUL( l, accumval )
293  n->r = hConstDistMUL( r, accumval )
294  end if
295  end if
296 
297  function = n
298 end function
299 
300 function hOptConstDistMUL( byval n as ASTNODE ptr ) as ASTNODE ptr
301  dim as ASTNODE ptr accumval = any
302 
303  if( n = NULL ) then
304  return NULL
305  end if
306 
307  '' walk, bottom-up, to optimize children first, potentially making the
308  '' transformation possible here.
309  if( n->l ) then
310  n->l = hOptConstDistMUL( n->l )
311  end if
312 
313  if( n->r ) then
314  n->r = hOptConstDistMUL( n->r )
315  end if
316 
317  ''
318  '' Multiplication is distributive, i.e.
319  ''
320  '' (a + b) * c
321  '' = a * c + b * c
322  ''
323  '' This optimization does exactly that transformation,
324  '' but only for constant summands:
325  ''
326  '' (a + 3 + b) * 2
327  '' = (a + b) * 2 + 3 * 2
328  '' = (a + b) * 2 + 6
329  ''
330  '' (1 + a + 2 + b) * 3
331  '' = (a + b) * 3 + (1 + 2) * 3
332  '' = (a + b) * 3 + 3 * 3
333  '' = (a + b) * 3 + 9
334  ''
335  '' i.e. constant summands are pulled out of the inner expression,
336  '' then multiplicated with the constant factor of the MUL, and then
337  '' that value is ADDed back on top. The MUL is left in to handle the
338  '' part of the expression with non-constant summands.
339  '' (We know there are non-constant summands, because any fully constant
340  '' ADD BOPs were precalculated by astNewBOP()'s constant folding)
341  ''
342  '' This transformation can open up further optimization possibilities,
343  '' for example, this:
344  '' (a * 2 + 3) * 2
345  '' = a * 2 * 2 + 3 * 2
346  '' = a * 2 * 2 + 6
347  '' will be turned into
348  '' = a * 4 + 6
349  '' by the constant accumulation optimizations.
350  ''
351  '' Or, as another example, this:
352  '' ((a + 1) * 2) * 3
353  '' = (a * 2 + 1 * 2) * 3
354  '' = (a * 2 + 2) * 3
355  '' allows for the same transformation to be applied again, as a result
356  '' of applying it the first time, to get:
357  '' = a * 2 * 3 + 2 * 3
358  '' = a * 2 * 3 + 6
359  '' which will be turned into
360  '' = a * 6 + 6
361  '' by the constant accumulation optimizations.
362  '' Applying this transformation repeatedly on the same tree however
363  '' can only work when walking the tree bottom-up.
364  ''
365 
366  '' 1. Check for a MUL BOP node with a CONST rhs (assuming astNewBOP()
367  '' swapped lhs/rhs if the CONST was on lhs, so only one thing has
368  '' to be checked here)
369  if( n->class = AST_NODECLASS_BOP ) then
370  if( astIsCONST( n->r ) ) then
371  if( n->op.op = AST_OP_MUL ) then
372  '' 2. Scan the lhs for ADD BOPs with CONST rhs (hConstDistMUL())
373  '' - Sums up the CONST summands of all such ADDs
374  '' - Removes these ADDs (possibly leaving in other non-const summands)
375  accumval = NULL
376  n->l = hConstDistMUL( n->l, accumval )
377 
378  if( accumval ) then
379  '' 3. Multiplicate the sum with the MUL's CONST rhs
380  accumval = astNewBOP( AST_OP_MUL, accumval, astCloneTree( n->r ) )
381 
382  '' 4. Use an ADD BOP to add the result on top
383  n = astNewBOP( AST_OP_ADD, n, accumval )
384  end if
385  end if
386  end if
387  end if
388 
389  function = n
390 end function
391 
392 sub hOptConstIdxMult( byval n as ASTNODE ptr )
393  dim as integer optimize = any, c = any
394  dim as ASTNODE ptr l = n->l
395 
396  ''
397  '' If top of tree = idx * lgt, and lgt is in the 1..9 range,
398  '' then the length multiplier can be put into ASTNODE.idx.mult,
399  '' allowing the x86 ASM emitter to generate better code.
400  ''
401  '' This only works if the multiplier is 1..9 and neither 6 nor 7,
402  '' see also hPrepOperand() and hGetIdxName().
403  ''
404 
405  if( astIsBOP(l, AST_OP_MUL ) ) then
406  dim as ASTNODE ptr lr = l->r
407  if( astIsCONST( lr ) ) then
408  '' ASM backend?
409  if( irGetOption( IR_OPT_ADDRCISC ) ) then
410  '' Check whether the constant is in usable range
411  '' (just casting to 32bit could break if 64bit
412  '' values are given)
413  c = astConstGetInt( lr )
414  if( (c >= 1) and (c <= 9) ) then
415  select case as const( c )
416  case 1, 2, 4, 8
417  '' The main multipliers supported by x86
418  optimize = TRUE
419 
420  case 3, 5, 9
421  '' The x86 ASM backend additionally supports 3, 5, 9,
422  '' but it's only possible if there isn't already an index
423  '' (that happens with local variables that use EBP plus an
424  '' index on each access already, x86 assumption)
425  optimize = TRUE
426  dim as FBSYMBOL ptr s = astGetSymbol( n->r )
427  if( symbIsParam( s ) ) then
428  optimize = FALSE
429  elseif( symbIsLocal( s ) ) then
430  if( symbIsStatic( s ) = FALSE ) then
431  optimize = FALSE
432  end if
433  end if
434 
435  case else
436  optimize = FALSE
437  end select
438 
439  if( optimize ) then
440  n->idx.mult = c
441 
442  '' relink
443  n->l = l->l
444 
445  '' del const node and the BOP itself
446  astDelNode( lr )
447  astDelNode( l )
448 
449  l = n->l
450  end if
451  end if
452  end if
453  end if
454  end if
455 
456  '' convert to integer if needed
457  if( (typeGetClass( astGetDataType( l ) ) <> FB_DATACLASS_INTEGER) or _
458  (typeGetSize( astGetDataType( l ) ) <> env.pointersize) ) then
459  n->l = astNewCONV( FB_DATATYPE_INTEGER, NULL, l )
460  end if
461 
462 end sub
463 
464 function astIncOffset _
465  ( _
466  byval n as ASTNODE ptr, _
467  byval ofs as longint _
468  ) as integer
469 
470  select case as const n->class
471  case AST_NODECLASS_VAR
472  n->var_.ofs += ofs
473  function = TRUE
474 
475  case AST_NODECLASS_IDX
476  n->idx.ofs += ofs
477  function = TRUE
478 
479  case AST_NODECLASS_DEREF
480  n->ptr.ofs += ofs
481  function = TRUE
482 
483  case AST_NODECLASS_LINK
484  if( n->link.ret_left ) then
485  function = astIncOffset( n->l, ofs )
486  else
487  function = astIncOffset( n->r, ofs )
488  end if
489 
490  case AST_NODECLASS_FIELD, AST_NODECLASS_IIF
491  function = astIncOffset( n->l, ofs )
492 
493  case AST_NODECLASS_CONV
494  '' There can be CONV nodes here, in cases like:
495  '' dim as integer i(0 to 1)
496  '' print *(@cast(long, i(0)) + offset)
497  ''
498  '' (when 1. the cast() is added because it's a different dtype,
499  '' and 2. the @ accepts the cast() because it's doconv = FALSE
500  '' because the dtypes are similar enough/have the same size,
501  '' and 3. the offset is <> 0)
502  ''
503  '' but also field access after upcasting of derived UDTs:
504  '' print cast(BaseUDT, udt).foo
505  '' if foo's offset is <> 0.
506 
507  if (n->cast.doconv = FALSE) then
508  function = astIncOffset( n->l, ofs )
509  else
510  function = FALSE
511  end if
512 
513  case else
514  function = FALSE
515  end select
516 
517 end function
518 
519 function hOptDerefAddr( byval n as ASTNODE ptr ) as ASTNODE ptr
520  dim as ASTNODE ptr l = n->l
521  dim as longint ofs = 0
522 
523  select case l->class
524  case AST_NODECLASS_OFFSET
525  '' newBOP() will optimize ofs + const nodes, but we can't use the full
526  '' ofs.ofs value because it has computed already the child's (var/idx) ofs
527  ofs = l->ofs.ofs - astGetOFFSETChildOfs( l->l )
528 
529  case AST_NODECLASS_ADDROF
530 
531  case else
532  return n
533  end select
534 
535  assert( astIsDEREF(n) )
536  ofs += n->ptr.ofs
537 
538  '' *(@[expr] + 0) -> [expr]
539  '' *(@[expr] + ofs) -> [expr+ofs]
540 
541  '' If the deref uses an <> 0 offset then try to include that into
542  '' any child var/idx/deref nodes. If that's not possible, then this
543  '' optimization can't be done.
544  '' Note: we must do this even if ofs = 0, to ensure it's ok to
545  '' do the astSetType() below.
546  if( astIncOffset( l->l, ofs ) = FALSE ) then
547  return n
548  end if
549 
550  dim as integer dtype = astGetFullType( n )
551  dim as FBSYMBOL ptr subtype = n->subtype
552 
553  astDelNode( n )
554  n = l->l
555  astDelNode( l )
556 
557  astSetType( n, dtype, subtype )
558 
559  function = n
560 end function
561 
562 function hOptConstIDX( byval n as ASTNODE ptr ) as ASTNODE ptr
563  dim as ASTNODE ptr l = any, r = any, accumval = any
564  dim as longint c = any
565 
566  if( n = NULL ) then
567  return NULL
568  end if
569 
570  '' walk
571  l = n->l
572  if( l <> NULL ) then
573  n->l = hOptConstIDX( l )
574  end if
575 
576  r = n->r
577  if( r <> NULL ) then
578  n->r = hOptConstIDX( r )
579  end if
580 
581  '' opt must be done in this order: addsub accum and then idx * lgt
582  select case n->class
583  case AST_NODECLASS_IDX, AST_NODECLASS_DEREF
584  if( n->l ) then
585  accumval = NULL
586  n->l = hConstAccumADDSUB( n->l, accumval, 1 )
587 
588  if( accumval ) then
589  c = astConstFlushToInt( accumval )
590  if( n->class = AST_NODECLASS_IDX ) then
591  n->idx.ofs += c * n->idx.mult
592  else
593  n->ptr.ofs += c
594  end if
595  end if
596 
597  '' remove l node if it's a const and add it to parent's offset
598  if( astIsCONST( n->l ) ) then
599  c = astConstFlushToInt( n->l )
600  n->l = NULL
601  if( n->class = AST_NODECLASS_IDX ) then
602  n->idx.ofs += c * n->idx.mult
603  else
604  n->ptr.ofs += c
605  end if
606  else
607  '' indexing?
608  if( n->class = AST_NODECLASS_IDX ) then
609  hOptConstIdxMult( n )
610  '' deref..
611  else
612  n = hOptDerefAddr( n )
613  end if
614  end if
615  end if
616  end select
617 
618  function = n
619 end function
620 
621 function hMergeNestedFIELDs( byval n as ASTNODE ptr ) as ASTNODE ptr
622  dim as ASTNODE ptr l = any
623 
624  if( n = NULL ) then
625  return NULL
626  end if
627 
628  n->l = hMergeNestedFIELDs( n->l )
629  n->r = hMergeNestedFIELDs( n->r )
630 
631  if( astIsFIELD( n ) ) then
632  l = n->l
633 
634  '' This is the pattern for field accesses:
635  ''
636  '' udt.field
637  ''
638  '' = *(@udt + offsetof(field))
639  ''
640  '' = FIELD( DEREF( BOP( +, ADDROF( udt ), offsetof(field) ) ) )
641  ''
642  ''
643  '' Nested field accesses will look like:
644  ''
645  '' udt.a.b
646  ''
647  '' = *(@udt.a + offsetof(b))
648  ''
649  '' FIELD
650  '' |
651  '' DEREF
652  '' |
653  '' + BOP
654  '' / \
655  '' ADDROF offsetof(b)
656  '' /
657  '' udt.a
658  ''
659  '' = *(@*(@udt + offsetof(a)) + offsetof(b))
660  ''
661  '' FIELD
662  '' |
663  '' DEREF
664  '' |
665  '' + BOP
666  '' / \
667  '' ADDROF offsetof(b) *2*
668  '' /
669  '' FIELD
670  '' |
671  '' DEREF
672  '' |
673  '' *1* + BOP
674  '' / \
675  '' ADDROF offsetof(a)
676  '' /
677  '' udt
678  ''
679  '' The extra ADDROF/DEREF cancel each other out, and by
680  '' removing the ADDROF/FIELD/DEREF combo, the whole tree
681  '' can be optimized to:
682  ''
683  '' = *(@udt + offsetof(a) + offsetof(b))
684  ''
685  '' FIELD
686  '' |
687  '' DEREF
688  '' |
689  '' + BOP
690  '' / \
691  '' *1* + BOP offsetof(b) *2*
692  '' / \
693  '' ADDROF offsetof(a)
694  '' /
695  '' udt
696  ''
697 
698  dim as ASTNODE ptr ll = l->l
699  '' Note: DEREF.l can be NULL in case it was dereferencing a constant
700  if( astIsDEREF( l ) and (ll <> NULL) ) then
701  if( ll->class = AST_NODECLASS_BOP ) then
702  assert( astIsBOP( ll, AST_OP_ADD ) )
703  dim as ASTNODE ptr lll = ll->l
704  if( lll->class = AST_NODECLASS_ADDROF ) then
705  dim as ASTNODE ptr llll = lll->l
706  if( astIsFIELD( llll ) ) then
707  dim as ASTNODE ptr lllll = llll->l
708  dim as ASTNODE ptr llllll = lllll->l
709  if( astIsDEREF( lllll ) and (llllll <> NULL) ) then
710  l->l = astNewBOP( AST_OP_ADD, llllll, ll->r )
711  astDelNode( ll )
712  astDelNode( lll )
713  astDelNode( llll )
714  astDelNode( lllll )
715  end if
716  end if
717  end if
718  end if
719  end if
720  end if
721 
722  function = n
723 end function
724 
725 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
726 '' arithmetic association optimizations
727 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
728 
729 '':::::
730 function hOptAssocADD _
731  ( _
732  byval n as ASTNODE ptr _
733  ) as ASTNODE ptr
734 
735  dim as ASTNODE ptr l = any, r = any, n_old = any
736  dim as integer op = any, rop = any
737 
738  if( n = NULL ) then
739  return NULL
740  end if
741 
742  '' convert a+(b+c) to a+b+c and a-(b-c) to a-b+c
743  if( n->class = AST_NODECLASS_BOP ) then
744  op = n->op.op
745  select case op
746  case AST_OP_ADD, AST_OP_SUB
747 
748  '' don't mess with strings..
749  select case astGetDataType( n )
750  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
751  FB_DATATYPE_WCHAR
752 
753  case else
754  r = n->r
755  if( r->class = AST_NODECLASS_BOP ) then
756  rop = r->op.op
757  select case rop
758  case AST_OP_ADD, AST_OP_SUB
759  if( op = AST_OP_SUB ) then
760  if( rop = AST_OP_SUB ) then
761  op = AST_OP_ADD
762  else
763  rop = AST_OP_SUB
764  end if
765  else
766  if( rop = AST_OP_SUB ) then
767  op = AST_OP_SUB
768  rop = AST_OP_ADD
769  end if
770  end if
771 
772  n_old = n
773 
774  '' n = (( n->l, r->l ), r->r)
775  n = astNewBOP( op, _
776  astNewBOP( rop, n->l, r->l ), _
777  r->r )
778 
779  astDelNode( r )
780  astDelNode( n_old )
781  end select
782  end if
783  end select
784 
785  end select
786  end if
787 
788  '' walk
789  l = n->l
790  if( l <> NULL ) then
791  n->l = hOptAssocADD( l )
792  end if
793 
794  r = n->r
795  if( r <> NULL ) then
796  n->r = hOptAssocADD( r )
797  end if
798 
799  function = n
800 
801 end function
802 
803 '':::::
804 function hOptAssocMUL _
805  ( _
806  byval n as ASTNODE ptr _
807  ) as ASTNODE ptr
808 
809  dim as ASTNODE ptr l = any, r = any, n_old = any
810 
811  if( n = NULL ) then
812  return NULL
813  end if
814 
815  '' convert a*(b*c) to a*b*c
816  if( astIsBOP( n, AST_OP_MUL ) ) then
817  r = n->r
818  if( astIsBOP( r, AST_OP_MUL ) ) then
819  n_old = n
820 
821  '' n = (( n->l, r->l ), r->r)
822  n = astNewBOP( AST_OP_MUL, _
823  astNewBOP( AST_OP_MUL, n->l, r->l ), _
824  r->r )
825 
826  astDelNode( r )
827  astDelNode( n_old )
828  end if
829  end if
830 
831  '' walk
832  l = n->l
833  if( l <> NULL ) then
834  n->l = hOptAssocMUL( l )
835  end if
836 
837  r = n->r
838  if( r <> NULL ) then
839  n->r = hOptAssocMUL( r )
840  end if
841 
842  function = n
843 
844 end function
845 
846 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
847 '' other optimizations
848 '':::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
849 
850 sub hDivToShift_Signed _
851  ( _
852  byval n as ASTNODE ptr, _
853  byval const_val as integer _
854  )
855 
856  dim as ASTNODE ptr l = any, l_cpy = any
857  dim as integer dtype = any, bits = any
858 
859  l = n->l
860 
861  '' !!!FIXME!!! while there's no common sub-expr elimination, only allow VAR nodes
862  if( l->class <> AST_NODECLASS_VAR ) then
863  exit sub
864  end if
865 
866  dtype = astGetFullType( l )
867 
868  bits = typeGetBits( dtype ) - 1
869  '' bytes are converted to int's..
870  if( bits = 7 ) then
871  bits = typeGetBits( FB_DATATYPE_INTEGER ) - 1
872  end if
873 
874  l_cpy = astCloneTree( l )
875 
876  if( const_val = 1 ) then
877  '' n + ( cunsg(n) shr bits )
878  n->l = astNewCONV( dtype, NULL, _
879  astNewBOP( AST_OP_ADD, _
880  l_cpy, _
881  astNewBOP( AST_OP_SHR, _
882  astNewCONV( typeToUnsigned( dtype ), NULL, l, AST_CONVOPT_SIGNCONV ), _
883  astNewCONSTi( bits ) ) ), _
884  AST_CONVOPT_SIGNCONV )
885  else
886  '' n + ( (n shr bits) and (1 shl const_val - 1) )
887  n->l = astNewCONV( dtype, NULL, _
888  astNewBOP( AST_OP_ADD, _
889  l_cpy, _
890  astNewBOP( AST_OP_AND, _
891  astNewBOP( AST_OP_SHR, _
892  l, _
893  astNewCONSTi( bits ) ), _
894  astNewCONSTi( 1 shl const_val - 1 ) ) ), _
895  AST_CONVOPT_SIGNCONV )
896  end if
897 
898  n->op.op = AST_OP_SHR
899  astConstGetInt( n->r ) = const_val
900 
901 end sub
902 
903 function hToPow2( byval v as ulongint ) as integer
904  '' Is it a power of 2? (2/4/8/16/32/...)
905  for i as integer = 1 to 63
906  if( v = (1ull shl i) ) then
907  '' return the exponent of the power of 2 (1/2/3/4/5/...)
908  return i
909  end if
910  next
911  function = 0
912 end function
913 
914 sub hOptToShift( byval n as ASTNODE ptr )
915  dim as ASTNODE ptr l = any, r = any
916  dim as integer op = any, exponent = any
917  dim as longint value = any
918 
919  if( n = NULL ) then
920  exit sub
921  end if
922 
923  '' convert ' a * pow2 imm' to 'a SHL pow2',
924  '' 'unsg(a) \ pow2 imm' to 'a SHR pow2',
925  '' 'sign(a) \ pow2 imm' to '((a SHR 31) + a) SAR pow2',
926  '' ' a MOD pow2 imm' to 'a AND pow2-1'
927  if( n->class = AST_NODECLASS_BOP ) then
928  op = n->op.op
929 
930  select case op
931  case AST_OP_MUL, AST_OP_INTDIV, AST_OP_MOD
932  r = n->r
933 
934  '' BOP result must be an integer, so no floats are involved
935  if( typeGetClass( n->dtype ) <> FB_DATACLASS_INTEGER ) then
936  exit select
937  end if
938 
939  '' The rhs must be an integer constant > 0
940  '' (doesn't matter whether it's signed or unsigned)
941  if( astIsCONST( r ) = FALSE ) then
942  exit select
943  end if
944  value = astConstGetInt( r )
945  if( (value = 0) or _
946  ((value < 0) and typeIsSigned( astGetFullType( r ) )) ) then
947  exit select
948  end if
949 
950  '' Get the exponent if it's a power of 2
951  exponent = hToPow2( value )
952  if( exponent <= 0 ) then
953  exit select
954  end if
955 
956  select case op
957  case AST_OP_MUL
958  if( exponent > typeGetBits( n->l->dtype ) ) then
959  exit select, select
960  end if
961 
962  n->op.op = AST_OP_SHL
963  astConstGetInt( r ) = exponent
964 
965  case AST_OP_INTDIV
966  if( exponent > typeGetBits( n->l->dtype ) ) then
967  exit select, select
968  end if
969 
970  if( typeIsSigned( n->l->dtype ) = FALSE ) then
971  n->op.op = AST_OP_SHR
972  astConstGetInt( r ) = exponent
973  else
974  hDivToShift_Signed( n, exponent )
975  end if
976 
977  case AST_OP_MOD
978  '' unsigned types only
979  if( typeIsSigned( astGetDataType( n->l ) ) ) then
980  exit select, select
981  end if
982 
983  n->op.op = AST_OP_AND
984  astConstGetInt( r ) -= 1
985  end select
986  end select
987  end if
988 
989  '' walk
990  l = n->l
991  if( l <> NULL ) then
992  hOptToShift( l )
993  end if
994 
995  r = n->r
996  if( r <> NULL ) then
997  hOptToShift( r )
998  end if
999 
1000 end sub
1001 
1002 ''::::
1003 function hOptNullOp _
1004  ( _
1005  byval n as ASTNODE ptr _
1006  ) as ASTNODE ptr
1007 
1008  dim as ASTNODE ptr l = any, r = any
1009  dim as integer op = any
1010  dim as longint v = any
1011  dim as integer keep_l = any, keep_r = any
1012 
1013  if( n = NULL ) then
1014  return NULL
1015  end if
1016 
1017  '' Eliminate nops in child nodes first, then perhaps we can eliminate
1018  '' the current (parent) one too.
1019  n->l = hOptNullOp( n->l )
1020  n->r = hOptNullOp( n->r )
1021 
1022  '' convert 'a * 0' to '0'**
1023  '' 'a MOD 1' to '0'*
1024  '' 'a MOD -1' to '0'*
1025  '' 'a * 1' to 'a'
1026  '' 'a \ 1' to 'a'
1027  '' 'a + 0' to 'a'
1028  '' 'a - 0' to 'a'
1029  '' 'a SHR 0' to 'a'
1030  '' 'a SHL 0' to 'a'
1031  '' 'a IMP -1' to '-1'*
1032  '' 'a OR -1' to '-1'*
1033  '' 'a OR 0' to 'a'
1034  '' 'a XOR 0' to 'a'
1035  '' 'a AND -1' to 'a'
1036  '' 'a AND 0' to '0'*
1037 
1038  '' '0 * a' to '0'*
1039  '' '0 \ a' to '0'*
1040  '' '0 MOD a' to '0'*
1041  '' '0 SHR a' to '0'*
1042  '' '0 SHL a' to '0'*
1043 
1044  ''* 'a' can't be deleted if it has side-effects
1045  ''** convert 'a * 0' to 'a AND 0' to optimize speed without changing side-effects
1046 
1047  if( n->class = AST_NODECLASS_BOP ) then
1048  op = n->op.op
1049  l = n->l
1050  r = n->r
1051 
1052  '' don't allow exprs with side-effects to be deleted
1053  keep_l = ( astIsClassOnTree( AST_NODECLASS_CALL, l ) <> NULL )
1054  keep_r = ( astIsClassOnTree( AST_NODECLASS_CALL, r ) <> NULL )
1055 
1056  if( typeGetClass( astGetDataType( n ) ) = FB_DATACLASS_INTEGER ) then
1057  if( astIsCONST( r ) ) then
1058  v = astConstGetInt( r )
1059 
1060  select case as const op
1061  case AST_OP_MUL
1062  if( v = 0 ) then
1063  if( keep_l = FALSE ) then
1064  astDelTree( l )
1065  astDelNode( n )
1066  return r
1067  else
1068  '' optimize '* 0' to 'AND 0'
1069  n->op.op = AST_OP_AND
1070  end if
1071  elseif( v = 1 ) then
1072  astDelNode( r )
1073  astDelNode( n )
1074  return l
1075  end if
1076 
1077  case AST_OP_MOD
1078  if( ( v = 1 ) or ( ( v = -1 ) and ( typeIsSigned( astGetDataType( r ) ) <> FALSE ) ) ) then
1079  if( keep_l = FALSE ) then
1080  astConstGetInt( r ) = 0
1081  astDelTree( l )
1082  astDelNode( n )
1083  return r
1084  end if
1085 
1086  end if
1087 
1088  case AST_OP_INTDIV
1089  if( v = 1 ) then
1090  astDelNode( r )
1091  astDelNode( n )
1092  return l
1093  end if
1094 
1095  case AST_OP_ADD, AST_OP_SUB, _
1096  AST_OP_SHR, AST_OP_SHL, _
1097  AST_OP_XOR
1098  if( v = 0 ) then
1099  astDelNode( r )
1100  astDelNode( n )
1101  return l
1102  end if
1103 
1104  case AST_OP_IMP
1105  if( v = -1 ) then
1106  if( keep_l = FALSE ) then
1107  astDelTree( l )
1108  astDelNode( n )
1109  return r
1110  end if
1111  end if
1112 
1113  case AST_OP_OR
1114  if( v = 0 ) then
1115  astDelNode( r )
1116  astDelNode( n )
1117  return l
1118  elseif( v = -1 ) then
1119  if( keep_l = FALSE ) then
1120  astDelTree( l )
1121  astDelNode( n )
1122  return r
1123  end if
1124  end if
1125 
1126  case AST_OP_AND
1127  if( v = -1 ) then
1128  astDelNode( r )
1129  astDelNode( n )
1130  return l
1131  elseif( v = 0 ) then
1132  if( keep_l = FALSE ) then
1133  astDelTree( l )
1134  astDelNode( n )
1135  return r
1136  end if
1137  end if
1138 
1139  end select
1140 
1141  elseif( astIsCONST( l ) ) then
1142  v = astConstGetInt( l )
1143 
1144  select case as const op
1145  case AST_OP_MUL, AST_OP_INTDIV, AST_OP_MOD, _
1146  AST_OP_SHR, AST_OP_SHL
1147  if( v = 0 ) then
1148  if( keep_r = FALSE ) then
1149  astDelTree( r )
1150  astDelNode( n )
1151  return l
1152  end if
1153  end if
1154 
1155  end select
1156  end if
1157  end if
1158  end if
1159 
1160  function = n
1161 end function
1162 
1163 ''::::
1164 function hOptLogic _
1165  ( _
1166  byval n as ASTNODE ptr _
1167  ) as ASTNODE ptr
1168 
1169  dim as ASTNODE ptr m = any
1170  dim as ASTNODE ptr l = any, r = any
1171  dim as integer op = any
1172  dim as longint v = any
1173 
1174  if( n = NULL ) then
1175  return n
1176  end if
1177 
1178  '' walk
1179  l = n->l
1180  if( l <> NULL ) then
1181  n->l = hOptLogic( l )
1182  l = n->l
1183  end if
1184 
1185  r = n->r
1186  if( r <> NULL ) then
1187  n->r = hOptLogic( r )
1188  r = n->r
1189  end if
1190 
1191  if( typeGetClass( astGetDataType( n ) ) = FB_DATACLASS_INTEGER ) then
1192  if( astIsUOP( n, AST_OP_NOT ) ) then
1193  if( astIsUOP( l, AST_OP_NOT ) ) then
1194  '' convert NOT NOT x to x
1195  m = l->l
1196  astDelNode( l )
1197  astDelNode( n )
1198  n = hOptLogic( m )
1199  elseif( astIsBOP( l, AST_OP_XOR ) ) then
1200  if( typeGetClass( astGetDataType( n ) ) = FB_DATACLASS_INTEGER ) then
1201  if( astIsCONST( l->l ) ) then
1202  '' convert:
1203  '' not (const xor x) to (not const) xor x
1204  astConstGetInt( l->l ) = not astConstGetInt( l->l )
1205  astDelNode( n )
1206  n = hOptLogic( l )
1207  elseif( astIsCONST( l->r ) ) then
1208  '' convert:
1209  '' not (x xor const) to x xor (not const)
1210  astConstGetInt( l->r ) = not astConstGetInt( l->r )
1211  astDelNode( n )
1212  n = hOptLogic( l )
1213  end if
1214  end if
1215  end if
1216  elseif( n->class = AST_NODECLASS_BOP ) then
1217  if( typeGetClass( astGetDataType( n ) ) = FB_DATACLASS_INTEGER ) then
1218  op = n->op.op
1219  select case op
1220  case AST_OP_OR, AST_OP_AND, AST_OP_XOR
1221 
1222  if( op = AST_OP_AND ) then
1223  op = AST_OP_OR
1224  elseif( op = AST_OP_OR ) then
1225  op = AST_OP_AND
1226  end if
1227 
1228  '' convert:
1229  '' (not x) and (not y) to not (x or y)
1230  '' (not x) or (not y) to not (x and y)
1231  '' (not x) xor (not y) to x xor y
1232 
1233  '' (op) NOT (for AND/OR)
1234  '' / \ => |
1235  '' NOT NOT (op) (opposite for AND/OR)
1236  '' | | / \
1237  '' x y x y
1238 
1239  if( astIsUOP(l, AST_OP_NOT) and astIsUOP(r, AST_OP_NOT) ) then
1240 
1241  l = hOptLogic( l->l )
1242  r = hOptLogic( r->l )
1243 
1244  m = astNewBOP( op, l, r )
1245 
1246  if( op <> AST_OP_XOR ) then
1247  m = astNewUOP( AST_OP_NOT, m )
1248  end if
1249 
1250  astDelNode( n->l )
1251  astDelNode( n->r )
1252  astDelNode( n )
1253 
1254  n = m
1255 
1256  '' pull out NOTs inside BOPs involving constants to allow further optimization
1257  '' (removal of NOT NOT, etc.)
1258 
1259  '' also, XOR involving const and NOT expr can be reduced to NOT on the const
1260  '' (instead of the other expr) to allow compile-time evaluation
1261  '' since x XOR y is equivalent to (not x) XOR (not y)
1262 
1263  elseif( astIsCONST( l ) and astisUOP(r, AST_OP_NOT) ) then
1264  '' convert:
1265  '' const and (not x) to not ((not const) or x)
1266  '' const or (not x) to not ((not const) and x)
1267  '' const xor (not x) to (not const) xor x
1268 
1269  v = astConstGetInt( l )
1270  m = astNewBOP( op, l, r->l )
1271  astConstGetInt( l ) = not v
1272 
1273  if( op <> AST_OP_XOR ) then
1274  m = astNewUOP( AST_OP_NOT, m )
1275  end if
1276 
1277  astDelNode( r )
1278  astDelNode( n )
1279  n = m
1280 
1281  elseif( astIsConst( r ) and astIsUOP(l, AST_OP_NOT) ) then
1282  '' convert:
1283  '' (not x) and const to not (x or (not const))
1284  '' (not x) or const to not (x and (not const))
1285  '' (not x) xor const to x xor (not const)
1286 
1287  v = astConstGetInt( r )
1288  m = astNewBOP( op, l->l, r )
1289  astConstGetInt( r ) = not v
1290 
1291  if( op <> AST_OP_XOR ) then
1292  m = astNewUOP( AST_OP_NOT, m )
1293  end if
1294 
1295  astDelNode( l )
1296  astDelNode( n )
1297  n = m
1298 
1299  elseif( (op = AST_OP_XOR) and astIsUOP(l, AST_OP_NOT) ) then
1300  '' convert:
1301  '' (not x) xor y to not (x xor y)
1302  m = astNewUOP( AST_OP_NOT, n )
1303  n->l = l->l
1304  astDelNode( l )
1305  n = m
1306  elseif( (op = AST_OP_XOR) and astIsUOP(r, AST_OP_NOT) ) then
1307  '' convert:
1308  '' x xor (not y) to not (x xor y)
1309  m = astNewUOP( AST_OP_NOT, n)
1310  n->r = r->l
1311  astDelNode( r )
1312  n = m
1313  end if
1314  end select
1315  end if
1316  end if
1317  end if
1318 
1319  function = n
1320 end function
1321 
1322 function hDoOptRemConv( byval n as ASTNODE ptr ) as ASTNODE ptr
1323  dim as ASTNODE ptr l = any, r = any
1324  dim as integer dorem = any
1325 
1326  if( n = NULL ) then
1327  return NULL
1328  end if
1329 
1330  '' convert l{float} op cast(float, r{var}) to l op r
1331  ''
1332  '' For example:
1333  '' dim f as single, i as integer
1334  '' print f + cast( single, i )
1335  ''
1336  '' The cast can be optimized out, because the x86 FPU's fiadd, fisub,
1337  '' fimul, fidiv instructions can work with integer operands directly,
1338  '' so we don't need to convert integer to float first and then do
1339  '' regular float+float BOPs afterwards.
1340  ''
1341  '' Apparently these instructions only support 16bit and 32bit memory
1342  '' operands though, thus BYTEs and LONGINTs have to be disallowed below.
1343  ''
1344  '' This all is only useful for the ASM backend since it's making
1345  '' assumptions about the x86 FPU. For the other backends, we can aswell
1346  '' do the cast, ensure we're getting the behaviour we want, and let
1347  '' gcc/llvm worry about good code generation.
1348 
1349  if( n->class = AST_NODECLASS_BOP ) then
1350  select case astGetDataType( n )
1351  case FB_DATATYPE_SINGLE, FB_DATATYPE_DOUBLE
1352  r = n->r
1353  if( r->class = AST_NODECLASS_CONV ) then
1354  '' left node can't be a cast() too
1355  if( n->l->class <> AST_NODECLASS_CONV ) then
1356  select case astGetDataType( r )
1357  case FB_DATATYPE_SINGLE, FB_DATATYPE_DOUBLE
1358  l = r->l
1359 
1360  '' Note: should not skip noconv CASTs here,
1361  '' because it could be a sign conversion such as
1362  '' from integer VAR to uinteger. Without that CAST
1363  '' to unsigned, it would pass the signed check below,
1364  '' and then a signed operation would be done while
1365  '' an unsigned one was intended.
1366 
1367  '' Disallow BYTEs and LONGINTs
1368  select case( typeGetSize( astGetDataType( l ) ) )
1369  case 2, 4
1370  dorem = FALSE
1371 
1372  select case( l->class )
1373  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, _
1374  AST_NODECLASS_FIELD, AST_NODECLASS_DEREF
1375  '' can't be unsigned either
1376  if( typeIsSigned( astGetDataType( l ) ) ) then
1377  dorem = TRUE
1378  end if
1379  end select
1380 
1381  if( dorem ) then
1382  astDelNode( r )
1383  n->r = l
1384  end if
1385  end select
1386  end select
1387  end if
1388  end if
1389  end select
1390  end if
1391 
1392  '' walk
1393  n->l = hDoOptRemConv( n->l )
1394  n->r = hDoOptRemConv( n->r )
1395 
1396  function = n
1397 end function
1398 
1399 '':::::
1400 function hOptStrMultConcat _
1401  ( _
1402  byval lnk as ASTNODE ptr, _
1403  byval dst as ASTNODE ptr, _
1404  byval n as ASTNODE ptr, _
1405  byval is_wstr as integer _
1406  ) as ASTNODE ptr
1407 
1408  if( n = NULL ) then
1409  return NULL
1410  end if
1411 
1412  '' +
1413  '' / \ f(:=) --> f(+=) --> f(+=)
1414  '' + d => / \ / \ / \
1415  '' / \ a b a c a d
1416  '' b c
1417 
1418  '' lowest node first..
1419  if( n->l <> NULL ) then
1420  if( n->l->class = AST_NODECLASS_BOP ) then
1421  lnk = hOptStrMultConcat( lnk, dst, n->l, is_wstr )
1422  n->l = NULL
1423  end if
1424  end if
1425 
1426  '' concat?
1427  if( n->class = AST_NODECLASS_BOP ) then
1428  if( n->l <> NULL ) then
1429  '' first concatenation? do an assignment..
1430  if( lnk = NULL ) then
1431  if( is_wstr = FALSE ) then
1432  lnk = rtlStrAssign( astCloneTree( dst ), n->l )
1433  else
1434  lnk = rtlWstrAssign( astCloneTree( dst ), n->l )
1435  end if
1436  else
1437  if( is_wstr = FALSE ) then
1438  lnk = astNewLINK( lnk, _
1439  rtlStrConcatAssign( astCloneTree( dst ), _
1440  n->l ) )
1441  else
1442  lnk = astNewLINK( lnk, _
1444  n->l ) )
1445  end if
1446  end if
1447  end if
1448 
1449  if( n->r <> NULL ) then
1450  if( is_wstr = FALSE ) then
1451  lnk = astNewLINK( lnk, _
1452  rtlStrConcatAssign( astCloneTree( dst ), _
1453  n->r ) )
1454  else
1455  lnk = astNewLINK( lnk, _
1457  n->r ) )
1458  end if
1459  end if
1460 
1461  astDelNode( n )
1462 
1463  '' string..
1464  else
1465  if( lnk = NULL ) then
1466  if( is_wstr = FALSE ) then
1467  lnk = rtlStrAssign( astCloneTree( dst ), n )
1468  else
1469  lnk = rtlWstrAssign( astCloneTree( dst ), n )
1470  end if
1471  else
1472  if( is_wstr = FALSE ) then
1473  lnk = astNewLINK( lnk, _
1474  rtlStrConcatAssign( astCloneTree( dst ), _
1475  n ) )
1476  else
1477  lnk = astNewLINK( lnk, _
1479  n ) )
1480  end if
1481  end if
1482  end if
1483 
1484  function = lnk
1485 
1486 end function
1487 
1488 ''::::
1489 function hIsMultStrConcat _
1490  ( _
1491  byval l as ASTNODE ptr, _
1492  byval r as ASTNODE ptr _
1493  ) as integer
1494 
1495  dim as FBSYMBOL ptr sym = any
1496 
1497  function = FALSE
1498 
1499  if( r->class = AST_NODECLASS_BOP ) then
1500  select case l->class
1501  case AST_NODECLASS_VAR, AST_NODECLASS_IDX
1502  sym = astGetSymbol( l )
1503  if( sym <> NULL ) then
1504  if (symbIsParamBydescOrByref(sym) = FALSE) then
1505  function = (astIsSymbolOnTree( sym, r ) = FALSE)
1506  end if
1507  end if
1508 
1509  case AST_NODECLASS_FIELD, AST_NODECLASS_IIF
1510  select case l->l->class
1511  case AST_NODECLASS_VAR, AST_NODECLASS_IDX
1512 
1513  '' byref params would be AST_NODECLASS_DEREF
1514 
1515  sym = astGetSymbol( l )
1516  if( sym <> NULL ) then
1517  function = (astIsSymbolOnTree( sym, r ) = FALSE)
1518  end if
1519  end select
1520  end select
1521  end if
1522 
1523 end function
1524 
1525 function hOptStrAssignment _
1526  ( _
1527  byval n as ASTNODE ptr, _
1528  byval l as ASTNODE ptr, _
1529  byval r as ASTNODE ptr _
1530  ) as ASTNODE ptr
1531 
1532  dim as integer optimize = any, is_wstr = any
1533 
1534  optimize = FALSE
1535 
1536  '' is right side a bin operation?
1537  if( r->class = AST_NODECLASS_BOP ) then
1538  dim as FBSYMBOL ptr sym
1539 
1540  '' is left side a var?
1541  select case as const l->class
1542  case AST_NODECLASS_VAR, AST_NODECLASS_IDX
1543  '' !!!FIXME!!! can't include AST_NODECLASS_DEREF, unless -noaliasing is added
1544 
1545  if( astIsTreeEqual( l, r->l ) ) then
1546  sym = astGetSymbol( l )
1547  if( sym <> NULL ) then
1548  if (symbIsParamBydescOrByref(sym) = FALSE) then
1549  optimize = astIsSymbolOnTree( sym, r->r ) = FALSE
1550  end if
1551  end if
1552  end if
1553 
1554  case AST_NODECLASS_FIELD, AST_NODECLASS_IIF
1555  select case as const l->l->class
1556  case AST_NODECLASS_VAR, AST_NODECLASS_IDX
1557 
1558  if( astIsTreeEqual( l, r->l ) ) then
1559  sym = astGetSymbol( l )
1560  if( sym <> NULL ) then
1561  optimize = astIsSymbolOnTree( sym, r->r ) = FALSE
1562  end if
1563  end if
1564 
1565  end select
1566  end select
1567  end if
1568 
1569  is_wstr = ( astGetDataType( n ) = FB_DATATYPE_WCHAR )
1570 
1571  if( optimize ) then
1572  astDelNode( n )
1573  n = r
1574  astDelTree( l )
1575  l = n->l
1576  r = n->r
1577 
1578  if( hIsMultStrConcat( l, r ) ) then
1579  function = hOptStrMultConcat( l, l, r, is_wstr )
1580  else
1581  '' = f() -- concatassign
1582  '' / \ / \
1583  ''a + => a expr
1584  '' / \
1585  '' a expr
1586  if( is_wstr = FALSE ) then
1587  function = rtlStrConcatAssign( l, astUpdStrConcat( r ) )
1588  else
1589  function = rtlWstrConcatAssign( l, astUpdStrConcat( r ) )
1590  end if
1591  end if
1592  else
1593  '' convert "a = b + c + d" to "a = b: a += c: a += d"
1594  if( hIsMultStrConcat( l, r ) ) then
1595  function = hOptStrMultConcat( NULL, l, r, is_wstr )
1596  else
1597  '' = f() -- assign
1598  '' / \ / \
1599  ''a + => a f() -- concat (done by UpdStrConcat)
1600  '' / \ / \
1601  '' b expr b expr
1602  if( is_wstr = FALSE ) then
1603  function = rtlStrAssign( l, astUpdStrConcat( r ) )
1604  else
1605  function = rtlWstrAssign( l, astUpdStrConcat( r ) )
1606  end if
1607  end if
1608  end if
1609 
1610  astDelNode( n )
1611 end function
1612 
1613 function astOptAssignment( byval n as ASTNODE ptr ) as ASTNODE ptr
1614  dim as ASTNODE ptr l = any, r = any
1615  dim as integer dtype = any, dclass = any
1616 
1617  function = n
1618 
1619  if( n = NULL ) then
1620  exit function
1621  end if
1622 
1623  '' try to convert "foo = foo op expr" to "foo op= expr" (including unary ops)
1624 
1625  select case n->class
1626  '' there's just one assignment per tree (always at top), so, just check this node
1627  case AST_NODECLASS_ASSIGN
1628 
1629  '' SelfBOP and TypeIniFlush will create links to emit trees
1630  case AST_NODECLASS_LINK, AST_NODECLASS_LOOP
1631  n->l = astOptAssignment( n->l )
1632  n->r = astOptAssignment( n->r )
1633  exit function
1634 
1635  case else
1636  exit function
1637  end select
1638 
1639  l = n->l
1640  r = n->r
1641 
1642  dtype = astGetFullType( n )
1643 
1644  '' strings?
1645  select case typeGet( dtype )
1646  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
1647  FB_DATATYPE_WCHAR
1648  return hOptStrAssignment( n, l, r )
1649  end select
1650 
1651  dclass = typeGetClass( dtype )
1652  if( dclass = FB_DATACLASS_INTEGER ) then
1653  if( irGetOption( IR_OPT_CPUSELFBOPS ) = FALSE ) then
1654  exit function
1655  end if
1656  else
1657  if( irGetOption( IR_OPT_FPUSELFBOPS ) = FALSE ) then
1658  '' try to optimize if a constant is being assigned to a float var
1659  if( astIsCONST( r ) ) then
1660  if( dclass = FB_DATACLASS_FPOINT ) then
1661  if( typeGetClass( astGetDataType( r ) ) <> FB_DATACLASS_FPOINT ) then
1662  n->r = astNewCONV( dtype, NULL, r )
1663  end if
1664  end if
1665  end if
1666 
1667  exit function
1668  end if
1669  end if
1670 
1671  '' can't be byte either, as BOP will do cint(byte) op cint(byte)
1672  if( typeGetSize( dtype ) = 1 ) then
1673  exit function
1674  end if
1675 
1676  '' is left side a var, idx or ptr?
1677 
1678  '' skip any casting if they won't do any conversion
1679  dim as ASTNODE ptr t = l
1680  if( l->class = AST_NODECLASS_CONV ) then
1681  if( l->cast.doconv = FALSE ) then
1682  t = l->l
1683  end if
1684  end if
1685 
1686  select case as const t->class
1687  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, AST_NODECLASS_DEREF
1688 
1689  case AST_NODECLASS_FIELD, AST_NODECLASS_IIF
1690  '' isn't it a bitfield?
1691  if( astGetDataType( t->l ) = FB_DATATYPE_BITFIELD ) then
1692  exit function
1693  end if
1694 
1695  case else
1696  exit function
1697  end select
1698 
1699  '' is right side an unary or binary operation?
1700  select case r->class
1701  case AST_NODECLASS_UOP
1702 
1703  case AST_NODECLASS_BOP
1704  '' can't be a relative op -- unless EMIT is changed to not assume
1705  '' the res operand is a reg
1706  select case as const r->op.op
1707  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE
1708  exit function
1709  end select
1710 
1711  case else
1712  exit function
1713  end select
1714 
1715  '' node result is an integer too?
1716  if( typeGetClass( astGetDataType( r ) ) <> FB_DATACLASS_INTEGER ) then
1717  exit function
1718  end if
1719 
1720  '' is the left child the same?
1721  if( astIsTreeEqual( l, r->l ) = FALSE ) then
1722  exit function
1723  end if
1724 
1725  '' delete assign node and alert UOP/BOP to not allocate a result (IR is aware)
1726  r->op.options and= not AST_OPOPT_ALLOCRES
1727 
1728  '' = o
1729  '' / \ / \
1730  ''d o => d expr
1731  '' / \
1732  '' d expr
1733 
1734  astDelNode( n )
1735  astDelTree( l )
1736 
1737  function = r
1738 
1739 end function
1740 
1741 ''::::
1742 function hOptSelfAssign _
1743  ( _
1744  byval n as ASTNODE ptr _
1745  ) as ASTNODE ptr
1746 
1747  '' = NOP
1748  '' / \ =>
1749  '' d d
1750 
1751  dim as ASTNODE ptr l = any, r = any
1752  dim as integer dtype = any, dclass = any
1753 
1754  function = n
1755 
1756  if( n = NULL ) then
1757  exit function
1758  end if
1759 
1760  if n->class <> AST_NODECLASS_ASSIGN then
1761  exit function
1762  end if
1763 
1764  l = n->l
1765  r = n->r
1766 
1767  if( astIsTreeEqual( l, r ) = FALSE ) then
1768  exit function
1769  end if
1770 
1771  astDelNode( n )
1772  astDelTree( l )
1773  astDelTree( r )
1774 
1775  function = astNewNOP( )
1776 end function
1777 
1778 ''::::
1779 function hOptSelfCompare _
1780  ( _
1781  byval n as ASTNODE ptr _
1782  ) as ASTNODE ptr
1783 
1784  dim as ASTNODE ptr l = any, r = any
1785  dim as integer dtype = any, dclass = any
1786 
1787  function = n
1788 
1789  if( n = NULL ) then
1790  exit function
1791  end if
1792 
1793  if n->class <> AST_NODECLASS_BOP then
1794  exit function
1795  end if
1796 
1797  l = n->l
1798  r = n->r
1799 
1800  if( astIsTreeEqual( l, r ) = FALSE ) then
1801  exit function
1802  end if
1803 
1804  dim as integer c
1805 
1806  select case as const n->op.op
1807  case AST_OP_EQ, AST_OP_LE, AST_OP_GE
1808  c = -1
1809  case AST_OP_NE, AST_OP_GT, AST_OP_LT
1810  c = 0
1811  case else
1812  exit function
1813  end select
1814 
1815  astDelNode( n )
1816  astDelTree( l )
1817  astDelTree( r )
1818 
1819  function = astNewCONSTi( c )
1820 end function
1821 
1822 '':::::
1823 function hOptReciprocal _
1824  ( _
1825  byval n as ASTNODE ptr _
1826  ) as ASTNODE ptr
1827 
1828  dim as ASTNODE ptr l = any, r = any
1829  dim as single v = Any
1830 
1831  if( n = NULL ) then
1832  return NULL
1833  end if
1834 
1835  '' first check if the op is a divide
1836  if( astIsBOP( n, AST_OP_DIV ) ) then
1837  l = n->l
1838  if( astIsCONST( l ) ) then
1839  if( (astGetDataType( l ) = FB_DATATYPE_SINGLE) andalso (astConstGetFloat( l ) = 1.0) ) then
1840  r = n->r
1841  if( astIsUOP( r, AST_OP_SQRT ) ) then
1842  '' change this to a rsqrt
1843  *n = *r
1844  n->class = AST_NODECLASS_UOP
1845  n->op.op = AST_OP_RSQRT
1846  astDelNode( r )
1847  astDelNode( l )
1848  elseif( astGetDataType( r ) = FB_DATATYPE_SINGLE ) then
1849  '' change this to a rcp
1850  astDelNode( n )
1851  n = astNewUOP( AST_OP_RCP, r )
1852  astDelNode( l )
1853  end if
1854  end if
1855  end if
1856  end if
1857 
1858  '' walk
1859  l = n->l
1860  if( l <> NULL ) then
1861  n->l = hOptReciprocal( l )
1862  end if
1863 
1864  r = n->r
1865  if( r <> NULL ) then
1866  n->r = hOptReciprocal( r )
1867  end if
1868 
1869  function = n
1870 
1871 end function
1872 
1873 function astOptimizeTree( byval n as ASTNODE ptr ) as ASTNODE ptr
1874  '' The order of calls below matters!
1875 
1876  var old_warn_convoverflow = ast.warn_convoverflow
1877  ast.warn_convoverflow = FALSE
1878 
1879  '' Optimize nested field accesses
1880  n = hMergeNestedFIELDs( n )
1881 
1882  n = hOptAssocADD( n )
1883 
1884  n = hOptAssocMUL( n )
1885 
1886  n = hOptConstDistMUL( n )
1887 
1888  n = hOptConstAccum1( n )
1889 
1890  n = hOptConstAccum2( n )
1891 
1892  hOptConstRemNeg( n )
1893 
1894  n = hOptConstIDX( n )
1895 
1896  hOptToShift( n )
1897 
1898  n = hOptLogic( n )
1899 
1900  n = hOptNullOp( n )
1901 
1902  n = hOptSelfAssign( n )
1903 
1904  n = hOptSelfCompare( n )
1905 
1906  if( (irGetOption( IR_OPT_FPUCONV ) = FALSE) and _
1907  (env.clopt.backend = FB_BACKEND_GAS) ) then
1908  n = hDoOptRemConv( n )
1909  end if
1910 
1911  if( irGetOption( IR_OPT_NOINLINEOPS ) = FALSE ) then
1912  if( env.clopt.fpmode = FB_FPMODE_FAST ) then
1913  n = hOptReciprocal( n )
1914  end if
1915  end if
1916 
1917  ast.warn_convoverflow = old_warn_convoverflow
1918 
1919  function = n
1920 end function
1921