FreeBASIC  0.91.0
ast-node-conv.bas
Go to the documentation of this file.
1 '' AST conversion nodes
2 '' l = expression to convert; r = NULL
3 ''
4 '' chng: sep/2004 written [v1ctor]
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 
12 sub hConstConv( byval todtype as integer, byval l as ASTNODE ptr )
13  dim as integer ldtype = any
14 
15  ldtype = astGetFullType( l )
16 
17  if( typeGetClass( ldtype ) = FB_DATACLASS_FPOINT ) then
18  select case as const( typeGetSizeType( todtype ) )
19  case FB_SIZETYPE_FLOAT32
20  '' SINGLE -> SINGLE: nothing to do
21  '' DOUBLE -> SINGLE?
22  if( typeGetDtAndPtrOnly( ldtype ) = FB_DATATYPE_DOUBLE ) then
23  '' Truncate DOUBLE to SINGLE (note: csng()
24  '' before 0.25 didn't truncate in this case,
25  '' so using an explicit temp var instead)
26  dim as single f = any
27  f = l->val.f
28  l->val.f = f
29  end if
30  case FB_SIZETYPE_FLOAT64
31  '' SINGLE/DOUBLE -> DOUBLE:
32  '' Nothing to do, since float constants are stored as DOUBLE
33  case FB_SIZETYPE_INT8
34  l->val.i = cbyte( l->val.f )
35  case FB_SIZETYPE_UINT8
36  l->val.i = cubyte( l->val.f )
37  case FB_SIZETYPE_INT16
38  l->val.i = cshort( l->val.f )
39  case FB_SIZETYPE_UINT16
40  l->val.i = cushort( l->val.f )
41  case FB_SIZETYPE_INT32
42  l->val.i = clng( l->val.f )
43  case FB_SIZETYPE_UINT32
44  l->val.i = culng( l->val.f )
45  case FB_SIZETYPE_INT64
46  l->val.i = clngint( l->val.f )
47  case FB_SIZETYPE_UINT64
48  l->val.i = hCastFloatToULongint( l->val.f )
49  end select
50  elseif( typeIsSigned( ldtype ) ) then
51  select case as const( typeGetSizeType( todtype ) )
52  case FB_SIZETYPE_FLOAT32
53  l->val.f = csng( l->val.i )
54  case FB_SIZETYPE_FLOAT64
55  l->val.f = cdbl( l->val.i )
56  case FB_SIZETYPE_INT8
57  l->val.i = cbyte( l->val.i )
58  case FB_SIZETYPE_UINT8
59  l->val.i = cubyte( l->val.i )
60  case FB_SIZETYPE_INT16
61  l->val.i = cshort( l->val.i )
62  case FB_SIZETYPE_UINT16
63  l->val.i = cushort( l->val.i )
64  case FB_SIZETYPE_INT32
65  l->val.i = clng( l->val.i )
66  case FB_SIZETYPE_UINT32
67  l->val.i = culng( l->val.i )
68  case FB_SIZETYPE_INT64
69  l->val.i = clngint( l->val.i )
70  case FB_SIZETYPE_UINT64
71  l->val.i = culngint( l->val.i )
72  end select
73  else
74  select case as const( typeGetSizeType( todtype ) )
75  case FB_SIZETYPE_FLOAT32
76  l->val.f = csng( cunsg( l->val.i ) )
77  case FB_SIZETYPE_FLOAT64
78  l->val.f = cdbl( cunsg( l->val.i ) )
79  case FB_SIZETYPE_INT8
80  l->val.i = cbyte( cunsg( l->val.i ) )
81  case FB_SIZETYPE_UINT8
82  l->val.i = cubyte( cunsg( l->val.i ) )
83  case FB_SIZETYPE_INT16
84  l->val.i = cshort( cunsg( l->val.i ) )
85  case FB_SIZETYPE_UINT16
86  l->val.i = cushort( cunsg( l->val.i ) )
87  case FB_SIZETYPE_INT32
88  l->val.i = clng( cunsg( l->val.i ) )
89  case FB_SIZETYPE_UINT32
90  l->val.i = culng( cunsg( l->val.i ) )
91  case FB_SIZETYPE_INT64
92  l->val.i = clngint( cunsg( l->val.i ) )
93  case FB_SIZETYPE_UINT64
94  l->val.i = culngint( cunsg( l->val.i ) )
95  end select
96  end if
97 end sub
98 
99 function hGetTypeMismatchErrMsg( byval options as AST_CONVOPT ) as integer
100  if( options and AST_CONVOPT_PTRONLY ) then
101  function = FB_ERRMSG_EXPECTEDPOINTER
102  else
103  function = FB_ERRMSG_TYPEMISMATCH
104  end if
105 end function
106 
107 function hCheckPtr _
108  ( _
109  byval to_dtype as integer, _
110  byval to_subtype as FBSYMBOL ptr, _
111  byval expr_dtype as integer, _
112  byval expr as ASTNODE ptr, _
113  byval options as AST_CONVOPT _
114  ) as integer
115 
116  function = FB_ERRMSG_OK
117 
118  '' to pointer? only allow integers of same size, and pointers
119  if( typeIsPtr( to_dtype ) ) then
120  select case as const typeGet( expr_dtype )
121  case FB_DATATYPE_INTEGER, FB_DATATYPE_UINT, FB_DATATYPE_ENUM, _
122  FB_DATATYPE_LONG, FB_DATATYPE_ULONG, _
123  FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT
124  '' Allow integer-to-pointer casts if same size
125  if( typeGetSize( expr_dtype ) = env.pointersize ) then
126  exit function
127  end if
128  return hGetTypeMismatchErrMsg( options )
129 
130  '' only allow other int dtypes if it's 0 (due QB's INTEGER = short)
131  case FB_DATATYPE_BYTE, FB_DATATYPE_UBYTE, _
132  FB_DATATYPE_SHORT, FB_DATATYPE_USHORT
133  if( astIsCONST( expr ) ) then
134  if( astConstEqZero( expr ) ) then
135  '' Allow 0-to-pointer casts
136  exit function
137  end if
138  end if
139 
140  return hGetTypeMismatchErrMsg( options )
141 
142  case FB_DATATYPE_POINTER
143  '' Both are pointers, fall through to checks below
144 
145  case else
146  '' Nothing else allowed (strings, structs)
147  return hGetTypeMismatchErrMsg( options )
148  end select
149 
150  '' from pointer? only allow integers of same size and pointers
151  elseif( typeIsPtr( expr_dtype ) ) then
152  select case as const typeGet( to_dtype )
153  case FB_DATATYPE_INTEGER, FB_DATATYPE_UINT, FB_DATATYPE_ENUM, _
154  FB_DATATYPE_LONG, FB_DATATYPE_ULONG, _
155  FB_DATATYPE_LONGINT, FB_DATATYPE_ULONGINT
156  '' Allow integer-to-pointer casts if same size
157  if( typeGetSize( to_dtype ) = env.pointersize ) then
158  exit function
159  end if
160  return hGetTypeMismatchErrMsg( options )
161 
162  case FB_DATATYPE_POINTER
163  '' Both are pointers, fall through to checks below
164 
165  case else
166  '' Nothing else allowed (strings, structs)
167  return hGetTypeMismatchErrMsg( options )
168  end select
169  else
170  '' No pointers at all, nothing to do
171  exit function
172  end if
173 
174  ''
175  '' Both are pointers
176  ''
177  '' If any of them is a pointer to a derived class,
178  '' only allow casting to a pointer to a class from that
179  '' inheritance hierarchy, or ANY PTR.
180  ''
181 
182  '' To derived pointer?
183  if( typeGetDtOnly( to_dtype ) = FB_DATATYPE_STRUCT ) then
184  if( to_subtype->udt.base <> NULL ) then
185  if( typeGetDtOnly( expr_dtype ) <> FB_DATATYPE_STRUCT ) then
186  if( typeGetDtOnly( expr_dtype ) <> FB_DATATYPE_VOID ) then
187  return FB_ERRMSG_CASTDERIVEDPTRFROMINCOMPATIBLE
188  end if
189  else
190  '' not a upcasting?
191  if( symbGetUDTBaseLevel( expr->subtype, to_subtype ) = 0 ) then
192  '' try downcasting..
193  if( symbGetUDTBaseLevel( to_subtype, expr->subtype ) = 0 ) then
194  return FB_ERRMSG_CASTDERIVEDPTRFROMUNRELATED
195  End If
196  End If
197  end if
198  End If
199  End If
200 
201  '' From derived pointer?
202  if( typeGetDtOnly( expr_dtype ) = FB_DATATYPE_STRUCT ) then
203  if( expr->subtype->udt.base <> NULL ) then
204  if( typeGetDtOnly( to_dtype ) <> FB_DATATYPE_STRUCT ) then
205  if( typeGetDtOnly( to_dtype ) <> FB_DATATYPE_VOID ) then
206  return FB_ERRMSG_CASTDERIVEDPTRTOINCOMPATIBLE
207  end if
208  else
209  '' not a upcasting?
210  if( symbGetUDTBaseLevel( to_subtype, expr->subtype ) = 0 ) then
211  '' try downcasting..
212  if( symbGetUDTBaseLevel( expr->subtype, to_subtype ) = 0 ) then
213  return FB_ERRMSG_CASTDERIVEDPTRTOUNRELATED
214  End If
215  End If
216  end if
217  End If
218  End If
219 
220 end function
221 
222 '':::::
223 function astCheckCONV _
224  ( _
225  byval to_dtype as integer, _
226  byval to_subtype as FBSYMBOL ptr, _
227  byval l as ASTNODE ptr _
228  ) as integer
229 
230  dim as integer ldtype = any
231 
232  function = FALSE
233 
234  ldtype = astGetFullType( l )
235 
236  '' to or from UDT? only upcasting supported by now
237  if( (typeGet( to_dtype ) = FB_DATATYPE_STRUCT) or _
238  (typeGet( ldtype ) = FB_DATATYPE_STRUCT) ) then
239  if( (typeGet( to_dtype ) = FB_DATATYPE_STRUCT) and _
240  (typeGet( ldtype ) = FB_DATATYPE_STRUCT) ) then
241  function = (symbGetUDTBaseLevel( l->subtype, to_subtype ) > 0)
242  end if
243  exit function
244  end if
245 
246  '' string? neither
247  if( typeGetClass( ldtype ) = FB_DATACLASS_STRING ) then
248  exit function
249  end if
250 
251  '' check pointers
252  if( hCheckPtr( to_dtype, to_subtype, ldtype, l, 0 ) <> FB_ERRMSG_OK ) then
253  exit function
254  end if
255 
256  select case typeGet( ldtype )
257  '' CHAR and WCHAR literals are also from the INTEGER class
258  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
259  '' don't allow, unless it's a deref pointer
260  if( astIsDEREF( l ) = FALSE ) then
261  exit function
262  end if
263 
264  end select
265 
266  function = TRUE
267 
268 end function
269 
270 '':::::
271 #macro hDoGlobOpOverload( to_dtype, to_subtype, node )
272  scope
273  dim as FBSYMBOL ptr proc = any
274  dim as FB_ERRMSG err_num = any
275 
276  proc = symbFindCastOvlProc( to_dtype, to_subtype, node, @err_num )
277  if( proc <> NULL ) then
278  '' build a proc call
279  return astBuildCall( proc, l )
280  else
281  if( err_num <> FB_ERRMSG_OK ) then
282  return NULL
283  end if
284  end if
285  end scope
286 #endmacro
287 
288 '':::::
289 function astNewCONV _
290  ( _
291  byval to_dtype as integer, _
292  byval to_subtype as FBSYMBOL ptr, _
293  byval l as ASTNODE ptr, _
294  byval options as AST_CONVOPT, _
295  byval perrmsg as integer ptr _
296  ) as ASTNODE ptr
297 
298  dim as ASTNODE ptr n = any
299  dim as integer ldclass = any, ldtype = any, errmsg = any, doconv = any
300 
301  if( perrmsg ) then
302  *perrmsg = FB_ERRMSG_OK
303  end if
304 
305  ldtype = astGetFullType( l )
306 
307  '' same type?
308  if( typeGetDtAndPtrOnly( ldtype ) = typeGetDtAndPtrOnly( to_dtype ) ) then
309  if( l->subtype = to_subtype ) then
310  '' Only CONST bits changed?
311  if( ldtype <> to_dtype ) then
312  '' CONST node? Evaluate at compile-time
313  if( astIsCONST( l ) ) then
314  astSetType( l, to_dtype, to_subtype )
315  n = l
316  else
317  '' Otherwise, add a CONV node to represent the changed CONST bits
318  '' to the expression parser
319  n = astNewNode( AST_NODECLASS_CONV, to_dtype, to_subtype )
320  n->l = l
321  n->cast.doconv = FALSE
322  n->cast.do_convfd2fs = FALSE
323  end if
324  else
325  n = l
326  end if
327 
328  return n
329  end if
330  end if
331 
332  '' try casting op overloading
333  hDoGlobOpOverload( to_dtype, to_subtype, l )
334 
335  select case as const typeGet( to_dtype )
336  case FB_DATATYPE_VOID, FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
337  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
338  '' refuse void (used by uop/bop to cast to be most precise
339  '' possible) and strings, as op overloading already failed
340  exit function
341 
342  '' to UDT?
343  case FB_DATATYPE_STRUCT ', FB_DATATYPE_CLASS
344  '' not from UDT? op overloading already failed, refuse.
345  if( typeGet( ldtype ) <> FB_DATATYPE_STRUCT ) then
346  exit function
347  end if
348 
349  if( symbGetUDTBaseLevel( l->subtype, to_subtype ) = 0 ) then
350  exit function
351  end if
352 
353  '' to anything else (integers/floats)
354  case else
355  '' from UDT? refuse, since op overloading already failed
356  if( typeGet( ldtype ) = FB_DATATYPE_STRUCT ) then
357  exit function
358  end if
359 
360  end select
361 
362  ldclass = typeGetClass( ldtype )
363 
364  '' sign conversion?
365  if( options and AST_CONVOPT_SIGNCONV ) then
366  '' float? invalid
367  if( ldclass <> FB_DATACLASS_INTEGER ) then
368  exit function
369  end if
370  end if
371 
372  if( (options and AST_CONVOPT_DONTCHKPTR) = 0 ) then
373  '' check pointers
374  errmsg = hCheckPtr( to_dtype, to_subtype, ldtype, l, options )
375  if( errmsg <> FB_ERRMSG_OK ) then
376  if( perrmsg ) then
377  *perrmsg = errmsg
378  end if
379  exit function
380  end if
381  end if
382 
383  '' string?
384  if( options and AST_CONVOPT_CHECKSTR ) then
385  select case as const typeGet( ldtype )
386  case FB_DATATYPE_STRING, FB_DATATYPE_FIXSTR, _
387  FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
388  return rtlStrToVal( l, to_dtype )
389  end select
390  else
391  if( ldclass = FB_DATACLASS_STRING ) then
392  exit function
393  '' CHAR and WCHAR literals are also from the INTEGER class
394  else
395  select case typeGet( ldtype )
396  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
397  '' don't allow, unless it's a deref pointer
398  if( astIsDEREF( l ) = FALSE ) then
399  exit function
400  end if
401  end select
402  end if
403  end if
404 
405  '' constant? evaluate at compile-time
406  if( astIsCONST( l ) ) then
407  astCheckConst( to_dtype, l )
408 
409  hConstConv( to_dtype, l )
410 
411  l->dtype = to_dtype
412  l->subtype = to_subtype
413  return l
414  end if
415 
416  '' C backend?
417  if( env.clopt.backend = FB_BACKEND_GCC ) then
418  '' special case: if it's a float to int, use a builtin function
419  if( (ldclass = FB_DATACLASS_FPOINT) and (typeGetClass( to_dtype ) = FB_DATACLASS_INTEGER) ) then
420  return rtlMathFTOI( l, to_dtype )
421  else
422  select case( typeGetDtAndPtrOnly( to_dtype ) )
423  case FB_DATATYPE_STRUCT '', FB_DATATYPE_CLASS
424  '' C (not C++) doesn't support casting from a UDT to another, so do this instead: lhs = *((typeof(lhs)*)&rhs)
425  return astNewDEREF( astNewCONV( typeAddrOf( to_dtype ), to_subtype, astNewADDROF( l ) ) )
426  end select
427  end if
428  end if
429 
430  doconv = TRUE
431 
432  '' only convert if the classes are different (ie, floating<->integer) or
433  '' if sizes are different (ie, byte<->int)
434  if( ldclass = typeGetClass( to_dtype ) ) then
435  select case( typeGet( to_dtype ) )
436  case FB_DATATYPE_STRUCT '', FB_DATATYPE_CLASS
437  '' do nothing
438  doconv = FALSE
439  case else
440  if( typeGetSize( ldtype ) = typeGetSize( to_dtype ) ) then
441  doconv = FALSE
442  end if
443  end select
444  end if
445 
446  if( irGetOption( IR_OPT_FPUCONV ) ) then
447  if (ldclass = FB_DATACLASS_FPOINT) and ( typeGetClass( to_dtype ) = FB_DATACLASS_FPOINT ) then
448  if( typeGetSize( ldtype ) <> typeGetSize( to_dtype ) ) then
449  doconv = TRUE
450  end if
451  end if
452  end if
453 
454  '' casting another cast?
455  if( l->class = AST_NODECLASS_CONV ) then
456  '' no conversion in both?
457  if( l->cast.doconv = FALSE ) then
458  if( doconv = FALSE ) then
459  '' just replace the bottom cast()'s type
460  astGetFullType( l ) = to_dtype
461  l->subtype = to_subtype
462  return l
463  end if
464  end if
465  end if
466 
467  '' alloc new node
468  n = astNewNode( AST_NODECLASS_CONV, to_dtype, to_subtype )
469 
470  n->l = l
471  n->cast.doconv = doconv
472  n->cast.do_convfd2fs = FALSE
473 
474  if( env.clopt.backend = FB_BACKEND_GAS ) then
475  if( doconv ) then
476  '' converting DOUBLE to SINGLE?
477  if( typeGet( ldtype ) = FB_DATATYPE_DOUBLE ) then
478  n->cast.do_convfd2fs = (typeGet( to_dtype ) = FB_DATATYPE_SINGLE)
479  end if
480  end if
481  end if
482 
483  function = n
484 
485 end function
486 
487 '':::::
488 function astNewOvlCONV _
489  ( _
490  byval to_dtype as integer, _
491  byval to_subtype as FBSYMBOL ptr, _
492  byval l as ASTNODE ptr _
493  ) as ASTNODE ptr
494 
495  '' try casting op overloading only
496  hDoGlobOpOverload( to_dtype, to_subtype, l )
497 
498  '' nothing to do
499  function = l
500 
501 end function
502 
503 sub astUpdateCONVFD2FS _
504  ( _
505  byval n as ASTNODE ptr, _
506  byval to_dtype as integer, _
507  byval is_expr as integer _
508  )
509 
510  assert( n->class = AST_NODECLASS_CONV )
511 
512  '' only when converting DOUBLE to SINGLE
513  if( n->cast.do_convfd2fs = FALSE ) then
514  exit sub
515  end if
516 
517  assert( env.clopt.backend = FB_BACKEND_GAS )
518 
519  ''
520  '' x86 assumptions
521  ''
522  '' Don't do the DOUBLE to SINGLE truncation unless needed.
523  ''
524  '' If the target dtype cannot hold bigger values than SINGLE
525  '' anyways, then we don't need to do the additional truncation,
526  '' that will happen automatically when storing into the target.
527  ''
528  '' This applies to stores (ASSIGN, ARG), and to expressions
529  '' that do not use the FPU stack (ST(N) registers).
530  ''
531 
532  '' everything >= 4 bytes, assuming that 4 byte integers can hold values
533  '' that still are too big for SINGLE
534  n->cast.do_convfd2fs = (typeGetSize( to_dtype ) >= 4)
535 
536  '' to SINGLE itself? no need to do anything then, except if it's on
537  '' the FPU stack, and won't be automatically truncated because of that.
538  if( typeGet( to_dtype ) = FB_DATATYPE_SINGLE ) then
539  n->cast.do_convfd2fs = is_expr
540  end if
541 
542 end sub
543 
544 '':::::
545 function astLoadCONV _
546  ( _
547  byval n as ASTNODE ptr _
548  ) as IRVREG ptr
549 
550  dim as ASTNODE ptr l = any
551  dim as IRVREG ptr vs = any, vr = any
552 
553  l = n->l
554 
555  if( l = NULL ) then
556  return NULL
557  end if
558 
559  vs = astLoad( l )
560 
561  if( ast.doemit ) then
562  vs->vector = n->vector
563  if( n->cast.doconv ) then
564  vr = irAllocVreg( astGetDataType( n ), n->subtype )
565  vr->vector = n->vector
566  irEmitConvert( vr, vs )
567 
568  if( n->cast.do_convfd2fs ) then
569  '' converting DOUBLE to SINGLE?
570  if( vs->dtype = FB_DATATYPE_DOUBLE ) then
571  if( vr->dtype = FB_DATATYPE_SINGLE ) then
572  if( vr->regFamily = IR_REG_FPU_STACK ) then
573  '' Do additional conversion to truncate to SINGLE
574  irEmitUOP( AST_OP_CONVFD2FS, vr, NULL )
575  end if
576  end if
577  end if
578  end if
579  else
580  vr = vs
581  irSetVregDataType( vr, astGetDataType( n ), n->subtype )
582  end if
583  end if
584 
585  astDelNode( l )
586 
587  function = vr
588 
589 end function
590 
591 
592