FreeBASIC  0.91.0
ir-llvm.bas
Go to the documentation of this file.
1 ''
2 '' IR backend for emitting LLVM IR to output file
3 ''
4 '' For comparison, see
5 '' - LLVM IR language reference: http://llvm.org/docs/LangRef.html
6 '' - clang output: $ clang -Wall -emit-llvm -S test.c -o test.ll
7 '' - llc compiler: $ llc -O2 test.ll -o test.asm
8 ''
9 '' LLVM IR instructions inside procedures look like this:
10 ''
11 '' %var = alloca i32 ; dim var as integer ptr = alloca( sizeof( integer ) )
12 '' store %i32 0, i32* %var ; *var = 0
13 '' loop:
14 '' %temp0 = load %i32* %var ; temp0 = *var
15 '' %temp1 = add i32 %temp0, 1 ; temp1 = temp0 + 1
16 '' store %i32 %temp1, i32* %var ; *var = temp1
17 '' %temp2 = load %i32* %var ; temp2 = *var
18 '' %cond = icmp lt i32 %temp2, 10 ; condition = (temp2 < 10)
19 '' br i1 %cond, label %loop, label %exit ; if condition then goto loop else goto exit
20 '' exit:
21 ''
22 '' - Operations must be in SSA form, there are no self-ops. Operations that
23 '' don't return void can be assigned to a %name which can be referenced in
24 '' following operations. The result values can only be stored into memory
25 '' by separate/explicit store ops.
26 ''
27 '' - Operations without name implicitly use the %N naming scheme: %1, %2, %3 ...
28 '' For fbc it seems better to emit proper names though and not rely on the
29 '' implicit position-based names, because the IR vreg allocation order does
30 '' not match the order of emitted operations.
31 ''
32 '' - Labels begin basic blocks, certain operations (ret, br, ...) end them.
33 '' Basic blocks without a name/label are given a default name/label similar
34 '' to the default naming for operations.
35 ''
36 '' - Labels are not allowed to appear consecutively (a basic block can only
37 '' have one name), and labels are not allowed in the middle of basic blocks
38 '' (only after an end operation like ret or br).
39 '' Both situations can happen in FB code easily (empty scope blocks, GOTO...),
40 '' so _emitLabel() needs to work around that by inserting no-ops or branches.
41 '' (a more complex solution would be to remove duplicate labels from the AST,
42 '' and redirect all uses of the removed label to the label that was kept)
43 ''
44 '' - Operand types are always emitted explicitly; they are not guessed or
45 '' automatically derived from the actual operand.
46 ''
47 '' - All types must match exactly, or llc will complain.
48 '' Since the AST does not always call irSetVregDataType() or irEmitConvert(),
49 '' the operations emitting ensures to emit casts if needed.
50 ''
51 '' - Local variables are allocated from stack using "alloca",
52 '' the returned value is a pointer to the memory.
53 ''
54 '' - Procedure parameters are passed as values, not pointers, so if the
55 '' function wants to take the address of a parameter,
56 '' it has to alloca a stack variable to hold the parameter value.
57 '' (that's what clang does)
58 ''
59 
60 #include once "fb.bi"
61 #include once "fbint.bi"
62 #include once "ir.bi"
63 #include once "rtl.bi"
64 #include once "flist.bi"
65 #include once "lex.bi"
66 
67 enum
68  SECTION_HEAD '' global declarations
69  SECTION_BODY '' procedure bodies
70  SECTION_FOOT '' debugging meta data
71 end enum
72 
73 type IRCALLARG
74  vr as IRVREG ptr
75  level as integer
76 end type
77 
78 type IRHLCCTX
79  identcnt as integer ' how many levels of indent
80  regcnt as integer ' temporary labels counter
81  lblcnt as integer
82  tmpcnt as integer
83  vregTB as TFLIST
85  callargs as TLIST '' IRCALLARG's during emitPushArg/emitCall[Ptr]
86  linenum as integer
87 
88  varini as string
89  variniscopelevel as integer
90 
91  fbctinf as string
92  fbctinf_len as integer
93 
94  asm_line as string '' line of inline asm built up by _emitAsm*()
95 
96  section as integer '' current section to write to
97  head_txt as string
98  body_txt as string
99  foot_txt as string
100 
101  memset_used as integer
102  memmove_used as integer
103 end type
104 
105 declare function hEmitType _
106  ( _
107  byval dtype as integer, _
108  byval subtype as FBSYMBOL ptr, _
109  byval is_result as integer = FALSE _
110  ) as string
111 
112 declare sub hEmitStruct( byval s as FBSYMBOL ptr )
113 
114 declare sub _emitDBG _
115  ( _
116  byval op as integer, _
117  byval proc as FBSYMBOL ptr, _
118  byval ex as integer _
119  )
120 
121 declare function hVregToStr( byval vreg as IRVREG ptr ) as string
122 declare sub _emitConvert( byval v1 as IRVREG ptr, byval v2 as IRVREG ptr )
123 declare sub _emitStore( byval v1 as IRVREG ptr, byval v2 as IRVREG ptr )
124 
125 declare sub _emitBop _
126  ( _
127  byval op as integer, _
128  byval v1 as IRVREG ptr, _
129  byval v2 as IRVREG ptr, _
130  byval vr as IRVREG ptr, _
131  byval ex as FBSYMBOL ptr _
132  )
133 
134 '' globals
135 dim shared as IRHLCCTX ctx
136 
137 sub _init( )
138  flistInit( @ctx.vregTB, IR_INITVREGNODES, len( IRVREG ) )
139  flistInit( @ctx.forwardlist, 32, len( FBSYMBOL ptr ) )
140  listInit( @ctx.callargs, 32, sizeof(IRCALLARG), LIST_FLAGS_NOCLEAR )
141 
142  irSetOption( IR_OPT_CPUSELFBOPS or IR_OPT_FPUIMMEDIATES or IR_OPT_NOINLINEOPS )
143 
144  ' initialize the current section
146 end sub
147 
148 sub _end( )
149  listEnd( @ctx.callargs )
151  flistEnd( @ctx.vregTB )
152 end sub
153 
154 sub hWriteLine( byref ln as string )
155  if( ctx.identcnt > 0 ) then
156  ln = string( ctx.identcnt, TABCHAR ) + ln
157  end if
158 
159  ln += NEWLINE
160 
161  '' Write it out to the current section
162  select case as const( ctx.section )
163  case SECTION_HEAD
164  ctx.head_txt += ln
165  case SECTION_BODY
166  ctx.body_txt += ln
167  case SECTION_FOOT
168  ctx.foot_txt += ln
169  end select
170 end sub
171 
172 sub hWriteLabel( byval id as zstring ptr )
173  ctx.identcnt -= 1
174  hWriteLine( *id + ":" )
175  ctx.identcnt += 1
176 end sub
177 
178 function hEmitParamName( byval sym as FBSYMBOL ptr ) as string
179  function = *symbGetMangledName( sym ) + "$"
180 end function
181 
182 function hEmitProcCallConv( byval proc as FBSYMBOL ptr ) as string
183  '' Calling convention
184  '' - default if none specified is Cdecl as in C
185  '' - must be given on the declaration, on the body,
186  '' and on each CALL instruction
187  ''
188  '' Note: Pascal is like Stdcall (callee cleans up stack), except that
189  '' arguments are pushed left-to-right (same order as written in code,
190  '' not reversed like Cdecl/Stdcall).
191  '' The symbGetProc*Param() macros take care of changing the order when
192  '' cycling through parameters of Pascal functions. Together with Stdcall
193  '' this results in a double-reverse resulting in the proper ABI.
194  ''
195  '' For non-x86, don't emit any calling convention at all, it would just
196  '' be ignored anyways (for x86_64 and ARM it seems that way at least).
197 
198  if( fbCpuTypeIsX86( ) = FALSE ) then
199  exit function
200  end if
201 
202  select case as const( symbGetProcMode( proc ) )
203  case FB_FUNCMODE_STDCALL, FB_FUNCMODE_STDCALL_MS, FB_FUNCMODE_PASCAL
204  function = "x86_stdcallcc "
205  end select
206 end function
207 
208 function hEmitProcHeader _
209  ( _
210  byval proc as FBSYMBOL ptr, _
211  byval is_proto as integer _
212  ) as string
213 
214  dim as string ln
215 
216  assert( symbIsProc( proc ) )
217 
219 
220  '' Function result type (is 'void' for subs)
221  ln += hEmitType( typeGetDtAndPtrOnly( symbGetProcRealType( proc ) ), _
222  symbGetProcRealSubtype( proc ), TRUE )
223 
224  ln += " "
225 
226  '' @id
227  ln += *symbGetMangledName( proc )
228 
229  '' Parameter list
230  ln += "( "
231 
232  '' If returning a struct, there's an extra parameter
233  dim as FBSYMBOL ptr hidden = NULL
234  if( symbProcReturnsOnStack( proc ) ) then
235  if( is_proto ) then
236  hidden = symbGetSubType( proc )
237  ln += hEmitType( typeAddrOf( symbGetType( hidden ) ), hidden )
238  else
239  hidden = proc->proc.ext->res
240  ln += hEmitType( typeAddrOf( symbGetType( hidden ) ), symbGetSubtype( hidden ) )
241  ln += " " + hEmitParamName( hidden )
242  end if
243 
244  if( symbGetProcParams( proc ) > 0 ) then
245  ln += ", "
246  end if
247  end if
248 
249  var param = symbGetProcLastParam( proc )
250  while( param )
251  if( symbGetParamMode( param ) = FB_PARAMMODE_VARARG ) then
252  ln += "..."
253  else
254  var dtype = symbGetType( param )
255  var subtype = param->subtype
256  symbGetRealParamDtype( param->param.mode, dtype, subtype )
257  ln += hEmitType( dtype, subtype )
258 
259  if( is_proto = FALSE ) then
260  '' Proc body? Emit the mangled name of the param var
261  '' (the param itself isn't mangled)
262  ln += " " + hEmitParamName( symbGetParamVar( param ) )
263  end if
264  end if
265 
266  param = symbGetProcPrevParam( proc, param )
267  if( param ) then
268  ln += ", "
269  end if
270  wend
271 
272  ln += " )"
273 
274  '' Function attributes
275  '' TODO: clang emits this for C code, seems good for us too, but if
276  '' there will be exceptions, this must be removed...
277  ln += " nounwind"
278 
279  if( proc->attrib and FB_SYMBATTRIB_NAKED ) then
280  ln += " naked"
281  end if
282 
283  function = ln
284 end function
285 
286 function hGetUDTName( byval sym as FBSYMBOL ptr ) as string
287  dim as FBSYMBOL ptr ns = symbGetNamespace( sym )
288 
289  var s = "%"
290  do until( ns = @symbGetGlobalNamespc( ) )
291  s += *symbGetName( ns )
292  s += "."
293  ns = symbGetNamespace( ns )
294  loop
295 
296  if( sym->id.alias <> NULL ) then
297  s += *sym->id.alias
298  else
299  s += *symbGetName( sym )
300  end if
301 
302  function = s
303 end function
304 
305 sub hEmitUDT( byval s as FBSYMBOL ptr )
306  if( s = NULL ) then
307  return
308  end if
309 
310  if( symbGetIsEmitted( s ) ) then
311  return
312  end if
313 
314  var oldsection = ctx.section
315  if( symbIsLocal( s ) = FALSE ) then
317  end if
318 
319  select case as const( symbGetClass( s ) )
320  case FB_SYMBCLASS_ENUM
321  symbSetIsEmitted( s )
322  hWriteLine( hGetUDTName( s ) + " = type %integer" )
323 
324  case FB_SYMBCLASS_STRUCT
325  hEmitStruct( s )
326 
327  case FB_SYMBCLASS_PROC
328  if( symbGetIsFuncPtr( s ) ) then
329  hWriteLine( "typedef " + hEmitProcHeader( s, TRUE ) + "*" )
330  symbSetIsEmitted( s )
331  end if
332 
333  end select
334 
335  ctx.section = oldsection
336 end sub
337 
338 '' Returns "[N]" (N = array size) if the symbol is an array or a fixlen string.
339 function hEmitArrayDecl( byval sym as FBSYMBOL ptr ) as string
340  dim as string s
341 
342  '' Emit all array dimensions individually
343  '' (This lets array initializers rely on gcc to fill uninitialized
344  '' elements with zeroes)
345  select case( symbGetClass( sym ) )
346  case FB_SYMBCLASS_VAR, FB_SYMBCLASS_FIELD
347  if( (symbGetIsDynamic( sym ) = FALSE) and _
348  (symbGetArrayDimensions( sym ) <> 0) ) then
349  dim as FBVARDIM ptr d = symbGetArrayFirstDim( sym )
350  while( d )
351  '' elements = ubound( array, d ) - lbound( array, d ) + 1
352  s += "[" + str( d->upper - d->lower + 1 ) + "]"
353  d = d->next
354  wend
355  end if
356  end select
357 
358  '' If it's a fixed-length string, add an extra array dimension
359  '' (zstring * 5 becomes char[5])
360  dim as integer length = 0
361  select case( symbGetType( sym ) )
362  case FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR
363  length = symbGetStrLen( sym )
364  case FB_DATATYPE_WCHAR
365  length = symbGetWstrLen( sym )
366  end select
367  if( length > 0 ) then
368  s += "[" + str( length ) + "]"
369  end if
370 
371  function = s
372 end function
373 
374 sub hBuildStrLit _
375  ( _
376  byref ln as string, _
377  byval wantedlength as integer, _ '' including null terminator
378  byval z as zstring ptr, _
379  byval length as integer _ '' ditto
380  )
381 
382  dim as integer ch = any
383 
384  '' Convert the string to LLVM IR format
385  '' (assuming internal escape sequences have already been solved out
386  '' using hUnescape())
387  ''
388  '' clang turns
389  '' "a\0\\\n"
390  '' into
391  '' [5 x i8] c"a\00\5C\0A\00", align 1
392  ''
393  '' \0 doesn't work, it must be two digits as in \00.
394 
395  '' String literal too long?
396  if( length > wantedlength ) then
397  '' Cut off; may be empty afterwards
398  length = wantedlength
399  end if
400 
401  for i as integer = 0 to length - 1
402  ch = (*z)[i]
403  '' chars like a-zA-Z0-9 can be emitted literally,
404  '' but special chars (including '\') should be encoded in hex
405  if( hCharNeedsEscaping( ch, asc( """" ) ) ) then
406  '' emit in \XX escape form
407  ln += $"\" + hex( ch, 2 )
408  else
409  '' emit as-is
410  ln += chr( ch )
411  end if
412  next
413 
414  '' Pad with zeroes if string literal too short
415  while( length < wantedlength )
416  ln += $"\00"
417  length += 1
418  wend
419 end sub
420 
421 sub hBuildWstrLit _
422  ( _
423  byref ln as string, _
424  byval wantedlength as integer, _ '' including null terminator
425  byval w as wstring ptr, _
426  byval length as integer _ '' ditto
427  )
428 
429  dim as uinteger ch = any, wcharsize = any
430 
431  '' (ditto)
432  ''
433  '' clang turns
434  '' L"a\0\\\n"
435  '' into
436  '' [20 x i8] c"a\00\00\00\00\00\00\00\5C\00\00\00\0A\00\00\00\00\00\00\00", align 4
437  '' (with Linux 4-byte wchar_t)
438 
439  wcharsize = typeGetSize( FB_DATATYPE_WCHAR )
440 
441  '' String literal too long?
442  if( length > wantedlength ) then
443  '' Cut off; may be empty afterwards
444  length = wantedlength
445  end if
446 
447  for i as integer = 0 to length - 1
448  ch = (*w)[i]
449  '' (ditto)
450  if( hCharNeedsEscaping( ch, asc( """" ) ) ) then
451  if( wcharsize >= 1 ) then
452  ln += $"\" + hex( (ch ) and &hFF, 2 )
453  end if
454  if( wcharsize >= 2 ) then
455  ln += $"\" + hex( (ch shr 8) and &hFF, 2 )
456  end if
457  if( wcharsize >= 4 ) then
458  ln += $"\" + hex( (ch shr 16) and &hFF, 2 )
459  ln += $"\" + hex( (ch shr 24) and &hFF, 2 )
460  end if
461  else
462  ln += chr( ch )
463  '' Pad up to wchar_t size
464  for j as integer = 2 to wcharsize
465  ln += $"\00"
466  next
467  end if
468  next
469 
470  '' Pad with zeroes if string literal too short
471  while( length < wantedlength )
472  '' Pad up to wchar_t size
473  for j as integer = 1 to wcharsize
474  ln += $"\00"
475  next
476  length += 1
477  wend
478 end sub
479 
480 function hEmitStrLitType( byval length as integer ) as string
481  function = "[" + str( length ) + " x i8]"
482 end function
483 
484 function hEmitSymType( byval sym as FBSYMBOL ptr ) as string
485  select case( symbGetType( sym ) )
486  case FB_DATATYPE_FIXSTR, FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
487  function = hEmitStrLitType( symbGetLen( sym ) )
488  case else
489  function = hEmitType( symbGetType( sym ), symbGetSubtype( sym ) )
490  end select
491 end function
492 
493 sub hEmitVariable( byval sym as FBSYMBOL ptr )
494  dim as string ln
495  dim as integer is_global = any, length = any
496 
497  '' already allocated?
498  if( symbGetVarIsAllocated( sym ) ) then
499  exit sub
500  end if
501 
502  symbSetVarIsAllocated( sym )
503 
504  '' literal?
505  if( symbGetIsLiteral( sym ) ) then
506  if( symbGetIsAccessed( sym ) = FALSE ) then
507  exit sub
508  end if
509 
510  select case( symbGetType( sym ) )
511  case FB_DATATYPE_CHAR, FB_DATATYPE_WCHAR
512  '' string literals are emitted as global char arrays,
513  '' this also means a bitcast to char pointer is needed
514  '' on every use of the global symbol.
515  ln = *symbGetMangledName( sym ) + " = "
516  ln += "private constant "
517  ln += hEmitSymType( sym )
518  ln += " c"""
519  if( symbGetType( sym ) = FB_DATATYPE_WCHAR ) then
520  length = symbGetWstrLen( sym )
521  hBuildWstrLit( ln, length, hUnescapeW( symbGetVarLitTextW( sym ) ), length )
522  else
523  length = symbGetStrLen( sym )
524  hBuildStrLit( ln, length, hUnescape( symbGetVarLitText( sym ) ), length )
525  end if
526  ln += """"
527  hWriteLine( ln )
528  case else
529  '' float constants are handled as "literals",
530  '' at least under the ASM backend
531  end select
532 
533  exit sub
534  end if
535 
536  '' initialized? only if not local or local and static
537  if( symbGetIsInitialized( sym ) and (symbIsLocal( sym ) = FALSE or symbIsStatic( sym )) ) then
538  '' extern?
539  if( symbIsExtern( sym ) ) then
540  exit sub
541  end if
542 
543  '' never referenced?
544  if( symbIsLocal( sym ) = FALSE ) then
545  if( symbGetIsAccessed( sym ) = FALSE ) then
546  '' not public?
547  if( symbIsPublic( sym ) = FALSE ) then
548  exit sub
549  end if
550  end if
551  end if
552 
553  astTypeIniFlush( sym->var_.initree, sym, AST_INIOPT_ISINI or AST_INIOPT_ISSTATIC )
554  sym->var_.initree = NULL
555  exit sub
556  end if
557 
558  '' dynamic? only the array descriptor is emitted
559  if( symbGetIsDynamic( sym ) ) then
560  exit sub
561  end if
562 
563  '' a string or array descriptor?
564  if( symbGetLen( sym ) <= 0 ) then
565  exit sub
566  end if
567 
568  is_global = symbGetAttrib( sym ) and _
569  (FB_SYMBATTRIB_COMMON or FB_SYMBATTRIB_PUBLIC or _
570  FB_SYMBATTRIB_EXTERN or FB_SYMBATTRIB_STATIC or _
571  FB_SYMBATTRIB_SHARED)
572 
573  '' Global var:
574  '' @sym = global <type> <initvalue>
575  '' Stack var:
576  '' %sym = alloca <type>
577  ln = *symbGetMangledName( sym )
578  ln += " = "
579  if( is_global ) then
580  ln += "global"
581  else
582  ln += "alloca"
583  end if
584  ln += " " + hEmitSymType( sym )
585  if( is_global ) then
586  '' Globals without initializer are zeroed in FB
587  ln += " zeroinitializer"
588  end if
589  hWriteLine( ln )
590 end sub
591 
592 sub hEmitFuncProto( byval s as FBSYMBOL ptr )
593  if( symbGetIsAccessed( s ) = FALSE ) then
594  return
595  end if
596 
597  if( symbGetMangledName( s ) = NULL ) then
598  return
599  end if
600 
601  var oldsection = ctx.section
603 
604  '' gcc builtin? gen a wrapper..
605  if( symbGetIsGccBuiltin( s ) ) then
606  var cnt = 0
607  var param = symbGetProcLastParam( s )
608  var params = ""
609  do while( param <> NULL )
610  params += "temp_ppparam$" & cnt
611 
612  param = symbGetProcPrevParam( s, param )
613  if param then
614  params += ", "
615  end if
616 
617  cnt += 1
618  loop
619 
620  hWriteLine( "#define " & *symbGetMangledName( s ) & "( " & params & " ) " & _
621  "__builtin_" & *symbGetMangledName( s ) & "( " & params & " )" )
622  else
623  dim as string ln = "declare "
624  ln += hEmitProcHeader( s, TRUE )
625 
626  if( symbGetIsGlobalCtor( s ) ) then
627  ln += " __attribute__ ((constructor)) "
628  elseif( symbGetIsGlobalDtor( s ) ) then
629  ln += " __attribute__ ((destructor)) "
630  end if
631 
632  hWriteLine( ln )
633  end if
634 
635  ctx.section = oldsection
636 end sub
637 
638 sub hEmitStruct( byval s as FBSYMBOL ptr )
639  dim as FBSYMBOL ptr fld = any
640 
641  ''
642  '' Already emitting this UDT currently? This means there is a circular
643  '' dependency between this UDT and one (or multiple) other UDT(s).
644  '' Note: LLVM IR doesn't seem to require explicit declaration of
645  '' forward references, clang for example generates code like:
646  ''
647  '' %struct.T = type { %struct.T* }
648  '' %struct.XX = type { %struct.YY* }
649  '' %struct.YY = type { %struct.XX }
650  ''
651  '' On top of that, it seems to be possible to forward reference
652  '' structures even directly and not by pointer:
653  ''
654  '' %struct.XX = type { %struct.T }
655  '' %struct.T = type { %struct.T* }
656  ''
657  '' ... as long as the type will be fully declared before its first use
658  '' in a function/variable declaration etc. This makes UDT emitting
659  '' pretty easy compared to the C backend.
660  ''
661  if( symbGetIsBeingEmitted( s ) ) then
662  return
663  end if
664 
665  symbSetIsBeingEmitted( s )
666 
667  '' Check every field for non-emitted subtypes
668  fld = symbUdtGetFirstField( s )
669  while( fld )
670  hEmitUDT( symbGetSubtype( fld ) )
671  fld = symbUdtGetNextField( fld )
672  wend
673 
674  '' Was it emitted in the mean time? (maybe one of the fields did that)
675  if( symbGetIsEmitted( s ) ) then
676  return
677  end if
678 
679  '' We'll emit it now.
680  symbSetIsEmitted( s )
681 
682  dim as string ln
683 
684  '' UDT name
685  if( symbGetName( s ) ) then
686  ln += hGetUDTName( s )
687  else
688  ln += "%" + *symbUniqueId( )
689  end if
690 
691  ln += " = type { "
692 
693  '' Alignment (field = N)
694  var attrib = ""
695  if( s->udt.align > 0 ) then
696  if( s->udt.align = 1 ) then
697  attrib = " __attribute__((packed))"
698  else
699  attrib = " __attribute__((aligned (" & s->udt.align & ")))"
700  end if
701  end if
702 
703  '' Write out the elements
704  fld = symbUdtGetFirstField( s )
705  while( fld )
706  ln += hEmitSymType( fld )
707  ln += hEmitArrayDecl( fld )
708  ln += attrib
709 
710  fld = symbUdtGetNextField( fld )
711  if( fld ) then
712  ln += ", "
713  end if
714  wend
715 
716  '' Close UDT body
717  ln += " }"
718 
719  hWriteLine( ln )
720 
721  symbResetIsBeingEmitted( s )
722 end sub
723 
724 sub hEmitDecls( byval s as FBSYMBOL ptr, byval procs as integer = FALSE )
725  while( s )
726  select case as const( symbGetClass( s ) )
727  case FB_SYMBCLASS_NAMESPACE
728  hEmitDecls( symbGetNamespaceTbHead( s ), procs )
729 
730  case FB_SYMBCLASS_STRUCT
731  hEmitDecls( symbGetCompSymbTb( s ).head, procs )
732 
733  case FB_SYMBCLASS_SCOPE
734  hEmitDecls( symbGetScopeSymbTbHead( s ), procs )
735 
736  case FB_SYMBCLASS_VAR
737  if( procs = FALSE ) then
738  hEmitVariable( s )
739  end if
740 
741  case FB_SYMBCLASS_PROC
742  if( procs ) then
743  if( symbGetIsFuncPtr( s ) = FALSE ) then
744  hEmitFuncProto( s )
745  end if
746  end if
747 
748  end select
749 
750  s = s->next
751  wend
752 end sub
753 
755  var s = astGetLastDataStmtSymbol( )
756  while( s )
757  hEmitVariable( s )
758  s = s->var_.data.prev
759  wend
760 end sub
761 
763  if( ctx.forwardlist.lastitem = NULL ) then
764  return
765  end if
766 
767  dim as FBSYMBOL ptr s = flistGetHead( @ctx.forwardlist )
768  while( s )
769  hEmitUDT( s )
770  s = flistGetNext( s )
771  wend
772 
774 end sub
775 
776 sub hWriteFTOI _
777  ( _
778  byref fname as string, _
779  byval rtype as integer, _
780  byval ptype as integer _
781  )
782 
783  dim as string rtype_str, rtype_suffix
784  select case rtype
785  case FB_DATATYPE_INTEGER
786  rtype_str = "integer"
787  rtype_suffix = "l"
788 
789  case FB_DATATYPE_LONGINT
790  rtype_str = "longint"
791  rtype_suffix = "q"
792  end select
793 
794  dim as string ptype_str, ptype_suffix
795  select case ptype
796  case FB_DATATYPE_SINGLE
797  ptype_str = "single"
798  ptype_suffix = "s"
799 
800  case FB_DATATYPE_DOUBLE
801  ptype_str = "double"
802  ptype_suffix = "l"
803  end select
804 
805  '' TODO: x86 specific
806  hWriteLine( "static inline " & rtype_str & " fb_" & fname & " ( " & ptype_str & !" value ) {\n" & _
807  !"\tvolatile " & rtype_str & !" result;\n" & _
808  !"\t__asm__ (\n" & _
809  !"\t\t\"fld" & ptype_suffix & !" %1;\"\n" & _
810  !"\t\t\"fistp" & rtype_suffix & !" %0;\"\n" & _
811  !"\t\t:\"=m\" (result)\n" & _
812  !"\t\t:\"m\" (value)\n" & _
813  !"\t);\n" & _
814  !"\treturn result;\n" & _
815  !"}" )
816 
817 end sub
818 
820  '' Special conversion routines for:
821  '' single/double -> [unsigned] byte/short/integer/longint
822  '' (which one will be used where is determined at AST/RTL)
823  ''
824  '' Simple C casting as in '(int)floatvar' cannot be used because it
825  '' just truncates instead of rounding to nearest.
826  ''
827  '' There are at max 4 routines generated:
828  '' single -> int
829  '' single -> longint
830  '' double -> int
831  '' double -> longint
832  '' and all other cases reuse those.
833  ''
834  '' A special case to watch out for: float -> unsigned int conversions.
835  '' When converting to unsigned integer, it has to be converted to
836  '' longint first, to avoid truncating to signed integer. That's a
837  '' limitation of the ASM routines, and the ASM emitter is having the
838  '' same problem, see emit_x86.bas:_emitLOADF2I() & co.
839 
840  '' single
841  if( symbGetIsAccessed( PROCLOOKUP( FTOSL ) ) or _
842  symbGetIsAccessed( PROCLOOKUP( FTOUL ) ) or _
843  symbGetIsAccessed( PROCLOOKUP( FTOUI ) ) ) then
844  hWriteFTOI( "ftosl", FB_DATATYPE_LONGINT, FB_DATATYPE_SINGLE )
845  end if
846 
847  if( symbGetIsAccessed( PROCLOOKUP( FTOUL ) ) ) then
848  hWriteLine( "#define fb_ftoul( v ) (ulongint)fb_ftosl( v )" )
849  end if
850 
851  if( symbGetIsAccessed( PROCLOOKUP( FTOUI ) ) ) then
852  hWriteLine( "#define fb_ftoui( v ) (uinteger)fb_ftosl( v )" )
853  end if
854 
855  if( symbGetIsAccessed( PROCLOOKUP( FTOSI ) ) or _
856  symbGetIsAccessed( PROCLOOKUP( FTOSS ) ) or _
857  symbGetIsAccessed( PROCLOOKUP( FTOUS ) ) or _
858  symbGetIsAccessed( PROCLOOKUP( FTOSB ) ) or _
859  symbGetIsAccessed( PROCLOOKUP( FTOUB ) ) ) then
860  hWriteFTOI( "ftosi", FB_DATATYPE_INTEGER, FB_DATATYPE_SINGLE )
861  end if
862 
863  if( symbGetIsAccessed( PROCLOOKUP( FTOSS ) ) ) then
864  hWriteLine( "#define fb_ftoss( v ) (short)fb_ftosi( v )" )
865  end if
866 
867  if( symbGetIsAccessed( PROCLOOKUP( FTOUS ) ) ) then
868  hWriteLine( "#define fb_ftous( v ) (ushort)fb_ftosi( v )" )
869  end if
870 
871  if( symbGetIsAccessed( PROCLOOKUP( FTOSB ) ) ) then
872  hWriteLine( "#define fb_ftosb( v ) (byte)fb_ftosi( v )" )
873  end if
874 
875  if( symbGetIsAccessed( PROCLOOKUP( FTOUB ) ) ) then
876  hWriteLine( "#define fb_ftoub( v ) (ubyte)fb_ftosi( v )" )
877  end if
878 
879  '' double
880  if( symbGetIsAccessed( PROCLOOKUP( DTOSL ) ) or _
881  symbGetIsAccessed( PROCLOOKUP( DTOUL ) ) or _
882  symbGetIsAccessed( PROCLOOKUP( DTOUI ) ) ) then
883  hWriteFTOI( "dtosl", FB_DATATYPE_LONGINT, FB_DATATYPE_DOUBLE )
884  end if
885 
886  if( symbGetIsAccessed( PROCLOOKUP( DTOUL ) ) ) then
887  hWriteLine( "#define fb_dtoul( v ) (ulongint)fb_dtosl( v )" )
888  end if
889 
890  if( symbGetIsAccessed( PROCLOOKUP( DTOUI ) ) ) then
891  hWriteLine( "#define fb_dtoui( v ) (uinteger)fb_dtosl( v )" )
892  end if
893 
894  if( symbGetIsAccessed( PROCLOOKUP( DTOSI ) ) or _
895  symbGetIsAccessed( PROCLOOKUP( DTOSS ) ) or _
896  symbGetIsAccessed( PROCLOOKUP( DTOUS ) ) or _
897  symbGetIsAccessed( PROCLOOKUP( DTOSB ) ) or _
898  symbGetIsAccessed( PROCLOOKUP( DTOUB ) ) ) then
899  hWriteFTOI( "dtosi", FB_DATATYPE_INTEGER, FB_DATATYPE_DOUBLE )
900  end if
901 
902  if( symbGetIsAccessed( PROCLOOKUP( DTOSS ) ) ) then
903  hWriteLine( "#define fb_dtoss( v ) (short)fb_dtosi( v )" )
904  end if
905 
906  if( symbGetIsAccessed( PROCLOOKUP( DTOUS ) ) ) then
907  hWriteLine( "#define fb_dtous( v ) (ushort)fb_dtosi( v )" )
908  end if
909 
910  if( symbGetIsAccessed( PROCLOOKUP( DTOSB ) ) ) then
911  hWriteLine( "#define fb_dtosb( v ) (byte)fb_dtosi( v )" )
912  end if
913 
914  if( symbGetIsAccessed( PROCLOOKUP( DTOUB ) ) ) then
915  hWriteLine( "#define fb_dtoub( v ) (ubyte)fb_dtosi( v )" )
916  end if
917 
918 end sub
919 
920 function _emitBegin( ) as integer
921  if( hFileExists( env.outf.name ) ) then
922  kill env.outf.name
923  end if
924 
925  env.outf.num = freefile
926  if( open( env.outf.name, for binary, access read write, as #env.outf.num ) <> 0 ) then
927  return FALSE
928  end if
929 
930  ctx.identcnt = 0
931  ctx.regcnt = 0
932  ctx.lblcnt = 0
933  ctx.tmpcnt = 0
934  ctx.head_txt = ""
935  ctx.body_txt = ""
936  ctx.foot_txt = ""
937  ctx.linenum = 0
941 
942  if( env.clopt.debug ) then
943  _emitDBG( AST_OP_DBG_LINEINI, NULL, 0 )
944  end if
945 
946  hWriteLine( "; Compilation of " + env.inf.name + " started at " + time( ) + " on " + date( ) )
947 
948  '' Some named types we use to make the output more readable
949  hWriteLine( "" )
950  hWriteLine( "%any = type i8" )
951  hWriteLine( "%byte = type i8" )
952  hWriteLine( "%short = type i16" )
953  hWriteLine( "%integer = type i32" )
954  hWriteLine( "%long = type i32" ) '' TODO: 64-bit
955  hWriteLine( "%longint = type i64" )
956  hWriteLine( "%single = type float" )
957  hWriteLine( "%double = type double" )
958  hWriteLine( "%string = type { i8*, i32, i32 }" )
959  hWriteLine( "%fixstr = type i8" )
960  hWriteLine( "%char = type i8" )
961  hWriteLine( "%wchar = type i" + str( typeGetBits( FB_DATATYPE_WCHAR ) ) )
962 
964 
965  function = TRUE
966 end function
967 
968 sub _emitEnd( byval tottime as double )
969  ' Add the decls on the end of the header
971 
972  if( ctx.memset_used ) then
973  hWriteLine( "declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1) nounwind" )
974  end if
975  if( ctx.memmove_used ) then
976  hWriteLine( "declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1) nounwind" )
977  end if
978 
980 
981  hEmitDataStmt( )
982 
983  '' Emit proc decls first (because of function pointer initializers referencing procs)
984  hWriteLine( "" )
985  hEmitDecls( symbGetGlobalTbHead( ), TRUE )
986 
987  '' Then the variables
988  hWriteLine( "" )
989  hEmitDecls( symbGetGlobalTbHead( ), FALSE )
990 
992 
994 
995  hWriteLine( "" )
996  hWriteLine( "; Total compilation time: " & tottime & " seconds. " )
997 
998  ' flush all sections to file
999  if( put( #env.outf.num, , ctx.head_txt ) <> 0 ) then
1000  end if
1001  if( put( #env.outf.num, , ctx.body_txt ) <> 0 ) then
1002  end if
1003  if( put( #env.outf.num, , ctx.foot_txt ) <> 0 ) then
1004  end if
1005 
1006  if( close( #env.outf.num ) <> 0 ) then
1007  '' ...
1008  end if
1009 
1010  env.outf.num = 0
1011 end sub
1012 
1013 function _getOptionValue( byval opt as IR_OPTIONVALUE ) as integer
1014  select case opt
1015  case IR_OPTIONVALUE_MAXMEMBLOCKLEN
1016  return 0
1017  case else
1018  errReportEx( FB_ERRMSG_INTERNAL, __FUNCTION__ )
1019  end select
1020 end function
1021 
1022 sub _procBegin( byval proc as FBSYMBOL ptr )
1023  proc->proc.ext->dbg.iniline = lexLineNum( )
1024 end sub
1025 
1026 sub _procEnd( byval proc as FBSYMBOL ptr )
1027  proc->proc.ext->dbg.endline = lexLineNum( )
1028 end sub
1029 
1030 sub _procAllocArg _
1031  ( _
1032  byval proc as FBSYMBOL ptr, _
1033  byval sym as FBSYMBOL ptr _
1034  )
1035 
1036  dim as string ln
1037  dim as integer parammode = any
1038 
1039  ''
1040  '' Load the parameter values into local stack vars, to support taking
1041  '' the address of the parameters on stack.
1042  ''
1043  '' This means there are two symbols per parameter:
1044  '' - the parameter value in the procedure header
1045  '' - the alloca operation representing the stack var
1046  '' they must use different names to avoid collision.
1047  ''
1048 
1049  if( symbIsParamByref( sym ) ) then
1050  parammode = FB_PARAMMODE_BYREF
1051  elseif( symbIsParamBydesc( sym ) ) then
1052  parammode = FB_PARAMMODE_BYDESC
1053  else
1054  assert( symbIsParamByval( sym ) )
1055  parammode = FB_PARAMMODE_BYVAL
1056  end if
1057 
1058  var dtype = symbGetType( sym )
1059  var subtype = sym->subtype
1060  symbGetRealParamDtype( parammode, dtype, subtype )
1061 
1062  '' %myparam = alloca type
1063  ln = *symbGetMangledName( sym ) + " = alloca "
1064  ln += hEmitType( dtype, subtype )
1065  hWriteLine( ln )
1066 
1067  '' store type %myparam$, type* %myparam
1068  ln = "store "
1069  ln += hEmitType( dtype, subtype ) + " " + hEmitParamName( sym )
1070  ln += ", "
1071  ln += hEmitType( typeAddrOf( dtype ), subtype ) + " " + *symbGetMangledName( sym )
1072  hWriteLine( ln )
1073 
1074 end sub
1075 
1076 sub _procAllocLocal _
1077  ( _
1078  byval proc as FBSYMBOL ptr, _
1079  byval sym as FBSYMBOL ptr _
1080  )
1081 
1082  hEmitVariable( sym )
1083 
1084 end sub
1085 
1086 sub _scopeBegin( byval s as FBSYMBOL ptr )
1087 end sub
1088 
1089 sub _scopeEnd( byval s as FBSYMBOL ptr )
1090 end sub
1091 
1092 sub _procAllocStaticVars(byval head_sym as FBSYMBOL ptr)
1093 /' do nothing '/
1094 end sub
1095 
1096 function hNewVR _
1097  ( _
1098  byval dtype as integer, _
1099  byval subtype as FBSYMBOL ptr, _
1100  byval vtype as integer _
1101  ) as IRVREG ptr
1102 
1103  dim as IRVREG ptr v = any
1104 
1105  v = flistNewItem( @ctx.vregTB )
1106 
1107  v->typ = vtype
1108  v->dtype = dtype
1109  v->subtype = subtype
1110  v->sym = NULL
1111  if( vtype = IR_VREGTYPE_REG ) then
1112  v->reg = ctx.regcnt
1113  ctx.regcnt += 1
1114  else
1115  v->reg = INVALID
1116  end if
1117  v->vidx = NULL
1118  v->ofs = 0
1119 
1120  function = v
1121 end function
1122 
1123 function _allocVreg _
1124  ( _
1125  byval dtype as integer, _
1126  byval subtype as FBSYMBOL ptr _
1127  ) as IRVREG ptr
1128 
1129  function = hNewVR( dtype, subtype, IR_VREGTYPE_REG )
1130 
1131 end function
1132 
1133 function _allocVrImm _
1134  ( _
1135  byval dtype as integer, _
1136  byval subtype as FBSYMBOL ptr, _
1137  byval value as longint _
1138  ) as IRVREG ptr
1139 
1140  dim as IRVREG ptr vr = any
1141 
1142  vr = hNewVR( dtype, subtype, IR_VREGTYPE_IMM )
1143  vr->value.i = value
1144 
1145  function = vr
1146 end function
1147 
1148 function _allocVrImmF _
1149  ( _
1150  byval dtype as integer, _
1151  byval subtype as FBSYMBOL ptr, _
1152  byval value as double _
1153  ) as IRVREG ptr
1154 
1155  dim as IRVREG ptr vr = any
1156 
1157  vr = hNewVR( dtype, subtype, IR_VREGTYPE_IMM )
1158  vr->value.f = value
1159 
1160  function = vr
1161 end function
1162 
1163 function _allocVrVar _
1164  ( _
1165  byval dtype as integer, _
1166  byval subtype as FBSYMBOL ptr, _
1167  byval symbol as FBSYMBOL ptr, _
1168  byval ofs as longint _
1169  ) as IRVREG ptr
1170 
1171  dim as IRVREG ptr vr = hNewVR( dtype, subtype, IR_VREGTYPE_VAR )
1172 
1173  vr->sym = symbol
1174  vr->ofs = ofs
1175 
1176  function = vr
1177 
1178 end function
1179 
1180 function _allocVrIdx _
1181  ( _
1182  byval dtype as integer, _
1183  byval subtype as FBSYMBOL ptr, _
1184  byval symbol as FBSYMBOL ptr, _
1185  byval ofs as longint, _
1186  byval mult as integer, _
1187  byval vidx as IRVREG ptr _
1188  ) as IRVREG ptr
1189 
1190  dim as IRVREG ptr vr = hNewVR( dtype, subtype, IR_VREGTYPE_IDX )
1191 
1192  vr->sym = symbol
1193  vr->ofs = ofs
1194  vr->vidx = vidx
1195 
1196  function = vr
1197 
1198 end function
1199 
1200 function _allocVrPtr _
1201  ( _
1202  byval dtype as integer, _
1203  byval subtype as FBSYMBOL ptr, _
1204  byval ofs as longint, _
1205  byval vidx as IRVREG ptr _
1206  ) as IRVREG ptr
1207 
1208  dim as IRVREG ptr vr = hNewVR( dtype, subtype, IR_VREGTYPE_PTR )
1209 
1210  vr->ofs = ofs
1211  vr->vidx = vidx
1212 
1213  function = vr
1214 
1215 end function
1216 
1217 function _allocVrOfs _
1218  ( _
1219  byval dtype as integer, _
1220  byval subtype as FBSYMBOL ptr, _
1221  byval symbol as FBSYMBOL ptr, _
1222  byval ofs as longint _
1223  ) as IRVREG ptr
1224 
1225  dim as IRVREG ptr vr = hNewVR( dtype, subtype, IR_VREGTYPE_OFS )
1226 
1227  vr->sym = symbol
1228  vr->ofs = ofs
1229 
1230  function = vr
1231 
1232 end function
1233 
1234 sub _setVregDataType _
1235  ( _
1236  byval v as IRVREG ptr, _
1237  byval dtype as integer, _
1238  byval subtype as FBSYMBOL ptr _
1239  )
1240 
1241  dim as IRVREG ptr temp0 = any
1242 
1243  if( (v->dtype <> dtype) or (v->subtype <> subtype) ) then
1244  temp0 = _allocVreg( dtype, subtype )
1245  _emitConvert( temp0, v )
1246  *v = *temp0
1247  end if
1248 
1249 end sub
1250 
1251 sub hPrepareAddress( byval v as IRVREG ptr )
1252  dim as integer dtype = any, ofs = any
1253  dim as FBSYMBOL ptr subtype = any
1254  dim as IRVREG ptr vidx = any, temp0 = any
1255 
1256  assert( (v->typ = IR_VREGTYPE_VAR) or _
1257  (v->typ = IR_VREGTYPE_IDX) or _
1258  (v->typ = IR_VREGTYPE_PTR) )
1259 
1260  '' Treat memory access as address - turn it into a REG.
1261  '' If there is an offset or index, it must be added on top of the
1262  '' base address.
1263  dtype = v->dtype
1264  subtype = v->subtype
1265  ofs = v->ofs
1266  vidx = v->vidx
1267 
1268  select case( v->typ )
1269  case IR_VREGTYPE_PTR
1270  assert( irIsREG( vidx ) )
1271  *v = *vidx
1272  case else
1273  v->typ = IR_VREGTYPE_REG
1274  v->dtype = typeAddrOf( v->dtype )
1275  v->reg = INVALID
1276  v->ofs = 0
1277  end select
1278 
1279  if( (vidx <> NULL) or (ofs <> 0) ) then
1280  '' temp0 = ptrtoint l
1281  temp0 = _allocVreg( FB_DATATYPE_INTEGER, NULL )
1282  _emitConvert( temp0, v )
1283 
1284  if( ofs <> 0 ) then
1285  '' temp0 add= <offset>
1286  _emitBop( AST_OP_ADD, temp0, _allocVrImm( FB_DATATYPE_INTEGER, NULL, ofs ), NULL, NULL )
1287  end if
1288 
1289  '' temp0 = inttoptr temp0
1290  _setVregDataType( temp0, typeAddrOf( dtype ), subtype )
1291 
1292  *v = *temp0
1293  end if
1294 end sub
1295 
1296 sub hLoadVreg( byval v as IRVREG ptr )
1297  dim as string ln
1298  dim as IRVREG ptr temp0 = any
1299 
1300  '' LLVM instructions take registers or immediates (including offsets,
1301  '' i.e. addresses of globals/procedures),
1302  '' anything else must be loaded into a register first.
1303  '' (register in LLVM just means a <%N = insn ...> temporary value)
1304 
1305  select case( v->typ )
1306  case IR_VREGTYPE_REG, IR_VREGTYPE_IMM
1307 
1308  case IR_VREGTYPE_OFS
1309  '' global symbol address
1310  ''
1311  '' with offset:
1312  '' %0 = ptrtoint foo* @global to i32
1313  '' %1 = add i32 %0, i32 <offset>
1314  '' %2 = inttoptr i32 %1 to foo*
1315  ''
1316  '' without offset:
1317  '' (no "loading" necessary, handled purely in hVregToStr())
1318  '' @global
1319  if( v->ofs <> 0 ) then
1320  '' temp0 = ptrtoint v
1321  temp0 = _allocVreg( FB_DATATYPE_INTEGER, NULL )
1322  _emitConvert( temp0, v )
1323 
1324  '' temp0 add= <offset>
1325  _emitBop( AST_OP_ADD, temp0, _allocVrImm( FB_DATATYPE_INTEGER, NULL, v->ofs ), NULL, NULL )
1326 
1327  '' temp0 = inttoptr temp0
1328  _setVregDataType( temp0, v->dtype, v->subtype )
1329 
1330  *v = *temp0
1331  end if
1332 
1333  case else
1334  '' memory accesses: stack vars, arrays, ptr derefs
1335  '' Get the address and then load the value stored there.
1336 
1337  hPrepareAddress( v )
1338 
1339  temp0 = _allocVreg( typeDeref( v->dtype ), v->subtype )
1340  hWriteLine( hVregToStr( temp0 ) + " = load " + hEmitType( v->dtype, v->subtype ) + " " + hVregToStr( v ) )
1341  *v = *temp0
1342 
1343  end select
1344 end sub
1345 
1346 function hEmitType _
1347  ( _
1348  byval dtype as integer, _
1349  byval subtype as FBSYMBOL ptr, _
1350  byval is_result as integer _
1351  ) as string
1352 
1353  '' same order as FB_DATATYPE
1354  static as const zstring ptr dtypeName(0 to FB_DATATYPES-1) = _
1355  { _
1356  @"%any" , _ '' void
1357  @"%byte" , _ '' byte
1358  @"%byte" , _ '' ubyte
1359  @"%char" , _ '' char
1360  @"%short" , _ '' short
1361  @"%short" , _ '' ushort
1362  @"%wchar" , _ '' wchar
1363  @"%integer" , _ '' int
1364  @"%integer" , _ '' uint
1365  NULL , _ '' enum
1366  NULL , _ '' bitfield
1367  @"%long" , _ '' long
1368  @"%long" , _ '' ulong
1369  @"%longint" , _ '' longint
1370  @"%longint" , _ '' ulongint
1371  @"%single" , _ '' single
1372  @"%double" , _ '' double
1373  @"%string" , _ '' string
1374  @"%fixstr" , _ '' fix-len string
1375  NULL , _ '' struct
1376  NULL , _ '' namespace
1377  NULL , _ '' function
1378  NULL , _ '' fwd-ref
1379  NULL _ '' pointer
1380  }
1381 
1382  dim as string s
1383  dim as integer ptrcount = typeGetPtrCnt( dtype )
1384  dtype = typeGetDtOnly( dtype )
1385 
1386  select case as const( dtype )
1387  case FB_DATATYPE_STRUCT, FB_DATATYPE_ENUM
1388  if( subtype ) then
1389  hEmitUDT( subtype )
1390  s = hGetUDTName( subtype )
1391  elseif( dtype = FB_DATATYPE_ENUM ) then
1392  dtype = FB_DATATYPE_INTEGER
1393  else
1394  dtype = FB_DATATYPE_VOID
1395  end if
1396 
1397  case FB_DATATYPE_FUNCTION
1398  ptrcount -= 1
1399  hEmitUDT( subtype )
1400  s = *symbGetMangledName( subtype )
1401 
1402  case FB_DATATYPE_STRING, FB_DATATYPE_WCHAR
1403  if( is_result ) then
1404  if( ptrcount = 0 ) then
1405  ptrcount = 1
1406  end if
1407  end if
1408 
1409  case FB_DATATYPE_BITFIELD
1410  if( subtype ) then
1411  dtype = symbGetType( subtype )
1412  else
1413  dtype = FB_DATATYPE_INTEGER
1414  end if
1415 
1416  case FB_DATATYPE_VOID
1417  '' void* isn't allowed in LLVM IR, i8* can be used instead,
1418  '' that's why %any is aliased to i8. "void" will almost never
1419  '' be used, except for subs.
1420  if( ptrcount = 0 ) then
1421  s = "void"
1422  end if
1423 
1424  end select
1425 
1426  if( len( s ) = 0 ) then
1427  s = *dtypeName(dtype)
1428  end if
1429 
1430  if( ptrcount > 0 ) then
1431  s += string( ptrcount, "*" )
1432  end if
1433 
1434  function = s
1435 end function
1436 
1437 function hEmitInt _
1438  ( _
1439  byval dtype as integer, _
1440  byval subtype as FBSYMBOL ptr, _
1441  byval value as integer _
1442  ) as string
1443 
1444  dim as string s
1445 
1446  select case( dtype )
1447  case FB_DATATYPE_INTEGER, FB_DATATYPE_UINT, _
1448  FB_DATATYPE_LONG, FB_DATATYPE_ULONG, _
1449  FB_DATATYPE_ENUM
1450  '' It seems like llc doesn't care whether we emit -1 or
1451  '' 4294967295, it's the bit pattern that matters.
1452  s = str( value )
1453 
1454  case else
1455  '' cast the i32 constant to pointer/byte/short type
1456  '' <castop> (i32 <n> to <type>)
1457  if( typeIsPtr( dtype ) ) then
1458  s = "inttoptr "
1459  else
1460  s = "trunc "
1461  end if
1462  s += "("
1463  s += hEmitType( FB_DATATYPE_INTEGER, NULL ) + " " + str( value )
1464  s += " to " + hEmitType( dtype, subtype )
1465  s += ")"
1466  end select
1467 
1468  function = s
1469 end function
1470 
1471 function hEmitLong( byval value as longint ) as string
1472  function = str( value )
1473 end function
1474 
1475 function hEmitFloat( byval value as double ) as string
1476  '' Single/double float constants can be emitted as decimals or
1477  '' as raw bytes in 0x hex notation with 16 digits (even singles must
1478  '' be emitted as doubles, i.e. 16 hex digits, according to the LangRef).
1479  '' We always use the raw hex form, that avoids any rounding issues
1480  '' or errors with the decimals...
1481  function = "0x" + hex( *cptr( ulongint ptr, @value ), 16 )
1482 end function
1483 
1484 function hVregToStr( byval v as IRVREG ptr ) as string
1485  dim as string s
1486  dim as FBSYMBOL ptr sym = any
1487 
1488  select case as const( v->typ )
1489  case IR_VREGTYPE_VAR, IR_VREGTYPE_IDX, IR_VREGTYPE_PTR
1490  s = *symbGetMangledName( v->sym )
1491 
1492  case IR_VREGTYPE_OFS
1493  assert( v->ofs = 0 ) '' TODO
1494 
1495  sym = v->sym
1496  if( symbGetIsLiteral( sym ) ) then
1497  '' Use an inline bitcast operation to convert from
1498  '' the char array pointer type to just a char pointer
1499  s = "bitcast ("
1500  s += hEmitSymType( sym ) + "* "
1501  s += *symbGetMangledName( sym )
1502  s += " to "
1503  s += hEmitType( typeAddrOf( symbGetType( sym ) ), NULL )
1504  s += ")"
1505  else
1506  s = *symbGetMangledName( sym )
1507  end if
1508 
1509  case IR_VREGTYPE_IMM
1510  if( typeGetClass( v->dtype ) = FB_DATACLASS_FPOINT ) then
1511  s = hEmitFloat( v->value.f )
1512  elseif( typeGetSize( v->dtype ) = 8 ) then
1513  s = hEmitLong( v->value.i )
1514  else
1515  s = hEmitInt( v->dtype, v->subtype, v->value.i )
1516  end if
1517 
1518  case IR_VREGTYPE_REG
1519  if( v->sym ) then
1520  s = *symbGetMangledName( v->sym )
1521  else
1522  s = "%vr" + str( v->reg )
1523  end if
1524 
1525  end select
1526 
1527  function = s
1528 end function
1529 
1530 sub _emitLabel( byval label as FBSYMBOL ptr )
1531  '' end current basic block
1532  hWriteLine( "br label %" + *symbGetMangledName( label ) )
1533 
1534  '' and start the next one
1535  hWriteLabel( symbGetMangledName( label ) )
1536 end sub
1537 
1538 function hGetBopCode _
1539  ( _
1540  byval op as integer, _
1541  byval dtype as integer _
1542  ) as zstring ptr
1543 
1544  select case as const( op )
1545  case AST_OP_ADD
1546  if( typeGetClass( dtype ) = FB_DATACLASS_FPOINT ) then
1547  function = @"fadd"
1548  else
1549  function = @"add"
1550  end if
1551  case AST_OP_SUB
1552  if( typeGetClass( dtype ) = FB_DATACLASS_FPOINT ) then
1553  function = @"fsub"
1554  else
1555  function = @"sub"
1556  end if
1557  case AST_OP_MUL
1558  if( typeGetClass( dtype ) = FB_DATACLASS_FPOINT ) then
1559  function = @"fmul"
1560  else
1561  function = @"mul"
1562  end if
1563  case AST_OP_DIV
1564  function = @"fdiv"
1565  case AST_OP_INTDIV
1566  function = @"sdiv"
1567  case AST_OP_MOD
1568  if( typeGetClass( dtype ) = FB_DATACLASS_FPOINT ) then
1569  function = @"frem"
1570  else
1571  function = @"srem"
1572  end if
1573  case AST_OP_SHL
1574  function = @"shl"
1575  case AST_OP_SHR
1576  function = @"ashr"
1577  case AST_OP_AND
1578  function = @"and"
1579  case AST_OP_OR
1580  function = @"or"
1581  case AST_OP_XOR
1582  function = @"xor"
1583  case AST_OP_EQ
1584  function = @"icmp eq"
1585  case AST_OP_NE
1586  function = @"icmp ne"
1587  case AST_OP_GT
1588  function = @"icmp sgt"
1589  case AST_OP_LT
1590  function = @"icmp slt"
1591  case AST_OP_GE
1592  function = @"icmp sge"
1593  case AST_OP_LE
1594  function = @"icmp sle"
1595  case AST_OP_EQV
1596  '' TODO: vr = not (v1 xor v2)
1597  function = @"eqv"
1598  case AST_OP_IMP
1599  '' TODO: vr = (not v1) or v2
1600  function = @"imp"
1601 
1602  end select
1603 
1604 end function
1605 
1606 sub _emitBop _
1607  ( _
1608  byval op as integer, _
1609  byval v1 as IRVREG ptr, _
1610  byval v2 as IRVREG ptr, _
1611  byval vr as IRVREG ptr, _
1612  byval ex as FBSYMBOL ptr _
1613  )
1614 
1615  dim as string ln, falselabel
1616  dim as IRVREG ptr vresult = any, vtemp = any
1617  dim as integer is_comparison = any
1618 
1619  '' Conditional branch?
1620  select case( op )
1621  case AST_OP_EQ, AST_OP_NE, AST_OP_GT, AST_OP_LT, AST_OP_GE, AST_OP_LE
1622  is_comparison = TRUE
1623  case else
1624  is_comparison = FALSE
1625  end select
1626 
1627  '' Conditional branch?
1628  if( is_comparison and (vr = NULL) ) then
1629  hLoadVreg( v1 )
1630  hLoadVreg( v2 )
1631  _setVregDataType( v2, v1->dtype, v1->subtype )
1632  vresult = _allocVreg( FB_DATATYPE_INTEGER, NULL )
1633 
1634  '' condition = comparison expression
1635  ln = hVregToStr( vresult ) + " = "
1636  ln += *hGetBopCode( op, v1->dtype )
1637  ln += " "
1638  ln += hEmitType( v1->dtype, v1->subtype )
1639  ln += " "
1640  ln += hVregToStr( v1 )
1641  ln += ", "
1642  ln += hVregToStr( v2 )
1643  hWriteLine( ln )
1644 
1645  '' The conditional branch in LLVM always needs both
1646  '' true and false labels, to keep the proper basic
1647  '' block semantics up.
1648  '' true label = the label given through the BOP,
1649  '' false label = the code right behind the branch
1650 
1651  '' branch condition, truelabel, falselabel
1652  falselabel = *symbUniqueLabel( )
1653  ln = "br i1 " + hVregToStr( vresult )
1654  ln += ", "
1655  ln += "label %" + *symbGetMangledName( ex )
1656  ln += ", "
1657  ln += "label %" + falselabel
1658  hWriteLine( ln )
1659 
1660  '' falselabel:
1661  hWriteLabel( falselabel )
1662  exit sub
1663  end if
1664 
1665  '' If it's a self-bop, we need to allocate a result REG and then
1666  '' store that into v1 later.
1667  if( vr ) then
1668  '' vr = v1 bop b2
1669  assert( irIsREG( vr ) )
1670  vresult = vr
1671  else
1672  '' v1 bop= b2
1673  vresult = _allocVreg( v1->dtype, v1->subtype )
1674  end if
1675 
1676  hLoadVreg( v1 )
1677  hLoadVreg( v2 )
1678  _setVregDataType( v1, vresult->dtype, vresult->subtype )
1679  _setVregDataType( v2, vresult->dtype, vresult->subtype )
1680 
1681  ln = hVregToStr( vresult )
1682  ln += " = "
1683  ln += *hGetBopCode( op, vresult->dtype )
1684  ln += " "
1685  ln += hEmitType( vresult->dtype, vresult->subtype )
1686  ln += " "
1687  ln += hVregToStr( v1 )
1688  ln += ", "
1689  ln += hVregToStr( v2 )
1690  hWriteLine( ln )
1691 
1692  '' LLVM comparison ops return i1, but we usually want i32,
1693  '' so do an sign-extending cast (i1 -1 to i32 -1).
1694  if( is_comparison ) then
1695  vtemp = _allocVreg( vresult->dtype, vresult->subtype )
1696  ln = hVregToStr( vtemp )
1697  ln += " = sext "
1698  ln += "i1 " + hVregToStr( vresult )
1699  ln += " to "
1700  ln += hEmitType( vresult->dtype, vresult->subtype )
1701  hWriteLine( ln )
1702  *vresult = *vtemp
1703  end if
1704 
1705  '' self-bop? (see above)
1706  if( vr = NULL ) then
1707  if( irIsREG( v1 ) ) then
1708  *v1 = *vresult
1709  else
1710  _emitStore( v1, vresult )
1711  end if
1712  end if
1713 end sub
1714 
1715 sub _emitUop _
1716  ( _
1717  byval op as integer, _
1718  byval v1 as IRVREG ptr, _
1719  byval vr as IRVREG ptr _
1720  )
1721 
1722  dim as IRVREG ptr v2 = any
1723 
1724  '' LLVM IR doesn't have unary operations,
1725  '' corresponding BOPs are supposed to be used instead
1726  select case( op )
1727  case AST_OP_NEG
1728  '' vr = 0 - v1
1729  v2 = _allocVrImm( FB_DATATYPE_INTEGER, NULL, 0 )
1730  _emitBop( AST_OP_SUB, v2, v1, vr, NULL )
1731  case AST_OP_NOT
1732  '' vr = v1 xor -1
1733  v2 = _allocVrImm( FB_DATATYPE_INTEGER, NULL, -1 )
1734  _emitBop( AST_OP_XOR, v1, v2, vr, NULL )
1735  end select
1736 
1737 end sub
1738 
1739 sub _emitConvert( byval v1 as IRVREG ptr, byval v2 as IRVREG ptr )
1740  dim as string ln
1741  dim as integer ldtype = any, rdtype = any, lptr = any, rptr = any
1742  dim as zstring ptr op = any
1743  dim as IRVREG ptr v0 = any
1744 
1745  ldtype = v1->dtype
1746  rdtype = v2->dtype
1747  assert( (ldtype <> rdtype) or (v1->subtype <> v2->subtype) )
1748 
1749  if( typeGetClass( ldtype ) = FB_DATACLASS_FPOINT ) then
1750  if( typeGetClass( rdtype ) = FB_DATACLASS_FPOINT ) then
1751  '' float = float
1752  '' i.e. single <-> double
1753  if( typeGetSize( ldtype ) < typeGetSize( rdtype ) ) then
1754  op = @"fptrunc"
1755  else
1756  assert( typeGetSize( ldtype ) > typeGetSize( rdtype ) )
1757  op = @"fpext"
1758  end if
1759  else
1760  '' float = int
1761  if( typeIsSigned( rdtype ) ) then
1762  op = @"sitofp"
1763  else
1764  op = @"uitofp"
1765  end if
1766  end if
1767  else
1768  if( typeGetClass( rdtype ) = FB_DATACLASS_FPOINT ) then
1769  '' int = float
1770  if( typeIsSigned( ldtype ) ) then
1771  op = @"fptosi"
1772  else
1773  op = @"fptoui"
1774  end if
1775  else
1776  '' int = int
1777  if( typeIsPtr( ldtype ) ) then
1778  if( typeIsPtr( rdtype ) ) then
1779  '' both are pointers, just convert the type
1780  '' (bitcast doesn't change any bits)
1781  op = @"bitcast"
1782  else
1783  op = @"inttoptr"
1784  end if
1785  else
1786  if( typeIsPtr( rdtype ) ) then
1787  op = @"ptrtoint"
1788  else
1789  if( typeGetSize( ldtype ) = typeGetSize( rdtype ) ) then
1790  '' same size ints, should happen only with signed <-> unsigned
1791  op = @"bitcast"
1792  else
1793  if( typeGetSize( ldtype ) < typeGetSize( rdtype ) ) then
1794  op = @"trunc"
1795  else
1796  if( typeIsSigned( ldtype ) ) then
1797  op = @"sext"
1798  else
1799  op = @"zext"
1800  end if
1801  end if
1802  end if
1803  end if
1804  end if
1805  end if
1806  end if
1807 
1808  if( irIsREG( v1 ) ) then
1809  v0 = v1
1810  else
1811  v0 = _allocVreg( v1->dtype, v1->subtype )
1812  end if
1813 
1814  hLoadVreg( v2 )
1815  _setVregDataType( v2, v2->dtype, v2->subtype )
1816 
1817  ln = hVregToStr( v0 ) + " = " + *op + " "
1818  ln += hEmitType( v2->dtype, v2->subtype )
1819  ln += " " + hVregToStr( v2 ) + " to "
1820  ln += hEmitType( v1->dtype, v1->subtype )
1821  hWriteLine( ln )
1822 
1823  if( irIsREG( v1 ) = FALSE ) then
1824  _emitStore( v1, v0 )
1825  end if
1826 end sub
1827 
1828 sub _emitStore( byval l as IRVREG ptr, byval r as IRVREG ptr )
1829  dim as string ln
1830 
1831  hLoadVreg( r )
1832  _setVregDataType( r, l->dtype, l->subtype )
1833 
1834  hPrepareAddress( l )
1835 
1836  ln = "store "
1837  ln += hEmitType( typeDeref( l->dtype ), l->subtype ) + " "
1838  ln += hVregToStr( r ) + ", "
1839  ln += hEmitType( l->dtype, l->subtype ) + " "
1840  ln += hVregToStr( l )
1841  hWriteLine( ln )
1842 end sub
1843 
1845 /' do nothing '/
1846 end sub
1847 
1848 sub _emitLoad( byval v1 as IRVREG ptr )
1849 /' do nothing '/
1850 end sub
1851 
1852 sub _emitLoadRes _
1853  ( _
1854  byval v1 as IRVREG ptr, _
1855  byval vr as IRVREG ptr _
1856  )
1857 
1858  hLoadVreg( v1 )
1859  _setVregDataType( v1, vr->dtype, vr->subtype )
1860 
1861  hWriteLine( "ret " + hEmitType( vr->dtype, vr->subtype ) + " " + hVregToStr( v1 ) )
1862 
1863 end sub
1864 
1865 sub _emitPushArg _
1866  ( _
1867  byval param as FBSYMBOL ptr, _
1868  byval vr as IRVREG ptr, _
1869  byval udtlen as longint, _
1870  byval level as integer _
1871  )
1872 
1873  '' Remember for later, so during _emitCall[Ptr] we can emit the whole
1874  '' call in one go
1875  dim as IRCALLARG ptr arg = listNewNode( @ctx.callargs )
1876  arg->vr = vr
1877  arg->level = level
1878 
1879 end sub
1880 
1881 sub _emitAddr _
1882  ( _
1883  byval op as integer, _
1884  byval v1 as IRVREG ptr, _
1885  byval vr as IRVREG ptr _
1886  )
1887 
1888  dim as string ln
1889 
1890  select case( op )
1891  case AST_OP_ADDROF
1892  '' There is no address-of operator in LLVM, because it only
1893  '' uses addresses to access memory, i.e. everything is a
1894  '' pointer already.
1895  ''
1896  '' If a different type is wanted we can do a bitcast,
1897  '' but without loading the vreg, and if it's the same type
1898  '' the expression can be re-used as-is.
1899 
1900  assert( irIsREG( vr ) )
1901 
1902  '' Treat memory access as address - turn it into a REG
1903  '' Note: we do not allocate a v1->reg value like _allocVreg()
1904  '' would do, but instead leave v1->sym set, to be able to
1905  '' access that LLVM value.
1906  assert( v1->typ = IR_VREGTYPE_VAR )
1907  assert( v1->ofs = 0 )
1908  assert( v1->vidx = NULL )
1909  v1->typ = IR_VREGTYPE_REG
1910  v1->dtype = typeAddrOf( v1->dtype )
1911  v1->reg = INVALID
1912 
1913  '' Add bitcast if types differ
1914  if( (vr->dtype <> v1->dtype) or (vr->subtype <> v1->subtype) ) then
1915  ln = hVregToStr( vr ) + " = bitcast "
1916  ln += hEmitType( v1->dtype, v1->subtype )
1917  ln += " " + hVregToStr( v1 ) + " to "
1918  ln += hEmitType( vr->dtype, vr->subtype )
1919  hWriteLine( ln )
1920  else
1921  *vr = *v1
1922  end if
1923 
1924  case AST_OP_DEREF
1925  hLoadVreg( v1 )
1926  assert( irIsREG( vr ) and irIsREG( v1 ) )
1927  *vr = *v1
1928 
1929  end select
1930 
1931 end sub
1932 
1933 sub hDoCall _
1934  ( _
1935  byval pname as zstring ptr, _
1936  byval proc as FBSYMBOL ptr, _
1937  byval bytestopop as integer, _
1938  byval vr as IRVREG ptr, _
1939  byval level as integer _
1940  )
1941 
1942  dim as string ln
1943  dim as IRCALLARG ptr arg = any, prev = any
1944  dim as IRVREG ptr varg = any, v0 = any
1945 
1946  assert( symbIsProc( proc ) )
1947 
1948  if( vr = NULL ) then
1949  '' Result discarded? Not allowed in LLVM, so assign to a
1950  '' temporary result vreg that will be unused.
1951  if( symbGetType( proc ) <> FB_DATATYPE_VOID ) then
1952  vr = _allocVreg( typeGetDtAndPtrOnly( symbGetProcRealType( proc ) ), _
1953  symbGetProcRealSubtype( proc ) )
1954  end if
1955  end if
1956 
1957  if( vr ) then
1958  if( irIsREG( vr ) ) then
1959  v0 = vr
1960  else
1961  v0 = _allocVreg( vr->dtype, vr->subtype )
1962  end if
1963 
1964  ln = hVregToStr( v0 ) + " = call "
1965  ln += hEmitProcCallConv( proc )
1966  ln += hEmitType( v0->dtype, v0->subtype ) + " "
1967  else
1968  ln = "call " + hEmitProcCallConv( proc ) + "void "
1969  end if
1970 
1971  ln += *pname + "( "
1972 
1973  '' args
1974  arg = listGetTail( @ctx.callargs )
1975  while( arg andalso (arg->level = level) )
1976  prev = listGetPrev( arg )
1977 
1978  varg = arg->vr
1979  hLoadVreg( varg )
1980  ln += hEmitType( varg->dtype, varg->subtype )
1981  ln += " "
1982  ln += hVregToStr( varg )
1983 
1984  listDelNode( @ctx.callargs, arg )
1985 
1986  if( prev ) then
1987  if( prev->level = level ) then
1988  ln += ", "
1989  end if
1990  end if
1991 
1992  arg = prev
1993  wend
1994 
1995  ln += " )"
1996 
1997  hWriteLine( ln )
1998 
1999  if( vr ) then
2000  if( irIsREG( vr ) = FALSE ) then
2001  _emitStore( vr, v0 )
2002  end if
2003  end if
2004 end sub
2005 
2006 sub _emitCall _
2007  ( _
2008  byval proc as FBSYMBOL ptr, _
2009  byval bytestopop as integer, _
2010  byval vr as IRVREG ptr, _
2011  byval level as integer _
2012  )
2013 
2014  hDoCall( symbGetMangledName( proc ), proc, bytestopop, vr, level )
2015 
2016 end sub
2017 
2018 sub _emitCallPtr _
2019  ( _
2020  byval v1 as IRVREG ptr, _
2021  byval vr as IRVREG ptr, _
2022  byval bytestopop as integer, _
2023  byval level as integer _
2024  )
2025 
2026  dim as FBSYMBOL ptr proc = any
2027 
2028  assert( v1->dtype = typeAddrOf( FB_DATATYPE_FUNCTION ) )
2029  proc = v1->subtype
2030 
2031  hLoadVreg( v1 )
2032  hDoCall( hVregToStr( v1 ), proc, bytestopop, vr, level )
2033 
2034 end sub
2035 
2036 sub _emitJumpPtr( byval v1 as IRVREG ptr )
2037  hLoadVreg( v1 )
2038  hWriteLine( "goto *" & hVregToStr( v1 ) )
2039 end sub
2040 
2041 sub _emitBranch( byval op as integer, byval label as FBSYMBOL ptr )
2042  '' GOTO label
2043  assert( op = AST_OP_JMP )
2044 
2045  '' The jump ends the current basic block...
2046  hWriteLine( "br label %" + *symbGetMangledName( label ) )
2047 
2048  '' so, we need to add a dummy label afterwards (starts new basic block)
2050 end sub
2051 
2052 sub _emitJmpTb _
2053  ( _
2054  byval v1 as IRVREG ptr, _
2055  byval tbsym as FBSYMBOL ptr, _
2056  byval values as ulongint ptr, _
2057  byval labels as FBSYMBOL ptr ptr, _
2058  byval labelcount as integer, _
2059  byval deflabel as FBSYMBOL ptr, _
2060  byval minval as ulongint, _
2061  byval maxval as ulongint _
2062  )
2063 
2064  dim as string ln
2065 
2066  assert( labelcount > 0 )
2067 
2068  hLoadVreg( v1 )
2069 
2070  ln = "switch "
2071  ln += hEmitType( v1->dtype, v1->subtype ) + " "
2072  ln += hVregToStr( v1 ) + ", "
2073  ln += "label %" + *symbGetMangledName( deflabel ) + " "
2074  ln += "["
2075  hWriteLine( ln )
2076 
2077  ctx.identcnt += 1
2078  for i as integer = 0 to labelcount - 1
2079  ln = "%integer " + str( values[i] ) + ", "
2080  ln += "label %" + *symbGetMangledName( labels[i] )
2081  hWriteLine( ln )
2082  next
2083  ctx.identcnt -= 1
2084 
2085  hWriteLine( "]" )
2086 
2087 end sub
2088 
2089 sub _emitMem _
2090  ( _
2091  byval op as integer, _
2092  byval v1 as IRVREG ptr, _
2093  byval v2 as IRVREG ptr, _
2094  byval bytes as longint _
2095  )
2096 
2097  dim as string ln
2098 
2099  ln = "call void "
2100 
2101  select case( op )
2102  case AST_OP_MEMCLEAR
2103  ctx.memset_used = TRUE
2104 
2105  hLoadVreg( v1 )
2106  hLoadVreg( v2 )
2107  _setVregDataType( v1, typeAddrOf( FB_DATATYPE_BYTE ), NULL )
2108  _setVregDataType( v2, FB_DATATYPE_INTEGER, NULL )
2109 
2110  ln += "@llvm.memset.p0i8.i32( "
2111  ln += "i8* " + hVregToStr( v1 ) + ", "
2112  ln += "i8 0, "
2113  ln += "i32 " + hVregToStr( v2 ) + ", "
2114 
2115  case AST_OP_MEMMOVE
2116  ctx.memmove_used = TRUE
2117 
2118  hLoadVreg( v1 )
2119  hLoadVreg( v2 )
2120  _setVregDataType( v1, typeAddrOf( FB_DATATYPE_BYTE ), NULL )
2121  _setVregDataType( v2, typeAddrOf( FB_DATATYPE_BYTE ), NULL )
2122 
2123  ln += "@llvm.memmove.p0i8.p0i8.i32( "
2124  ln += "i8* " + hVregToStr( v1 ) + ", "
2125  ln += "i8* " + hVregToStr( v2 ) + ", "
2126  ln += "i32 " + str( cunsg( bytes ) ) + ", "
2127 
2128  end select
2129 
2130  ln += "i32 1, i1 false )"
2131 
2132  hWriteLine( ln )
2133 end sub
2134 
2135 sub _emitDECL( byval sym as FBSYMBOL ptr )
2136  hEmitVariable( sym )
2137 end sub
2138 
2139 sub _emitDBG _
2140  ( _
2141  byval op as integer, _
2142  byval proc as FBSYMBOL ptr, _
2143  byval ex as integer _
2144  )
2145 
2146  if( op = AST_OP_DBG_LINEINI ) then
2147  hWriteLine( "#line " & ex & " """ & hReplace( env.inf.name, "\", $"\\" ) & """" )
2148  ctx.linenum = ex
2149  end if
2150 
2151 end sub
2152 
2153 sub _emitComment( byval text as zstring ptr )
2154  hWriteLine( "; " + *text )
2155 end sub
2156 
2158  ctx.asm_line = ""
2159 end sub
2160 
2161 sub _emitAsmText( byval text as zstring ptr )
2162  ctx.asm_line += *text
2163 end sub
2164 
2165 sub _emitAsmSymb( byval sym as FBSYMBOL ptr )
2166  ctx.asm_line += *symbGetMangledName( sym )
2167  if( symbGetOfs( sym ) > 0 ) then
2168  ctx.asm_line += "+" + str( symbGetOfs( sym ) )
2169  elseif( symbGetOfs( sym ) < 0 ) then
2170  ctx.asm_line += str( symbGetOfs( sym ) )
2171  end if
2172 end sub
2173 
2176 end sub
2177 
2178 sub _emitVarIniBegin( byval sym as FBSYMBOL ptr )
2179  ctx.varini = *symbGetMangledName( sym )
2180  ctx.varini += " = global "
2181  ctx.varini += hEmitSymType( sym )
2182  ctx.varini += " "
2183  ctx.variniscopelevel = 0
2184 end sub
2185 
2186 sub _emitVarIniEnd( byval sym as FBSYMBOL ptr )
2187  hWriteLine( ctx.varini )
2188  ctx.varini = ""
2189 end sub
2190 
2191 sub hVarIniElementType _
2192  ( _
2193  byval dtype as integer, _
2194  byval subtype as FBSYMBOL ptr _
2195  )
2196  if( ctx.variniscopelevel > 0 ) then
2197  ctx.varini += hEmitType( dtype, subtype ) + " "
2198  end if
2199 end sub
2200 
2202  if( ctx.variniscopelevel > 0 ) then
2203  ctx.varini += ", "
2204  end if
2205 end sub
2206 
2207 sub _emitVarIniI( byval sym as FBSYMBOL ptr, byval value as longint )
2208  var dtype = symbGetType( sym )
2209  hVarIniElementType( dtype, sym->subtype )
2210  if( typeGetSize( dtype ) = 8 ) then
2211  ctx.varini += hEmitLong( value )
2212  else
2213  ctx.varini += hEmitInt( dtype, sym->subtype, value )
2214  end if
2215  hVarIniSeparator( )
2216 end sub
2217 
2218 sub _emitVarIniF( byval sym as FBSYMBOL ptr, byval value as double )
2219  var dtype = symbGetType( sym )
2220  hVarIniElementType( dtype, sym->subtype )
2221  ctx.varini += hEmitFloat( value )
2222  hVarIniSeparator( )
2223 end sub
2224 
2225 sub _emitVarIniOfs( byval sym as FBSYMBOL ptr, byval ofs as longint )
2226  ctx.varini += "TODO offset " + *symbGetMangledName( sym ) + " + " + str( ofs )
2227  hVarIniSeparator( )
2228 end sub
2229 
2230 sub _emitVarIniStr _
2231  ( _
2232  byval varlength as longint, _
2233  byval literal as zstring ptr, _
2234  byval litlength as longint _
2235  )
2236 
2237  if( ctx.variniscopelevel > 0 ) then
2238  ctx.varini += hEmitStrLitType( varlength ) + " "
2239  end if
2240  ctx.varini += "c"""
2241  hBuildStrLit( ctx.varini, varlength + 1, hUnescape( literal ), litlength + 1 )
2242  ctx.varini += """"
2243  hVarIniSeparator( )
2244 
2245 end sub
2246 
2247 sub _emitVarIniWstr _
2248  ( _
2249  byval varlength as longint, _
2250  byval literal as wstring ptr, _
2251  byval litlength as longint _
2252  )
2253 
2254  if( ctx.variniscopelevel > 0 ) then
2255  ctx.varini += hEmitStrLitType( varlength ) + " "
2256  end if
2257  ctx.varini += "c"""
2258  hBuildWstrLit( ctx.varini, varlength + 1, hUnescapeW( literal ), litlength + 1 )
2259  ctx.varini += """"
2260  hVarIniSeparator( )
2261 
2262 end sub
2263 
2264 sub _emitVarIniPad( byval bytes as longint )
2265  '' Nothing to do -- we're using {...} for structs and each array
2266  '' dimension, and gcc will zero-initialize any uninitialized elements,
2267  '' aswell as add padding between fields etc. where needed.
2268 end sub
2269 
2271  ctx.variniscopelevel += 1
2272  ctx.varini += "{ "
2273 end sub
2274 
2276  '' Trim separator at the end, to make the output look a bit more clean
2277  '' (this isn't needed though, since the extra comma is allowed in C)
2278  if( right( ctx.varini, 2 ) = ", " ) then
2279  ctx.varini = left( ctx.varini, len( ctx.varini ) - 2 )
2280  end if
2281 
2282  ctx.varini += " }"
2283  ctx.variniscopelevel -= 1
2284  hVarIniSeparator( )
2285 end sub
2286 
2288  hWriteLine( "" )
2289 end sub
2290 
2291 sub _emitFbctinfString( byval s as zstring ptr )
2292  ctx.fbctinf += *s + $"\00"
2293  ctx.fbctinf_len += len( *s ) + 1
2294 end sub
2295 
2297  dim as string ln
2298 
2299  '' This is based on the LLVM IR code generated by clang for a:
2300  '' static const char __attribute__((used, section(".fbctinf"))) __fbctinf[] = "...";
2301 
2302  '' internal - private
2303  '' constant - read-only
2304  '' section - This global must be put into a custom .fbctinf section,
2305  '' as done by the ASM backend.
2306  ln = "@__fbctinf = internal constant "
2308  ln += " c""" + ctx.fbctinf + """"
2309  ln += ", section ""." + FB_INFOSEC_NAME + """"
2310  hWriteLine( ln )
2311 
2312  '' Append to the special llvm.used symbol to ensure it won't be
2313  '' optimized out:
2314  ln = "@llvm.used = appending global [1 x i8*] "
2315  ln += "["
2316  ln += "i8* bitcast (" + hEmitStrLitType( ctx.fbctinf_len ) + "* @__fbctinf to i8*)"
2317  ln += "]"
2318  ln += ", section ""llvm.metadata"""
2319  hWriteLine( ln )
2320 
2321  ctx.fbctinf = ""
2322  ctx.fbctinf_len = 0
2323 end sub
2324 
2325 sub _emitProcBegin _
2326  ( _
2327  byval proc as FBSYMBOL ptr, _
2328  byval initlabel as FBSYMBOL ptr _
2329  )
2330 
2331  hWriteLine( "" )
2332 
2333  dim as string ln
2334 
2335  ln += "define "
2336  if( symbIsExport( proc ) ) then
2337  ln += "dllexport "
2338  elseif( symbIsPrivate( proc ) ) then
2339  ln += "private "
2340  ''ln += "internal "
2341  end if
2342  ln += hEmitProcHeader( proc, FALSE )
2343 
2344  hWriteLine( ln )
2345 
2346  hWriteLine( "{" )
2347  ctx.identcnt += 1
2348 
2349 end sub
2350 
2351 sub _emitProcEnd _
2352  ( _
2353  byval proc as FBSYMBOL ptr, _
2354  byval initlabel as FBSYMBOL ptr, _
2355  byval exitlabel as FBSYMBOL ptr _
2356  )
2357 
2358  '' Sub? Add ret manually, the AST doesn't do a LOAD[RES] for this
2359  if( symbGetType( proc ) = FB_DATATYPE_VOID ) then
2360  hWriteLine( "ret void" )
2361  end if
2362 
2363  ctx.identcnt -= 1
2364  hWriteLine( "}" )
2365 
2366 end sub
2367 
2368 sub _emitScopeBegin( byval s as FBSYMBOL ptr )
2369 end sub
2370 
2371 sub _emitScopeEnd( byval s as FBSYMBOL ptr )
2372 end sub
2373 
2374 static as IR_VTBL irllvm_vtbl = _
2375 ( _
2376  @_init, _
2377  @_end, _
2378  @_emitBegin, _
2379  @_emitEnd, _
2380  @_getOptionValue, _
2381  @_procBegin, _
2382  @_procEnd, _
2383  @_procAllocArg, _
2384  @_procAllocLocal, _
2385  NULL, _
2386  @_scopeBegin, _
2387  @_scopeEnd, _
2389  @_emitConvert, _
2390  @_emitLabel, _
2391  @_emitLabel, _
2392  NULL, _
2393  @_emitProcBegin, _
2394  @_emitProcEnd, _
2395  @_emitPushArg, _
2396  @_emitAsmBegin, _
2397  @_emitAsmText, _
2398  @_emitAsmSymb, _
2399  @_emitAsmEnd, _
2400  @_emitComment, _
2401  @_emitBop, _
2402  @_emitUop, _
2403  @_emitStore, _
2404  @_emitSpillRegs, _
2405  @_emitLoad, _
2406  @_emitLoadRes, _
2407  NULL, _
2408  @_emitAddr, _
2409  @_emitCall, _
2410  @_emitCallPtr, _
2411  NULL, _
2412  @_emitJumpPtr, _
2413  @_emitBranch, _
2414  @_emitJmpTb, _
2415  @_emitMem, _
2416  @_emitScopeBegin, _
2417  @_emitScopeEnd, _
2418  @_emitDECL, _
2419  @_emitDBG, _
2420  @_emitVarIniBegin, _
2421  @_emitVarIniEnd, _
2422  @_emitVarIniI, _
2423  @_emitVarIniF, _
2424  @_emitVarIniOfs, _
2425  @_emitVarIniStr, _
2426  @_emitVarIniWstr, _
2427  @_emitVarIniPad, _
2430  @_emitFbctinfBegin, _
2431  @_emitFbctinfString, _
2432  @_emitFbctinfEnd, _
2433  @_allocVreg, _
2434  @_allocVrImm, _
2435  @_allocVrImmF, _
2436  @_allocVrVar, _
2437  @_allocVrIdx, _
2438  @_allocVrPtr, _
2439  @_allocVrOfs, _
2440  @_setVregDataType, _
2441  NULL, _
2442  NULL, _
2443  NULL, _
2444  NULL _
2445 )
2446