FreeBASIC  0.91.0
ast-node-bop.bas
Go to the documentation of this file.
1 '' AST binary operation nodes
2 '' l = left operand expression; r = right operand expression
3 ''
4 '' chng: sep/2004 written [v1ctor]
5 
6 
7 #include once "fb.bi"
8 #include once "fbint.bi"
9 #include once "dstr.bi"
10 #include once "ir.bi"
11 #include once "rtl.bi"
12 #include once "ast.bi"
13 
14 '':::::
15 function hStrLiteralConcat _
16  ( _
17  byval l as ASTNODE ptr, _
18  byval r as ASTNODE ptr _
19  ) as ASTNODE ptr
20 
21  dim as FBSYMBOL ptr s = any, ls = any, rs = any
22 
23  ls = astGetSymbol( l )
24  rs = astGetSymbol( r )
25 
26  '' new len = both strings' len less the 2 null-chars
27  s = symbAllocStrConst( *symbGetVarLitText( ls ) + *symbGetVarLitText( rs ), _
28  symbGetStrLen( ls ) - 1 + symbGetStrLen( rs ) - 1 )
29 
30  function = astNewVAR( s )
31 
32  astDelNode( r )
33  astDelNode( l )
34 
35 end function
36 
37 '':::::
38 function hWstrLiteralConcat _
39  ( _
40  byval l as ASTNODE ptr, _
41  byval r as ASTNODE ptr _
42  ) as ASTNODE ptr
43 
44  dim as FBSYMBOL ptr s = any, ls = any, rs = any
45 
46  ls = astGetSymbol( l )
47  rs = astGetSymbol( r )
48 
49  if( symbGetType( ls ) <> FB_DATATYPE_WCHAR ) then
50  '' new len = both strings' len less the 2 null-chars
51  s = symbAllocWstrConst( wstr( *symbGetVarLitText( ls ) ) + *symbGetVarLitTextW( rs ), _
52  symbGetStrLen( ls ) - 1 + symbGetWstrLen( rs ) - 1 )
53 
54  elseif( symbGetType( rs ) <> FB_DATATYPE_WCHAR ) then
55  s = symbAllocWstrConst( *symbGetVarLitTextW( ls ) + wstr( *symbGetVarLitText( rs ) ), _
56  symbGetWstrLen( ls ) - 1 + symbGetStrLen( rs ) - 1 )
57 
58  else
59  s = symbAllocWstrConst( *symbGetVarLitTextW( ls ) + *symbGetVarLitTextW( rs ), _
60  symbGetWstrLen( ls ) - 1 + symbGetWstrLen( rs ) - 1 )
61  end if
62 
63  function = astNewVAR( s )
64 
65  astDelNode( r )
66  astDelNode( l )
67 
68 end function
69 
70 '':::::
71 function hStrLiteralCompare _
72  ( _
73  byval op as integer, _
74  byval l as ASTNODE ptr, _
75  byval r as ASTNODE ptr _
76  ) as ASTNODE ptr
77 
78  static as DZSTRING ltext, rtext
79  dim as integer res = any
80 
81  DZstrAssign( ltext, hUnescape( symbGetVarLitText( astGetSymbol( l ) ) ) )
82  DZstrAssign( rtext, hUnescape( symbGetVarLitText( astGetSymbol( r ) ) ) )
83 
84  select case as const op
85  case AST_OP_EQ
86  res = (*ltext.data = *rtext.data)
87  case AST_OP_GT
88  res = (*ltext.data > *rtext.data)
89  case AST_OP_LT
90  res = (*ltext.data < *rtext.data)
91  case AST_OP_NE
92  res = (*ltext.data <> *rtext.data)
93  case AST_OP_LE
94  res = (*ltext.data <= *rtext.data)
95  case AST_OP_GE
96  res = (*ltext.data >= *rtext.data)
97  end select
98 
99  function = astNewCONSTi( res )
100 
101  astDelNode( r )
102  astDelNode( l )
103 
104 end function
105 
106 '':::::
107 function hWStrLiteralCompare _
108  ( _
109  byval op as integer, _
110  byval l as ASTNODE ptr, _
111  byval r as ASTNODE ptr _
112  ) as ASTNODE ptr
113 
114  dim as FBSYMBOL ptr ls = any, rs = any
115  static as DZSTRING textz
116  static as DWSTRING ltextw, rtextw
117  dim as integer res = any
118 
119  ls = astGetSymbol( l )
120  rs = astGetSymbol( r )
121 
122  '' left operand not a wstring?
123  if( symbGetType( ls ) <> FB_DATATYPE_WCHAR ) then
124  DZstrAssign( textz, hUnescape( symbGetVarLitText( ls ) ) )
125  DWstrAssign( rtextw, hUnescapeW( symbGetVarLitTextW( rs ) ) )
126 
127  select case as const op
128  case AST_OP_EQ
129  res = (*textz.data = *rtextw.data)
130  case AST_OP_GT
131  res = (*textz.data > *rtextw.data)
132  case AST_OP_LT
133  res = (*textz.data < *rtextw.data)
134  case AST_OP_NE
135  res = (*textz.data <> *rtextw.data)
136  case AST_OP_LE
137  res = (*textz.data <= *rtextw.data)
138  case AST_OP_GE
139  res = (*textz.data >= *rtextw.data)
140  end select
141 
142  '' right operand?
143  elseif( symbGetType( rs ) <> FB_DATATYPE_WCHAR ) then
144  DWstrAssign( ltextw, hUnescapeW( symbGetVarLitTextW( ls ) ) )
145  DZstrAssign( textz, hUnescape( symbGetVarLitText( rs ) ) )
146 
147  select case as const op
148  case AST_OP_EQ
149  res = (*ltextw.data = *textz.data)
150  case AST_OP_GT
151  res = (*ltextw.data > *textz.data)
152  case AST_OP_LT
153  res = (*ltextw.data < *textz.data)
154  case AST_OP_NE
155  res = (*ltextw.data <> *textz.data)
156  case AST_OP_LE
157  res = (*ltextw.data <= *textz.data)
158  case AST_OP_GE
159  res = (*ltextw.data >= *textz.data)
160  end select
161 
162  '' both wstrings..
163  else
164  DWstrAssign( ltextw, hUnescapeW( symbGetVarLitTextW( ls ) ) )
165  DWstrAssign( rtextw, hUnescapeW( symbGetVarLitTextW( rs ) ) )
166 
167  select case as const op
168  case AST_OP_EQ
169  res = (*ltextw.data = *rtextw.data)
170  case AST_OP_GT
171  res = (*ltextw.data > *rtextw.data)
172  case AST_OP_LT
173  res = (*ltextw.data < *rtextw.data)
174  case AST_OP_NE
175  res = (*ltextw.data <> *rtextw.data)
176  case AST_OP_LE
177  res = (*ltextw.data <= *rtextw.data)
178  case AST_OP_GE
179  res = (*ltextw.data >= *rtextw.data)
180  end select
181 
182  end if
183 
184  function = astNewCONSTi( res )
185 
186  astDelNode( r )
187  astDelNode( l )
188 
189 end function
190 
191 sub hToStr(byref l as ASTNODE ptr, byref r as ASTNODE ptr)
192  dim as integer ldtype = any, rdtype = any
193 
194  ldtype = astGetDataType( l )
195  rdtype = astGetDataType( r )
196 
197  '' convert left operand to string if needed
198  select case as const ldtype
199  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
200  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
201 
202  '' not a string..
203  case else
204  l = rtlToStr( l, FALSE )
205  if( l = NULL ) then
206  errReport( FB_ERRMSG_TYPEMISMATCH )
207  '' error recovery: fake a new node
208  l = astNewCONSTstr( NULL )
209  end if
210  end select
211 
212 
213  '' convert the right operand to string if needed
214  select case as const rdtype
215  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
216  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
217 
218  '' not a string..
219  case else
220  '' expression is not a wstring?
221  if( ldtype <> FB_DATATYPE_WCHAR ) then
222  r = rtlToStr( r, FALSE )
223  else
224  r = rtlToWstr( r )
225  end if
226 
227  if( r = NULL ) then
228  errReport( FB_ERRMSG_TYPEMISMATCH )
229  '' error recovery: fake a new node
230  r = astNewCONSTstr( NULL )
231  end if
232  end select
233 end sub
234 
235 function hConstBop _
236  ( _
237  byval op as integer, _
238  byval dtype as integer, _
239  byval subtype as FBSYMBOL ptr, _
240  byval l as ASTNODE ptr, _
241  byval r as ASTNODE ptr _
242  ) as ASTNODE ptr
243 
244  if( typeGetClass( l->dtype ) = FB_DATACLASS_FPOINT ) then
245  select case as const( op )
246  case AST_OP_ADD
247  l->val.f = l->val.f + r->val.f
248  case AST_OP_SUB
249  l->val.f = l->val.f - r->val.f
250  case AST_OP_MUL
251  l->val.f = l->val.f * r->val.f
252  case AST_OP_DIV
253  '' Note: no division by zero error here - we should return
254  '' INF instead, just like with (l / r) at runtime
255  l->val.f = l->val.f / r->val.f
256  case AST_OP_POW
257  l->val.f = l->val.f ^ r->val.f
258  case AST_OP_NE
259  l->val.i = l->val.f <> r->val.f
260  case AST_OP_EQ
261  l->val.i = l->val.f = r->val.f
262  case AST_OP_GT
263  l->val.i = l->val.f > r->val.f
264  case AST_OP_LT
265  l->val.i = l->val.f < r->val.f
266  case AST_OP_LE
267  l->val.i = l->val.f <= r->val.f
268  case AST_OP_GE
269  l->val.i = l->val.f >= r->val.f
270  case AST_OP_ATAN2
271  l->val.f = atan2( l->val.f, r->val.f )
272  case AST_OP_ANDALSO
273  if l->val.f then
274  l->val.i = (r->val.f <> 0)
275  else
276  l->val.i = 0
277  end if
278  case AST_OP_ORELSE
279  if l->val.f then
280  l->val.i = -1
281  else
282  l->val.i = (r->val.f <> 0)
283  end if
284  case else
285  assert( FALSE )
286  end select
287 
288  elseif( typeIsSigned( l->dtype ) ) then
289  select case as const( op )
290  case AST_OP_ADD : l->val.i = l->val.i + r->val.i
291  case AST_OP_SUB : l->val.i = l->val.i - r->val.i
292  case AST_OP_MUL : l->val.i = l->val.i * r->val.i
293  case AST_OP_SHL : l->val.i = l->val.i shl r->val.i
294  case AST_OP_SHR : l->val.i = l->val.i shr r->val.i
295  case AST_OP_AND : l->val.i = l->val.i and r->val.i
296  case AST_OP_OR : l->val.i = l->val.i or r->val.i
297  case AST_OP_XOR : l->val.i = l->val.i xor r->val.i
298  case AST_OP_EQV : l->val.i = l->val.i eqv r->val.i
299  case AST_OP_IMP : l->val.i = l->val.i imp r->val.i
300  case AST_OP_NE : l->val.i = l->val.i <> r->val.i
301  case AST_OP_EQ : l->val.i = l->val.i = r->val.i
302  case AST_OP_GT : l->val.i = l->val.i > r->val.i
303  case AST_OP_LT : l->val.i = l->val.i < r->val.i
304  case AST_OP_LE : l->val.i = l->val.i <= r->val.i
305  case AST_OP_GE : l->val.i = l->val.i >= r->val.i
306  case AST_OP_ANDALSO : l->val.i = iif( l->val.i <> 0, r->val.i <> 0, 0 )
307  case AST_OP_ORELSE : l->val.i = iif( l->val.i <> 0, -1, r->val.i <> 0 )
308  case AST_OP_INTDIV
309  if( r->val.i <> 0 ) then
310  l->val.i = l->val.i \ r->val.i
311  else
312  l->val.i = 0
313  errReport( FB_ERRMSG_DIVBYZERO )
314  end if
315  case AST_OP_MOD
316  if( r->val.i <> 0 ) then
317  l->val.i = l->val.i mod r->val.i
318  else
319  l->val.i = 0
320  errReport( FB_ERRMSG_DIVBYZERO )
321  end if
322  case else
323  assert( FALSE )
324  end select
325 
326  l = astConvertRawCONSTi( dtype, subtype, l )
327  else
328  select case as const( op )
329  case AST_OP_ADD : l->val.i = cunsg( l->val.i ) + cunsg( r->val.i )
330  case AST_OP_SUB : l->val.i = cunsg( l->val.i ) - cunsg( r->val.i )
331  case AST_OP_MUL : l->val.i = cunsg( l->val.i ) * cunsg( r->val.i )
332  case AST_OP_SHL : l->val.i = cunsg( l->val.i ) shl cunsg( r->val.i )
333  case AST_OP_SHR : l->val.i = cunsg( l->val.i ) shr cunsg( r->val.i )
334  case AST_OP_AND : l->val.i = cunsg( l->val.i ) and cunsg( r->val.i )
335  case AST_OP_OR : l->val.i = cunsg( l->val.i ) or cunsg( r->val.i )
336  case AST_OP_XOR : l->val.i = cunsg( l->val.i ) xor cunsg( r->val.i )
337  case AST_OP_EQV : l->val.i = cunsg( l->val.i ) eqv cunsg( r->val.i )
338  case AST_OP_IMP : l->val.i = cunsg( l->val.i ) imp cunsg( r->val.i )
339  case AST_OP_NE : l->val.i = cunsg( l->val.i ) <> cunsg( r->val.i )
340  case AST_OP_EQ : l->val.i = cunsg( l->val.i ) = cunsg( r->val.i )
341  case AST_OP_GT : l->val.i = cunsg( l->val.i ) > cunsg( r->val.i )
342  case AST_OP_LT : l->val.i = cunsg( l->val.i ) < cunsg( r->val.i )
343  case AST_OP_LE : l->val.i = cunsg( l->val.i ) <= cunsg( r->val.i )
344  case AST_OP_GE : l->val.i = cunsg( l->val.i ) >= cunsg( r->val.i )
345  case AST_OP_ANDALSO : l->val.i = iif( l->val.i <> 0, r->val.i <> 0, 0 )
346  case AST_OP_ORELSE : l->val.i = iif( l->val.i <> 0, -1, r->val.i <> 0 )
347  case AST_OP_INTDIV
348  if( r->val.i <> 0 ) then
349  l->val.i = cunsg( l->val.i ) \ cunsg( r->val.i )
350  else
351  l->val.i = 0
352  errReport( FB_ERRMSG_DIVBYZERO )
353  end if
354  case AST_OP_MOD
355  if( r->val.i <> 0 ) then
356  l->val.i = cunsg( l->val.i ) mod cunsg( r->val.i )
357  else
358  l->val.i = 0
359  errReport( FB_ERRMSG_DIVBYZERO )
360  end if
361  case else
362  assert( FALSE )
363  end select
364 
365  l = astConvertRawCONSTi( dtype, subtype, l )
366  end if
367 
368  function = l
369 end function
370 
371 '':::::
372 function hCheckPointer _
373  ( _
374  byval op as integer, _
375  byval dtype as integer, _
376  byval dclass as integer _
377  ) as integer
378 
379  '' not int?
380  if( dclass <> FB_DATACLASS_INTEGER ) then
381  return FALSE
382 
383  '' CHAR and WCHAR literals are also from the INTEGER class
384  else
385  select case typeGet( dtype )
386  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
387  return FALSE
388  end select
389  end if
390 
391  select case op
392  '' add op?
393  case AST_OP_ADD, AST_OP_SUB
394 
395  '' another pointer?
396  if( typeIsPtr( dtype ) ) then
397  return FALSE
398  end if
399 
400  return TRUE
401 
402  '' short-circuit ops? operands will be checked against zero, so allow.
403  case AST_OP_ANDALSO, AST_OP_ORELSE
404  return TRUE
405 
406  '' relational op?
407  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE
408 
409  return TRUE
410 
411  case else
412  return FALSE
413  end select
414 
415 end function
416 
417 '':::::
418 function hDoPointerArith _
419  ( _
420  byval op as integer, _
421  byval p as ASTNODE ptr, _
422  byval e as ASTNODE ptr, _
423  byval swapped as integer = FALSE _
424  ) as ASTNODE ptr
425 
426  dim as integer edtype = any
427  dim as longint lgt = any
428 
429  function = NULL
430 
431  edtype = astGetDataType( e )
432 
433  '' not integer class?
434  if( typeGetClass( edtype ) <> FB_DATACLASS_INTEGER ) then
435  exit function
436 
437  '' CHAR and WCHAR literals are also from the INTEGER class (to allow *p = 0 etc)
438  else
439  select case edtype
440  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
441  exit function
442  end select
443  end if
444 
445  '' calc len( *p )
446  lgt = symbCalcDerefLen( astGetDataType( p ), astGetSubType( p ) )
447  if( lgt <= 0 ) then
448  '' incomplete type
449  exit function
450  end if
451 
452  '' another pointer?
453  if( typeIsPtr( edtype ) ) then
454  '' only allow if it's a subtraction
455  if( op = AST_OP_SUB ) then
456  '' types can't be different..
457  if( (edtype <> astGetDataType( p )) or _
458  (astGetSubType( e ) <> astGetSubType( p )) ) then
459  exit function
460  end if
461 
462  '' convert to int or BOP will complain..
463  p = astNewCONV( FB_DATATYPE_INTEGER, NULL, p )
464  e = astNewCONV( FB_DATATYPE_INTEGER, NULL, e )
465 
466  '' subtract..
467  e = astNewBOP( AST_OP_SUB, p, e )
468 
469  '' and divide by length
470  function = astNewBOP( AST_OP_INTDIV, e, astNewCONSTi( lgt ) )
471  end if
472 
473  exit function
474  end if
475 
476  '' not integer? convert
477  if( edtype <> FB_DATATYPE_INTEGER ) then
478  e = astNewCONV( FB_DATATYPE_INTEGER, NULL, e )
479  end if
480 
481  '' any op but +|-?
482  select case op
483  case AST_OP_ADD, AST_OP_SUB
484 
485  if( (op = AST_OP_SUB) andalso swapped ) then
486  exit function
487  end if
488 
489  '' multiple by length
490  e = astNewBOP( AST_OP_MUL, e, astNewCONSTi( lgt ) )
491 
492  '' do op
493  function = astNewBOP( op, p, e )
494 
495  case else
496  '' allow AND and OR??
497  exit function
498  end select
499 
500 end function
501 
502 '':::::
503 function hConvertUDT_l _
504  ( _
505  byval op as integer, _
506  byval l as ASTNODE ptr, _
507  byval r as ASTNODE ptr, _
508  byval ex as FBSYMBOL ptr, _
509  byval options as AST_OPOPT _
510  ) as ASTNODE ptr
511 
512  dim as ASTNODE ptr t = any
513 
514  '' try to convert to l type
515  t = astNewCONV( astGetFullType( l ), l->subtype, r )
516  if( t <> NULL ) then
517  t = astNewBOP( op, l, t, ex, options or AST_OPOPT_NOCOERCION )
518  if( t <> NULL ) then
519  return t
520  end if
521  end if
522 
523  '' try convert to r type
524  t = astNewCONV( astGetFullType( r ), r->subtype, l )
525  if( t <> NULL ) then
526  t = astNewBOP( op, t, r, ex, options or AST_OPOPT_NOCOERCION )
527  if( t <> NULL ) then
528  return t
529  end if
530  end if
531 
532  '' try convert to the most precise type
533  t = astNewCONV( FB_DATATYPE_VOID, NULL, l )
534  if( t <> NULL ) then
535  '' coercion allowed, so hConvertUDT_r() can be called if r is an UDT too
536  return astNewBOP( op, t, r, ex, options )
537  end if
538 
539  function = NULL
540 
541 end function
542 
543 '':::::
544 function hConvertUDT_r _
545  ( _
546  byval op as integer, _
547  byval l as ASTNODE ptr, _
548  byval r as ASTNODE ptr, _
549  byval ex as FBSYMBOL ptr, _
550  byval options as AST_OPOPT _
551  ) as ASTNODE ptr
552 
553  dim as ASTNODE ptr t = any
554 
555  '' try to convert to r type
556  t = astNewCONV( astGetFullType( r ), r->subtype, l )
557  if( t <> NULL ) then
558  t = astNewBOP( op, t, r, ex, options or AST_OPOPT_NOCOERCION )
559  if( t <> NULL ) then
560  return t
561  end if
562  end if
563 
564  '' try convert to l type
565  t = astNewCONV( astGetFullType( l ), l->subtype, r )
566  if( t <> NULL ) then
567  t = astNewBOP( op, l, t, ex, options or AST_OPOPT_NOCOERCION )
568  if( t <> NULL ) then
569  return t
570  end if
571  end if
572 
573  '' try convert to the most precise type
574  t = astNewCONV( FB_DATATYPE_VOID, NULL, r )
575  if( t <> NULL ) then
576  return astNewBOP( op, l, t, ex, options or AST_OPOPT_NOCOERCION )
577  end if
578 
579  function = NULL
580 
581 end function
582 
583 '':::::
584 #macro hDoGlobOpOverload _
585  ( _
586  op, l, r _
587  )
588 
589  if( symb.globOpOvlTb(op).head <> NULL ) then
590  dim as FBSYMBOL ptr proc = any
591  dim as FB_ERRMSG err_num = any
592 
593  proc = symbFindBopOvlProc( op, l, r, @err_num )
594  if( proc <> NULL ) then
595  '' build a proc call
596  return astBuildCall( proc, l, r )
597  else
598  if( err_num <> FB_ERRMSG_OK ) then
599  return NULL
600  end if
601 
602  '' commutative?
603 /'if( astGetOpIsCommutative( op ) ) then
604  '' try (r, l) too
605  proc = symbFindBopOvlProc( op, r, l, @err_num )
606  if( proc <> NULL ) then
607  '' build a proc call
608  return astBuildCall( proc, r, l )
609  else
610  if( err_num <> FB_ERRMSG_OK ) then
611  return NULL
612  end if
613  end if
614  end if'/
615  end if
616  end if
617 
618 #endmacro
619 
620 function hCheckDerefWcharPtr _
621  ( _
622  byval l as ASTNODE ptr, _
623  byval pldtype as integer ptr, _
624  byval r as ASTNODE ptr, _
625  byval rdtype as integer _
626  ) as integer
627 
628  dim as ASTNODE ptr ll = any
629 
630  '' Disallow if it's not a DEREF'ed wcharptr
631  if( l->class <> AST_NODECLASS_DEREF ) then
632  exit function
633  end if
634 
635  '' Disallow if it's a fake dynamic string
636  ll = l->l
637  if( ll ) then
638  if( ll->class = AST_NODECLASS_VAR ) then
639  if( symbGetIsWstring( ll->sym ) ) then
640  exit function
641  end if
642  end if
643  end if
644 
645  '' remap the type or the optimizer can
646  '' make a wrong assumption
647  *pldtype = typeJoin( *pldtype, env.target.wchar )
648 
649  function = TRUE
650 end function
651 
652 '' Convert an expression to the given type, preserving CONST bits, and also
653 '' updating the corresponding helper variables
654 sub hConvOperand _
655  ( _
656  byval newdtype as integer, _
657  byref dtype as integer, _
658  byref dclass as integer, _
659  byref n as ASTNODE ptr _
660  )
661 
662  dtype = typeJoin( dtype, newdtype )
663  dclass = typeGetClass( newdtype )
664  n = astNewCONV( dtype, NULL, n )
665 
666 end sub
667 
668 '':::::
669 function astNewBOP _
670  ( _
671  byval op as integer, _
672  byval l as ASTNODE ptr, _
673  byval r as ASTNODE ptr, _
674  byval ex as FBSYMBOL ptr, _
675  byval options as AST_OPOPT _
676  ) as ASTNODE ptr
677 
678  dim as ASTNODE ptr n = any
679  dim as integer ldtype0 = any, rdtype0 = any
680  dim as integer ldtype = any, rdtype = any, dtype = any
681  dim as integer ldclass = any, rdclass = any
682  dim as integer lrank = any, rrank = any, intrank = any, uintrank = any
683  dim as integer is_str = any
684  dim as FBSYMBOL ptr litsym = any, subtype = any
685 
686  function = NULL
687 
688  '' check op overloading
689  hDoGlobOpOverload( op, l, r )
690 
691  is_str = FALSE
692 
693  '' special cases..
694  select case op
695  case AST_OP_CONCAT
696  hToStr( l, r )
697  op = AST_OP_ADD
698  case AST_OP_IS
699  return rtlOOPIsTypeOf( l, r )
700  end select
701 
702  ldtype = astGetFullType( l )
703  rdtype = astGetFullType( r )
704  ldclass = typeGetClass( ldtype )
705  rdclass = typeGetClass( rdtype )
706 
707  '' UDT's? try auto-coercion
708  if( (typeGet( ldtype ) = FB_DATATYPE_STRUCT) or _
709  (typeGet( rdtype ) = FB_DATATYPE_STRUCT) ) then
710 
711  '' recursion?
712  if( (options and AST_OPOPT_NOCOERCION) <> 0 ) then
713  exit function
714  end if
715 
716  '' l or both UDTs?
717  if( typeGet( ldtype ) = FB_DATATYPE_STRUCT ) then
718  return hConvertUDT_l( op, l, r, ex, options )
719 
720  '' only r is..
721  else
722  return hConvertUDT_r( op, l, r, ex, options )
723  end if
724  end if
725 
726  ''::::::
727  '' pointers?
728  if( typeIsPtr( ldtype ) ) then
729  '' do arithmetics?
730  if( (options and AST_OPOPT_LPTRARITH) <> 0 ) then
731  return hDoPointerArith( op, l, r )
732  else
733  if( hCheckPointer( op, rdtype, rdclass ) = FALSE ) then
734  exit function
735  end if
736  end if
737 
738  elseif( typeIsPtr( rdtype ) ) then
739  '' do arithmetics?
740  if( (options and AST_OPOPT_RPTRARITH) <> 0 ) then
741  return hDoPointerArith( op, r, l, TRUE )
742  else
743  if( hCheckPointer( op, ldtype, ldclass ) = FALSE ) then
744  exit function
745  end if
746  end if
747  end if
748 
749  ''
750  '' Enum operands? Convert them to integer (but preserve CONSTs).
751  ''
752  '' When doing math BOPs on enum constants, we don't even know whether
753  '' the resulting integer value will be a part of that enum.
754  '' For typesafe enums, an error would have to be shown here.
755  ''
756  '' Similar for relational BOPs, it's better to compare enums as
757  '' integers, especially if the two operands are from different enums.
758  '' (also, the result of relational BOPs is an integer anyways...)
759  ''
760  if( typeGet( ldtype ) = FB_DATATYPE_ENUM ) then
761  hConvOperand( FB_DATATYPE_INTEGER, ldtype, ldclass, l )
762  end if
763  if( typeGet( rdtype ) = FB_DATATYPE_ENUM ) then
764  hConvOperand( FB_DATATYPE_INTEGER, rdtype, rdclass, r )
765  end if
766 
767  '' both zstrings? treat as string..
768  if( (typeGet( ldtype ) = FB_DATATYPE_CHAR) and _
769  (typeGet( rdtype ) = FB_DATATYPE_CHAR) ) then
770  ldclass = FB_DATACLASS_STRING
771  rdclass = ldclass
772  end if
773 
774  '' wstrings?
775  if( (typeGet( ldtype ) = FB_DATATYPE_WCHAR) or _
776  (typeGet( rdtype ) = FB_DATATYPE_WCHAR) ) then
777 
778  '' not both wstrings?
779  if( typeGetDtAndPtrOnly( ldtype ) <> typeGetDtAndPtrOnly( rdtype ) ) then
780  if( typeGet( ldtype ) = FB_DATATYPE_WCHAR ) then
781  '' is right a string?
782  is_str = (rdclass = FB_DATACLASS_STRING) or (typeGet( rdtype ) = FB_DATATYPE_CHAR)
783  else
784  '' is left a string?
785  is_str = (ldclass = FB_DATACLASS_STRING) or (typeGet( ldtype ) = FB_DATATYPE_CHAR)
786  end if
787  else
788  is_str = TRUE
789  end if
790 
791  if( is_str ) then
792 
793  '' check for string literals
794  litsym = NULL
795  select case typeGet( ldtype )
796  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
797  litsym = astGetStrLitSymbol( l )
798  if( litsym <> NULL ) then
799  select case rdtype
800  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
801  litsym = astGetStrLitSymbol( r )
802  case else
803  litsym = NULL
804  end select
805  end if
806  end select
807 
808  select case as const op
809  '' concatenation?
810  case AST_OP_ADD
811 
812  '' both literals?
813  if( litsym <> NULL ) then
814  '' ok to convert at compile-time?
815  if( (typeGetDtAndPtrOnly( ldtype ) = typeGetDtAndPtrOnly( rdtype )) or _
816  env.wchar_doconv ) then
817  return hWstrLiteralConcat( l, r )
818  end if
819  end if
820 
821  '' not both wstrings?
822  if( typeGetDtAndPtrOnly( ldtype ) <> typeGetDtAndPtrOnly( rdtype ) ) then
823  return rtlWstrConcat( l, ldtype, r, rdtype )
824  end if
825 
826  '' result will be always a wstring
827  ldtype = typeUnsetIsConst( typeJoin( ldtype, FB_DATATYPE_WCHAR ) )
828  ldclass = FB_DATACLASS_INTEGER
829  rdtype = typeJoin( rdtype, ldtype )
830  rdclass = ldclass
831  is_str = TRUE
832 
833  '' concatenation will only be done when loading,
834  '' to allow optimizations..
835 
836  '' comparison?
837  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE
838  '' both literals?
839  if( litsym <> NULL ) then
840  return hWstrLiteralCompare( op, l, r )
841  end if
842 
843  '' convert to: wstrcmp(l,r) op 0
844  l = rtlWstrCompare( l, r )
845  r = astNewCONSTi( 0 )
846 
847  ldtype = typeJoin( ldtype, astGetFullType( l ) )
848  rdtype = typeJoin( rdtype, astGetFullType( r ) )
849  ldclass = FB_DATACLASS_INTEGER
850  rdclass = FB_DATACLASS_INTEGER
851 
852  '' no other operation allowed
853  case else
854  exit function
855  end select
856 
857  '' One is not a string, but e.g. an integer. Disallow if the
858  '' other is not a DEREF'ed wchar ptr - this allows comparisons
859  '' such as "wstringptr[index] = someinteger", i.e. a simplified
860  '' form of string indexing when dealing with a DEREF'ed ptr.
861  else
862  if( typeGet( ldtype ) = FB_DATATYPE_WCHAR ) then
863  if( hCheckDerefWcharPtr( l, @ldtype, r, rdtype ) = FALSE ) then
864  exit function
865  end if
866  else
867  if( hCheckDerefWcharPtr( r, @rdtype, l, ldtype ) = FALSE ) then
868  exit function
869  end if
870  end if
871  end if
872 
873  '' strings?
874  elseif( (ldclass = FB_DATACLASS_STRING) or _
875  (rdclass = FB_DATACLASS_STRING) ) then
876 
877  '' not both strings?
878  if( ldclass <> rdclass ) then
879  if( ldclass = FB_DATACLASS_STRING ) then
880  '' not a zstring?
881  if( typeGet( rdtype ) <> FB_DATATYPE_CHAR ) then
882  exit function
883  end if
884  else
885  '' not a zstring?
886  if( typeGet( ldtype ) <> FB_DATATYPE_CHAR ) then
887  exit function
888  end if
889  end if
890  end if
891 
892  '' check for string literals
893  litsym = NULL
894  if( typeGet( ldtype ) = FB_DATATYPE_CHAR ) then
895  if( typeGet( rdtype ) = FB_DATATYPE_CHAR ) then
896  litsym = astGetStrLitSymbol( l )
897  if( litsym <> NULL ) then
898  litsym = astGetStrLitSymbol( r )
899  end if
900  end if
901  end if
902 
903  select case as const op
904  '' concatenation?
905  case AST_OP_ADD
906  '' both literals?
907  if( litsym <> NULL ) then
908  return hStrLiteralConcat( l, r )
909  end if
910 
911  '' result will be always an var-len string
912  ldtype = typeUnsetIsConst( typeJoin( ldtype, FB_DATATYPE_STRING ) )
913  ldclass = FB_DATACLASS_STRING
914  rdtype = typeJoin( rdtype, ldtype )
915  rdclass = ldclass
916  is_str = TRUE
917 
918  '' concatenation will only be done when loading,
919  '' to allow optimizations..
920 
921  '' comparison?
922  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE
923  '' both literals?
924  if( litsym <> NULL ) then
925  return hStrLiteralCompare( op, l, r )
926  end if
927 
928  '' convert to: strcmp(l,r) op 0
929  l = rtlStrCompare( l, ldtype, r, rdtype )
930  r = astNewCONSTi( 0 )
931 
932  ldtype = typeJoin( ldtype, astGetFullType( l ) )
933  ldclass = FB_DATACLASS_INTEGER
934  rdtype = typeJoin( rdtype, astGetFullType( r ) )
935  rdclass = FB_DATACLASS_INTEGER
936 
937  '' no other operation allowed
938  case else
939  exit function
940  end select
941 
942  '' zstrings?
943  elseif( (typeGet( ldtype ) = FB_DATATYPE_CHAR) or _
944  (typeGet( rdtype ) = FB_DATATYPE_CHAR) ) then
945 
946  '' one is not a string (not fixed, var-len, z- or w-string,
947  '' or the tests above would catch them)
948  if( typeGet( ldtype ) = FB_DATATYPE_CHAR ) then
949  '' don't allow, unless it's a deref pointer
950  if( l->class <> AST_NODECLASS_DEREF ) then
951  exit function
952  end if
953  '' remap the type or the optimizer can
954  '' make a wrong assumption
955  ldtype = typeJoin( ldtype, FB_DATATYPE_UBYTE )
956 
957  else
958  '' same as above..
959  if( r->class <> AST_NODECLASS_DEREF ) then
960  exit function
961  end if
962  rdtype = typeJoin( rdtype, FB_DATATYPE_UBYTE )
963  end if
964 
965  end if
966 
967  ''::::::
968 
969  ''
970  '' Promote smaller integer types to [U]INTEGER before the operation
971  ''
972  '' - but not if it's -lang qb, because 16bit arithmetic should probably
973  '' not become 32bit there. It could matter for code like:
974  '' #lang "qb"
975  '' dim a as integer '' 16-bit "integer" (SHORT internally)
976  '' dim b as integer
977  '' dim x as long
978  '' x = a + b
979  '' where the result of the 16bit BOP is assigned to a 32bit value.
980  ''
981  '' - do nothing if this BOP is a string concatenation/comparison
982  '' - also, do nothing for float/UDT operands
983  ''
984  '' - Pointers and bitfields should be treated as UINTEGER (their
985  '' "remap" types), i.e. they will effectively never be promoted.
986  ''
987  '' Pointers can only appear in BOPs as part of pointer indexing,
988  '' which is a special case. The result type should always be the
989  '' pointer type, so it mustn't be converted here.
990  ''
991  '' Bitfields must be treated as their remap type, since the BOP result
992  '' can't have bitfield type itself... (similar to enums)
993  ''
994  '' - Enums would also be handled via their remap type here, but for now
995  '' any enum operand is already converted to integer above anyways,
996  '' so enums never arrive here.
997  ''
998 
999  ldtype0 = ldtype
1000  rdtype0 = rdtype
1001 
1002  if( (env.clopt.lang <> FB_LANG_QB) and (is_str = FALSE) ) then
1003  intrank = typeGetIntRank( FB_DATATYPE_INTEGER )
1004  uintrank = typeGetIntRank( FB_DATATYPE_UINT )
1005 
1006  '' not for float
1007  if( ldclass = FB_DATACLASS_INTEGER ) then
1008  lrank = typeGetIntRank( typeGetRemapType( ldtype ) )
1009 
1010  '' l < INTEGER?
1011  if( lrank < intrank ) then
1012  hConvOperand( FB_DATATYPE_INTEGER, ldtype, ldclass, l )
1013  else
1014  '' INTEGER < l < UINTEGER?
1015  if( (intrank < lrank) and (lrank < uintrank) ) then
1016  '' Convert to UINTEGER for consistency with
1017  '' the above conversion to INTEGER (this can
1018  '' happen with ULONG on 32bit, and ULONGINT
1019  '' on 64bit, due to the ranking order)
1020  hConvOperand( FB_DATATYPE_UINT, ldtype, ldclass, l )
1021  end if
1022  end if
1023  end if
1024 
1025  '' not for float
1026  if( rdclass = FB_DATACLASS_INTEGER ) then
1027  rrank = typeGetIntRank( typeGetRemapType( rdtype ) )
1028 
1029  '' same for r
1030  if( rrank < intrank ) then
1031  hConvOperand( FB_DATATYPE_INTEGER, rdtype, rdclass, r )
1032  else
1033  if( (intrank < rrank) and (rrank < uintrank) ) then
1034  hConvOperand( FB_DATATYPE_UINT, rdtype, rdclass, r )
1035  end if
1036  end if
1037  end if
1038  end if
1039 
1040  '' convert types
1041  select case as const op
1042  '' flt div (/) can only operate on floats
1043  case AST_OP_DIV
1044 
1045  if( ldclass <> FB_DATACLASS_FPOINT ) then
1046  ldtype = typeJoin( ldtype, FB_DATATYPE_DOUBLE )
1047  l = astNewCONV( ldtype, NULL, l )
1048  ldclass = FB_DATACLASS_FPOINT
1049  end if
1050 
1051  if( rdclass <> FB_DATACLASS_FPOINT ) then
1052  rdtype = typeJoin( rdtype, FB_DATATYPE_DOUBLE )
1053 
1054  if( irGetOption( IR_OPT_FPUCONV ) ) then
1055  r = astNewCONV( rdtype, NULL, r )
1056  else
1057  '' if it's an int var, let the FPU do it
1058  if( (r->class <> AST_NODECLASS_VAR) or (rdtype <> FB_DATATYPE_INTEGER) ) then
1059  r = astNewCONV( rdtype, NULL, r )
1060  end if
1061  end if
1062 
1063  rdclass = FB_DATACLASS_FPOINT
1064  end if
1065 
1066  '' bitwise ops, int div (\), modulus and shift can only operate on integers
1067  case AST_OP_AND, AST_OP_OR, AST_OP_XOR, AST_OP_EQV, AST_OP_IMP, _
1068  AST_OP_INTDIV, AST_OP_MOD, AST_OP_SHL, AST_OP_SHR
1069 
1070  if( ldclass <> FB_DATACLASS_INTEGER ) then
1071  ldtype = typeJoin( ldtype, FB_DATATYPE_INTEGER )
1072  l = astNewCONV( ldtype, NULL, l )
1073  ldclass = FB_DATACLASS_INTEGER
1074  end if
1075 
1076  if( rdclass <> FB_DATACLASS_INTEGER ) then
1077  rdtype = typeJoin( rdtype, FB_DATATYPE_INTEGER )
1078  r = astNewCONV( rdtype, NULL, r )
1079  rdclass = FB_DATACLASS_INTEGER
1080  end if
1081 
1082  '' atan2 can only operate on floats
1083  case AST_OP_ATAN2, AST_OP_POW
1084 
1085  if( ldclass <> FB_DATACLASS_FPOINT ) then
1086  ldtype = typeJoin( ldtype, FB_DATATYPE_DOUBLE )
1087  l = astNewCONV( ldtype, NULL, l )
1088  ldclass = FB_DATACLASS_FPOINT
1089  end if
1090 
1091  if( rdclass <> FB_DATACLASS_FPOINT ) then
1092  rdtype = typeJoin( rdtype, FB_DATATYPE_DOUBLE )
1093  r = astNewCONV( rdtype, NULL, r )
1094  rdclass = FB_DATACLASS_FPOINT
1095  end if
1096 
1097  end select
1098 
1099  ''::::::
1100 
1101  if( ldtype <> rdtype ) then
1102  '' Pointer arithmetic (but not handled above by hDoPointerArith())?
1103  '' (assuming hCheckPointers() checks were already done)
1104  if( (typeIsPtr( ldtype ) or typeIsPtr( rdtype )) and _
1105  ((op = AST_OP_ADD) or (op = AST_OP_SUB)) ) then
1106  '' The result is supposed to be the pointer type
1107  if( typeIsPtr( ldtype ) ) then
1108  dtype = ldtype
1109  subtype = l->subtype
1110  else
1111  dtype = rdtype
1112  subtype = r->subtype
1113  end if
1114  else
1115  '' Convert lhs/rhs to most precise type
1116  '' (e.g. for +/-/* math BOPs, but also for relational BOPs,
1117  '' even if they involve pointers)
1118  typeMax( ldtype, l->subtype, rdtype, r->subtype, dtype, subtype )
1119 
1120  if( (typeGetDtAndPtrOnly( dtype ) <> typeGetDtAndPtrOnly( ldtype )) or _
1121  (subtype <> l->subtype) ) then
1122  l = astNewCONV( dtype, subtype, l )
1123  if( l = NULL ) then exit function
1124  ldtype = dtype
1125  ldclass = typeGetClass( dtype )
1126  end if
1127 
1128  if( (typeGetDtAndPtrOnly( dtype ) <> typeGetDtAndPtrOnly( rdtype )) or _
1129  (subtype <> r->subtype) ) then
1130  '' if it's the src-operand of a shift operation, do nothing
1131  select case op
1132  case AST_OP_SHL, AST_OP_SHR
1133  '' it's already an integer
1134 
1135  case else
1136  r = astNewCONV( dtype, subtype, r )
1137  if( r = NULL ) then exit function
1138 
1139  rdtype = dtype
1140  rdclass = typeGetClass( dtype )
1141  end select
1142  end if
1143  end if
1144  '' no conversion, same types
1145  else
1146  dtype = ldtype
1147  subtype = l->subtype
1148  end if
1149 
1150  '' warn on mixing signed and unsigned ops on comparisons/intdiv/mod/shr (unless signed value was a positive constant)
1151  select case as const op
1152  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE, _
1153  AST_OP_INTDIV, AST_OP_MOD, AST_OP_SHR
1154 
1155  dim as FB_WARNINGMSG warning = 0
1156 
1157  '' lhs signed->unsigned?
1158  if( typeIsSigned( ldtype0 ) ) then
1159  if( typeIsSigned( ldtype ) = FALSE ) then
1160  if( astIsConst( l ) ) then
1161  '' check for negative const lhs
1162  if( astConstGetAsInt64( l ) < 0 ) then
1163  '' lhs const int was negative
1164  warning = FB_WARNINGMSG_OPERANDSMIXEDSIGNEDNESS
1165  end if
1166  else
1167  '' lhs var may have been negative
1168  '' (only a pedantic warning)
1169  if( fbPdCheckIsSet( FB_PDCHECK_SIGNEDNESS ) ) then
1170  warning = FB_WARNINGMSG_OPERANDSMIXEDSIGNEDNESS
1171  end if
1172  end if
1173  end if
1174  end if
1175 
1176  '' lhs signed->unsigned? (Except in SHR)
1177  if( (warning = 0) andalso op <> AST_OP_SHR andalso typeIsSigned( rdtype0 ) ) then
1178  if( typeIsSigned( rdtype ) = FALSE ) then
1179  if( astIsConst( r ) ) then
1180  if( astConstGetAsInt64( r ) < 0 ) then
1181  '' rhs const int was negative
1182  warning = FB_WARNINGMSG_OPERANDSMIXEDSIGNEDNESS
1183  end if
1184  else
1185  '' rhs var may have been negative
1186  '' (only a pedantic warning)
1187  if( fbPdCheckIsSet( FB_PDCHECK_SIGNEDNESS ) ) then
1188  warning = FB_WARNINGMSG_OPERANDSMIXEDSIGNEDNESS
1189  end if
1190  end if
1191  end if
1192  end if
1193 
1194  if( warning <> 0 ) then
1195  errReportWarn( warning )
1196  end if
1197 
1198  end select
1199 
1200  '' post check
1201  select case as const op
1202  '' relational operations always return an integer
1203  case AST_OP_EQ, AST_OP_GT, AST_OP_LT, AST_OP_NE, AST_OP_LE, AST_OP_GE, _
1204  AST_OP_ANDALSO, AST_OP_ORELSE
1205  dtype = FB_DATATYPE_INTEGER
1206  subtype = NULL
1207 
1208  '' right-operand must be an integer, so pow2 opts can be done on longint's
1209  case AST_OP_SHL, AST_OP_SHR
1210  if( astIsCONST( r ) ) then
1211  '' warn if shift is greater than or equal to the number of bits in ldtype
1212  select case astConstGetAsInt64( r )
1213  case 0 to typeGetBits( ldtype )-1
1214 
1215  case else
1216  errReportWarn( FB_WARNINGMSG_SHIFTEXCEEDSBITSINDATATYPE )
1217 
1218  '' prevent gas asm error when value is higher than 255
1219  r = astNewBOP(AST_OP_AND, r, astNewCONSTi(255))
1220  end select
1221  end if
1222 
1223  if( typeGetDtAndPtrOnly( rdtype ) <> FB_DATATYPE_INTEGER ) then
1224  if( typeGetDtAndPtrOnly( rdtype ) <> FB_DATATYPE_UINT ) then
1225  rdtype = typeJoin( rdtype, FB_DATATYPE_INTEGER )
1226  r = astNewCONV( rdtype, NULL, r )
1227  rdclass = FB_DATACLASS_INTEGER
1228  end if
1229  end if
1230  end select
1231 
1232  ''::::::
1233 
1234  '' constant folding (won't handle commutation, ie: "1+a+2+3" will become "1+a+5", not "a+6")
1235  if( astIsCONST( l ) and astIsCONST( r ) ) then
1236  l = hConstBop( op, dtype, subtype, l, r )
1237 
1238  astGetFullType( l ) = dtype
1239  l->subtype = subtype
1240 
1241  astDelNode( r )
1242 
1243  return l
1244 
1245  elseif( astIsCONST( l ) and ldtype = rdtype and is_str = FALSE ) then
1246  select case op
1247  case AST_OP_ADD, AST_OP_MUL, _
1248  AST_OP_AND, AST_OP_OR, AST_OP_XOR, AST_OP_EQV, _
1249  AST_OP_EQ, AST_OP_NE
1250  '' ? OP c = c OP ?
1251  astSwap( r, l )
1252 
1253  case AST_OP_GE
1254  '' c >= ? = ? <= c
1255  op = AST_OP_LE
1256  astSwap( r, l )
1257 
1258  case AST_OP_GT
1259  '' c > ? = ? < c
1260  op = AST_OP_LT
1261  astSwap( r, l )
1262 
1263  case AST_OP_LE
1264  '' c <= ? = ? >= c
1265  op = AST_OP_GE
1266  astSwap( r, l )
1267 
1268  case AST_OP_LT
1269  '' c < ? = ? > c
1270  op = AST_OP_GT
1271  astSwap( r, l )
1272 
1273  case AST_OP_SUB
1274  '' c - ? = -? + c (this will removed later if no const folding can be done)
1275  r = astNewUOP( AST_OP_NEG, r )
1276  if( r = NULL ) then
1277  return NULL
1278  end if
1279  astSwap( r, l )
1280  op = AST_OP_ADD
1281  end select
1282 
1283  elseif( astIsCONST( r ) ) then
1284  select case op
1285  case AST_OP_ADD
1286  '' offset?
1287  if( l->class = AST_NODECLASS_OFFSET ) then
1288  '' no need to check for other values, floats aren't
1289  '' allowed and if longints were used, this wouldn't be
1290  '' an ofs node
1291  l->ofs.ofs += r->val.i
1292  astDelNode( r )
1293 
1294  return l
1295  end if
1296 
1297  case AST_OP_SUB
1298  '' offset?
1299  if( l->class = AST_NODECLASS_OFFSET ) then
1300  '' see above
1301  l->ofs.ofs -= r->val.i
1302  astDelNode( r )
1303 
1304  return l
1305  end if
1306 
1307  '' ? - c = ? + -c
1308  r = astNewUOP( AST_OP_NEG, r )
1309  op = AST_OP_ADD
1310 
1311  '' report error for 'x \ 0', 'x mod 0'
1312  '' Note: no error for 'x / 0', that should just return INF
1313  case AST_OP_INTDIV, AST_OP_MOD
1314  if( r->val.i = 0 ) then
1315  errReport( FB_ERRMSG_DIVBYZERO )
1316  end if
1317 
1318  case AST_OP_POW
1319  '' convert var ^ 2 to var * var
1320  if( r->val.f = 2.0 ) then
1321  '' operands will be converted to DOUBLE if not floats..
1322  if( l->class = AST_NODECLASS_CONV ) then
1323  select case l->l->class
1324  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, _
1325  AST_NODECLASS_FIELD, AST_NODECLASS_DEREF
1326  n = l
1327  l = l->l
1328  astDelNode( n )
1329  ldtype = typeJoin( ldtype, astGetFullType( l ) )
1330  end select
1331  end if
1332 
1333  select case l->class
1334  case AST_NODECLASS_VAR, AST_NODECLASS_IDX, _
1335  AST_NODECLASS_FIELD, AST_NODECLASS_DEREF
1336 
1337  '' can't clone if there's a side-effect in the tree
1338  if( astIsClassOnTree( AST_NODECLASS_CALL, l ) = NULL ) then
1339  ' A pow should always promote l and r to
1340  ' float, and return a float
1341  if( typeGetClass( astGetDataType( l ) ) <> FB_DATACLASS_FPOINT ) then
1342  l = astNewCONV( FB_DATATYPE_DOUBLE, NULL, l )
1343  end if
1344  astDelNode( r )
1345  r = astCloneTree( l )
1346  op = AST_OP_MUL
1347  end if
1348  end select
1349  end if
1350  end select
1351  end if
1352 
1353  ''::::::
1354  '' handle special cases
1355 
1356  select case as const op
1357  case AST_OP_POW
1358  return rtlMathPow( l, r )
1359 
1360  case AST_OP_ATAN2
1361  if( irGetOption( IR_OPT_NOINLINEOPS ) ) then
1362  return rtlMathBop( op, l, r )
1363  end if
1364 
1365  case AST_OP_INTDIV
1366  '' longint?
1367  select case typeGet( dtype )
1368  case FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT
1369  return rtlMathLongintDIV( dtype, l, ldtype, r, rdtype )
1370  end select
1371 
1372  case AST_OP_MOD
1373  '' longint?
1374  select case typeGet( dtype )
1375  case FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT
1376  return rtlMathLongintMOD( dtype, l, ldtype, r, rdtype )
1377  end select
1378 
1379  ' Trap ANDALSO, ORELSE, handle floats, and convert to IIF
1380  case AST_OP_ANDALSO, AST_OP_ORELSE
1381  dim cmp_op as integer
1382  dim cmp_constl as ASTNODE ptr
1383  dim cmp_constr as ASTNODE ptr
1384 
1385  '' For ANDALSO/ORELSE, "ex" is the dtorlist cookie
1386 
1387  if ldclass = FB_DATACLASS_FPOINT then
1388  cmp_constl = astNewConstf(0.0, FB_DATATYPE_SINGLE)
1389  cmp_constr = astNewConstf(0.0, FB_DATATYPE_SINGLE)
1390  else
1391  cmp_constl = astNewCONSTi( 0 )
1392  cmp_constr = astNewCONSTi( 0 )
1393  end if
1394 
1395  if op = AST_OP_ANDALSO then
1396  cmp_op = AST_OP_NE
1397  else
1398  cmp_op = AST_OP_EQ
1399  end if
1400 
1401  l = astNewBOP( cmp_op, l, cmp_constl )
1402  r = astNewBOP( AST_OP_NE, r, cmp_constr )
1403 
1404  if op = AST_OP_ANDALSO then
1405  return astNewIIF( l, r, cint( ex ), astNewCONSTi( 0 ), 0 )
1406  else
1407  return astNewIIF( l, r, cint( ex ), astNewCONSTi( -1 ), 0 )
1408  end if
1409  end select
1410 
1411  '' alloc new node
1412  n = astNewNode( AST_NODECLASS_BOP, dtype, subtype )
1413 
1414  '' fill it
1415  n->l = l
1416  n->r = r
1417  n->op.ex = ex
1418  n->op.op = op
1419 
1420  '' always alloc the result VR for the C backend
1421  if( env.clopt.backend = FB_BACKEND_GCC ) then
1422  options or= AST_OPOPT_ALLOCRES
1423  end if
1424 
1425  n->op.options = options
1426 
1427  function = n
1428 end function
1429 
1430 '':::::
1431 #macro hDoSelfOpOverload _
1432  ( _
1433  op, l, r _
1434  )
1435 
1436  scope
1437  dim as FBSYMBOL ptr proc = any
1438  dim as FB_ERRMSG err_num = any
1439 
1440  proc = symbFindSelfBopOvlProc( op, l, r, @err_num )
1441  if( proc <> NULL ) then
1442  '' build a proc call
1443  function = astBuildCall( proc, l, r )
1444  exit function
1445  else
1446  if( err_num <> FB_ERRMSG_OK ) then
1447  return NULL
1448  end if
1449  end if
1450  end scope
1451 
1452 #endmacro
1453 
1454 '':::::
1455 function astNewSelfBOP _
1456  ( _
1457  byval op as integer, _
1458  byval l as ASTNODE ptr, _
1459  byval r as ASTNODE ptr, _
1460  byval ex as FBSYMBOL ptr, _
1461  byval options as AST_OPOPT _
1462  ) as ASTNODE ptr
1463 
1464  function = NULL
1465 
1466  '' check op overloading
1467  hDoSelfOpOverload( op, l, r )
1468 
1469  '' get the not-to-self version
1470  op = astGetOpSelfVer( op )
1471 
1472  '' if there's a function call in lvalue, convert to tmp = @lvalue, *tmp = *tmp op rhs:
1473  if( astIsClassOnTree( AST_NODECLASS_CALL, l ) ) then
1474  dim as FBSYMBOL ptr tmp = any
1475  dim as ASTNODE ptr ll = any, lr = any
1476 
1477  tmp = symbAddTempVar( typeAddrOf( astGetFullType( l ) ), astGetSubType( l ) )
1478 
1479  '' tmp = @lvalue
1480  ll = astNewASSIGN( astNewVAR( tmp ), astNewADDROF( l ) )
1481  if( ll = NULL ) then
1482  exit function
1483  end if
1484 
1485  '' *tmp = *tmp op expr
1486  lr = astNewASSIGN( _
1487  astNewDEREF( astNewVAR( tmp ) ), _
1488  astNewBOP( op, _
1489  astNewDEREF( astNewVAR( tmp ) ), _
1490  r, ex, options or AST_OPOPT_ALLOCRES ) )
1491 
1492  if( lr = NULL ) then
1493  exit function
1494  end if
1495 
1496  function = astNewLink( ll, lr )
1497 
1498  '' no side-effects, convert it to lvalue = lvalue op rhs and let it be optimized later
1499  else
1500  r = astNewBOP( op, astCloneTree( l ), r, ex, options or AST_OPOPT_ALLOCRES )
1501 
1502  if( r = NULL ) then
1503  exit function
1504  end if
1505 
1506  '' do the assignment
1507  function = astNewASSIGN( l, r )
1508  end if
1509 
1510 end function
1511 
1512 function astLoadBOP( byval n as ASTNODE ptr ) as IRVREG ptr
1513  dim as ASTNODE ptr l = any, r = any
1514  dim as integer op = any
1515  dim as IRVREG ptr v1 = any, v2 = any, vr = any
1516 
1517  op = n->op.op
1518  l = n->l
1519  r = n->r
1520 
1521  if( (l = NULL) or (r = NULL) ) then
1522  return NULL
1523  end if
1524 
1525  if( l->class = AST_NODECLASS_CONV ) then
1526  astUpdateCONVFD2FS( l, n->dtype, TRUE )
1527  end if
1528  if( r->class = AST_NODECLASS_CONV ) then
1529  astUpdateCONVFD2FS( r, n->dtype, TRUE )
1530  end if
1531 
1532  '' need some other algo here to select which operand is better to evaluate
1533  '' first - pay attention to logical ops, "func1(bar) OR func1(foo)" isn't
1534  '' the same as the inverse if func1 depends on the order..
1535  v1 = astLoad( l )
1536  v2 = astLoad( r )
1537 
1538  if( ast.doemit ) then
1539  '' result type can be different, with boolean operations on floats
1540  if( (n->op.options and AST_OPOPT_ALLOCRES) <> 0 ) then
1541  vr = irAllocVREG( astGetDataType( n ), n->subtype )
1542  vr->vector = n->vector
1543  else
1544  vr = NULL
1545  v1->vector = n->vector
1546  end if
1547 
1548  '' execute the operation
1549  if( n->op.ex <> NULL ) then
1550  '' hack! ex=label, vr being NULL 'll gen better code at IR..
1551  irEmitBOP( op, v1, v2, NULL, n->op.ex )
1552  else
1553  irEmitBOP( op, v1, v2, vr, NULL )
1554  end if
1555 
1556  '' "var op= expr" optimizations
1557  if( vr = NULL ) then
1558  vr = v1
1559  end if
1560  end if
1561 
1562  '' nodes not needed anymore
1563  astDelNode( l )
1564  astDelNode( r )
1565 
1566  function = vr
1567 end function
1568