-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCodeGen.h
More file actions
822 lines (698 loc) · 37 KB
/
Copy pathCodeGen.h
File metadata and controls
822 lines (698 loc) · 37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
#ifndef BLANG_CODEGEN_H_
#define BLANG_CODEGEN_H_
#include <string>
#include <map>
#include <set>
#include <vector>
#include <memory>
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
#include "Type.h"
#include "Expression.h"
#include "SQLGen.h"
#include "FormatString.h"
// Forward declarations for the LLVM debug-info types (U3). The full definitions
// live in llvm/IR/DIBuilder.h + DebugInfoMetadata.h, included only in the .cpp
// files that emit DWARF — keeping this header light. unique_ptr<DIBuilder> with
// an incomplete type is fine because ~CodeGen() is defined in CodeGen.cpp where
// DIBuilder is complete.
namespace llvm
{
class DIBuilder;
class DICompileUnit;
class DIFile;
class DISubprogram;
}
namespace QLang
{
class CodeGen
{
public:
CodeGen( const std::string &moduleName );
~CodeGen();
bool generate( Module *mod );
void print( llvm::raw_ostream &os );
bool verify();
// Run the LLVM new-PassManager per-module optimization pipeline over the
// generated module, in-process, before print(). `level` is one of
// "0","1","2","3","s","z" (empty or "0" => O0). Returns false on an invalid
// level (the driver reports it). This is layer 1 of the -O pipeline (IR
// passes); llc -O<n> is layer 2 (backend). Target-independent — no
// TargetMachine is required, so qcc needs no per-target backend libs.
bool optimize( const std::string &level );
// Raw LLVM verifier text captured by the most recent failing verify().
// The driver surfaces this only under --debug-compiler (U2, FR-010).
const std::string &getVerifyError() const { return mVerifyError; }
// Set a module prefix for name mangling (e.g. "sys" → functions become "sys__funcName")
void setModulePrefix( const std::string &prefix ) { mModulePrefix = prefix; }
// Test-runner mode (qcc --emit-test-main). When set, a module carrying
// test{} blocks emits a real main() that registers each test with the C
// test driver and dispatches to __blang_test_main; asserts inside test mode
// print a located <file>:<line>: diagnostic on failure. Off by default, so
// normal (bcc build / single-file) codegen is byte-for-byte unchanged.
void setTestMode( bool on ) { mTestMode = on; }
// Enable DWARF debug info emission (qcc -g, U3). Off by default so a
// non-`-g` build is byte-identical. Drives the DIBuilder setup in generate()
// and the per-function/per-statement debug-location hooks.
void setDebugInfo( bool on ) { mDebugInfo = on; }
// Configure the default database connection opened in main() (from the
// [database] section of blang.toml, forwarded by bcc via qcc flags).
// An empty url leaves the connection to the runtime's lazy env fallback.
void setDbConfig( const std::string &driver, const std::string &url )
{
mDbDriver = driver;
mDbUrl = url;
}
// Register a named database connection for @db("name") routing.
void addDbNamedConn( const std::string &name, const std::string &driver,
const std::string &url )
{
mDbNamedConns.push_back( { name, driver, url } );
}
// Multi-module support: register struct/enum defs from other modules
void registerExternalTypes(
const std::vector<SmartPtr<StructDefinition>> &structs,
const std::vector<SmartPtr<EnumDefinition>> &enums );
private:
// Top-level generators
llvm::Function *genFunction( FunctionDefinition *func );
void genBlock( Block *block );
// Statement generators
void genStatement( Statement *stmt );
void genVariableDeclaration( VariableDeclaration *decl );
void genReturnStatement( ReturnStatement *ret );
// Emit ARC releases for every in-scope local (shared/sync, string, array,
// buffer, lambda ctx, struct, enum payload) across all open scopes. Shared
// by genReturnStatement and the `?` operator's early-return error path so an
// error propagated by `?` runs the same cleanup a normal return does
// (otherwise locals live at the failing `?` leak).
void emitScopeStackReleases();
void genIfStatement( IfStatement *ifStmt );
void genWhileStatement( WhileStatement *whileStmt );
void genForStatement( ForStatement *forStmt );
// Phase 2 statement generators
llvm::Value *genSpawnStatement( SpawnStatement *spawn );
void genWaitStatement( WaitStatement *wait );
void genWaitAllStatement( WaitAllStatement *waitAll );
void genAssertStatement( AssertStatement *assertStmt );
void genEventHandler( EventHandler *handler );
// Expression generators (return llvm::Value*)
llvm::Value *genExpression( Expression *expr );
llvm::Value *genCallExpression( CallExpression *call );
llvm::Value *genVariableExpression( VariableExpression *var );
llvm::Value *genOperationsExpression( OperationsExpression *ops );
llvm::Value *genAssignmentExpression( AssignmentExpression *assign );
llvm::Value *genUnaryExpression( UnaryExpression *unary );
llvm::Value *genConstInteger( ConstInteger *ci );
llvm::Value *genConstFloat( ConstFloat *cf );
llvm::Value *genConstString( ConstString *cs );
llvm::Value *genConstChar( ConstChar *cc );
// Struct and field codegen
llvm::StructType *getOrCreateStructType( StructDefinition *structDef );
llvm::StructType *instantiateGenericStruct(
StructDefinition *genericDef,
const std::vector<SmartPtr<Type>> &typeArgs );
std::string mangleGenericName(
const std::string &baseName,
const std::vector<SmartPtr<Type>> &typeArgs );
llvm::Function *instantiateGenericFunction(
FunctionDefinition *genericDef,
const std::vector<SmartPtr<Type>> &typeArgs );
llvm::Value *genStructLiteral( StructLiteralExpression *expr );
llvm::Value *genConstructExpression( ConstructExpression *expr );
llvm::Value *genFieldAccess( FieldAccessExpression *expr );
llvm::Value *genFieldAssignment( FieldAssignmentExpression *expr );
llvm::Value *genIndexAssignment( IndexAssignmentExpression *expr );
llvm::Value *genMethodCall( MethodCallExpression *expr );
// Builtin type method/field codegen
llvm::Value *genStringMethodCall( MethodCallExpression *expr );
llvm::Value *genArrayMethodCall( MethodCallExpression *expr );
llvm::Value *genBufferMethodCall( MethodCallExpression *expr );
llvm::Value *genStringFieldAccess( FieldAccessExpression *expr );
llvm::Value *genArrayFieldAccess( FieldAccessExpression *expr );
llvm::Value *genBufferFieldAccess( FieldAccessExpression *expr );
// Enum tagged union codegen
llvm::StructType *getOrCreateEnumType( EnumDefinition *enumDef );
llvm::Value *genEnumConstruct( EnumConstructExpression *expr );
bool enumHasPayload( EnumDefinition *enumDef );
uint64_t getEnumMaxPayloadSize( EnumDefinition *enumDef );
// Match and error handling codegen
llvm::Value *genMatchExpression( MatchExpression *expr );
llvm::Value *genTryExpression( TryExpression *expr );
// Try operator helper: resolve the QLang enum type of an expression
EnumDefinition *resolveExpressionEnumDef( Expression *expr );
// Resolve the full QLang type (with type arguments) of an expression, used to
// recover concrete types for generic enum variant payloads (Option<T>/Result<T,E>).
Type *resolveExpressionQType( Expression *expr );
// Resolve the concrete QLang type of a variant's first associated type,
// substituting the enum's generic params from `subjectType`'s type arguments.
Type *resolveVariantBindingQType( EnumDefinition *enumDef, int variantIdx, Type *subjectType );
// Array codegen
llvm::Value *genArrayLiteral( ArrayLiteralExpression *expr );
llvm::Value *genIndexExpression( IndexExpression *expr );
// Array runtime declarations
llvm::Function *getOrDeclareArrayCreate();
llvm::Function *getOrDeclareArrayCreateFromData();
llvm::Function *getOrDeclareArrayRetain();
llvm::Function *getOrDeclareArrayRelease();
llvm::Function *getOrDeclareArrayGet();
llvm::Function *getOrDeclareArraySet();
llvm::Function *getOrDeclareArrayPush();
llvm::Function *getOrDeclareArrayLength();
llvm::Function *getOrDeclareArrayConcat();
llvm::Function *getOrDeclareArrayCapacity();
llvm::Function *getOrDeclareArrayIsEmpty();
llvm::Function *getOrDeclareArrayPop();
llvm::Function *getOrDeclareArrayClear();
llvm::Function *getOrDeclareArraySetElemDtor();
// Set element destructor on an array based on element type name
void emitArrayElemDtor( llvm::Value *arrayPtr, const std::string &elemTypeName );
// Retain a refcounted element being stored into an array that owns its
// elements (an elem_dtor was/will be set — see emitArrayElemDtor).
// __blang_array_push does NOT retain, so pushing a refcounted value without
// this leaves the array holding a reference it never took: the pushed
// temporary/variable is released at scope exit while the array still points
// at it, causing a dangling pointer and a double-free at array release.
// Mirrors emitArrayElemDtor's per-type mapping (string/Array/Buffer/struct).
// No-op for non-refcounted element types (int, byte, ...).
void emitArrayElemRetain( llvm::Value *elemVal, const std::string &elemTypeName );
// Array type helper
bool isArrayType( Expression *expr );
int getElementSize( Type *elemType );
// Byte type helper (for unsigned extension)
bool isByteExpression( Expression *expr );
// Buffer type helper
bool isBufferType( Expression *expr );
// Channel type helpers and method codegen (chan<T> .send()/.recv()/.close())
bool isChanType( Expression *expr );
Type *getChanElementQType( Expression *expr );
llvm::Value *genChanMethodCall( MethodCallExpression *expr );
// Buffer runtime declarations
llvm::Function *getOrDeclareBufferCreate();
llvm::Function *getOrDeclareBufferCreateFromString();
llvm::Function *getOrDeclareBufferRetain();
llvm::Function *getOrDeclareBufferRelease();
llvm::Function *getOrDeclareBufferLength();
llvm::Function *getOrDeclareBufferCapacity();
llvm::Function *getOrDeclareBufferIsEmpty();
llvm::Function *getOrDeclareBufferGet();
llvm::Function *getOrDeclareBufferSet();
llvm::Function *getOrDeclareBufferAppendByte();
llvm::Function *getOrDeclareBufferAppendBytes();
llvm::Function *getOrDeclareBufferAppendString();
llvm::Function *getOrDeclareBufferIndexOf();
llvm::Function *getOrDeclareBufferSlice();
llvm::Function *getOrDeclareBufferToString();
llvm::Function *getOrDeclareBufferToStringRange();
llvm::Function *getOrDeclareBufferClear();
llvm::Function *getOrDeclareBufferCompact();
// Break/continue codegen
void genBreakStatement();
void genContinueStatement();
// String interpolation codegen
llvm::Value *genStringInterpolation( StringInterpolation *interp );
// The struct a receiver/argument expression denotes, resolving the implicit
// `self` parameter (whose declared type name is the literal "self"). The
// single place that answers "which struct is this?" for a receiver —
// see the comment on the definition (known-issues KI-8, KI-10).
StructDefinition *receiverStructDef( Expression *obj );
// Interpolation parts that denote a struct must render through Printable,
// not be handed to the string runtime as a BlangString (known-issues KI-8).
StructDefinition *structDefForInterpolationPart( Expression *part );
llvm::Function *lookupToStringFn( StructDefinition *sd );
llvm::Value *genPrintableToString( StructDefinition *sd, Expression *node,
llvm::Value *selfPtr );
// Is this struct Printable? Explicit `impl Printable` conformance always
// counts; a structural `to_string` counts only for a type defined in THIS
// module (an imported type must state conformance via the .bmod, D16).
// One predicate for both the print path and the interpolation path.
bool structIsPrintable( StructDefinition *sd );
// The self POINTER for a struct receiver, taken from the value's ADDRESS
// (not a loaded value): genVariableExpression double-loads a shared/sync
// variable, so a loaded struct would be its first 8 bytes as a pointer.
// A non-addressable receiver (field access, call result) yields the heap
// pointer directly. Shared by genPrintCall and the interpolation path
// (known-issues KI-20).
llvm::Value *structSelfPointer( Expression *argExpr );
// Pipeline expression codegen
llvm::Value *genPipelineExpression( PipelineExpression *pipeline );
// Builtin print/println codegen
void genPrintCall( CallExpression *call, bool appendNewline );
// Print runtime declarations
llvm::Function *getOrDeclarePrintBlang();
llvm::Function *getOrDeclarePrintNewline();
llvm::Function *getOrDeclarePrintFlush();
llvm::Function *getOrDeclareIntToStringFmt();
llvm::Function *getOrDeclareFloatToStringFmt();
llvm::Function *getOrDeclareCharToString();
// Lambda, function reference, and indirect call codegen
llvm::Value *genLambdaExpression( LambdaExpression *lambda );
llvm::Value *genFunctionRefExpression( FunctionRefExpression *funcRef );
llvm::Value *genIndirectCallExpression( IndirectCallExpression *indCall );
// Lambda capture analysis: walk AST and collect referenced VariableDefinitions
void collectReferencedVars( Statement *stmt, std::set<VariableDefinition*> &vars );
// Lambda context destructor generation (releases captured refcounted types)
llvm::Function *genLambdaDestructor(
const std::string &name,
llvm::StructType *ctxType,
const std::vector<std::pair<VariableDefinition*, llvm::AllocaInst*>> &captures,
const std::vector<llvm::Type*> &captureTypes );
// Lambda context lifetime runtime declarations
llvm::Function *getOrDeclareLambdaCtxRetain();
llvm::Function *getOrDeclareLambdaCtxRelease();
// Phase 2 expression generators
llvm::Value *genAwaitExpression( AwaitExpression *await );
// Phase 2 test block and contract codegen
llvm::Function *genTestBlock( TestBlock *testBlock );
void genTestRunner( const std::vector<llvm::Function*> &testFunctions,
const std::vector<SmartPtr<TestBlock>> &testBlocks );
// Test-mode entry point (qcc --emit-test-main): emits main() that registers
// each test with the C driver and returns __blang_test_main(argc, argv).
void genTestMain( const std::vector<llvm::Function*> &testFunctions,
const std::vector<SmartPtr<TestBlock>> &testBlocks );
void genContractCheck( Expression *condition, const std::string &message );
// Runtime helper declarations
llvm::Function *getOrDeclarePuts();
llvm::Function *getOrDeclareExit();
llvm::Function *getOrDeclarePrintf();
// String helper declarations
llvm::Function *getOrDeclareSnprintf();
// String runtime declarations
llvm::Function *getOrDeclareStringCreate();
llvm::Function *getOrDeclareStringCreateStatic();
llvm::Function *getOrDeclareStringRetain();
llvm::Function *getOrDeclareStringRelease();
llvm::Function *getOrDeclareStringConcat();
llvm::Function *getOrDeclareStringConcatMany();
llvm::Function *getOrDeclareStringEquals();
llvm::Function *getOrDeclareStringCompare();
llvm::Function *getOrDeclareStringLength();
llvm::Function *getOrDeclareStringCharAt();
llvm::Function *getOrDeclareIntToString();
llvm::Function *getOrDeclareFloatToString();
llvm::Function *getOrDeclareBoolToString();
llvm::Function *getOrDeclareStrlen();
llvm::Function *getOrDeclareStringIsEmpty();
llvm::Function *getOrDeclareStringContains();
llvm::Function *getOrDeclareStringStartsWith();
llvm::Function *getOrDeclareStringEndsWith();
llvm::Function *getOrDeclareStringIndexOf();
llvm::Function *getOrDeclareStringToUpper();
llvm::Function *getOrDeclareStringToLower();
llvm::Function *getOrDeclareStringTrim();
llvm::Function *getOrDeclareStringByteAt();
llvm::Function *getOrDeclareStringSubstring();
llvm::Function *getOrDeclareStringReplace();
llvm::Function *getOrDeclareStringToCstring();
// String type helper
bool isStringType( Expression *expr );
// ---- Generic-context type resolution (generic ARC unit) ----
// Resolve a declared type name through the ACTIVE monomorphization
// substitution (mTypeSubstitution): inside sort<string>'s body, "T" -> string.
// Identity outside generic instantiation. Every ARC decision that keys on a
// declared type name (scope tracking, bind-retain, untrack, temp tracking)
// must go through this so a T-typed local participates in refcounting.
std::string resolvedTypeName( Type *t );
// Resolve a generic function CALL's declared return type name to the
// concrete name using the call's type arguments (explicit or inferred):
// identity<string> declared "T" -> "string". Identity for non-generic calls.
std::string callReturnTypeName( CallExpression *call );
// Resolve a METHOD's declared return type name for a call on a generic
// struct instance, mapping the struct's generic params through the object's
// type arguments: Map<string,int>.get declared "V" -> "int". Falls back to
// mTypeSubstitution, then the declared name.
std::string methodReturnTypeName( MethodCallExpression *mc );
// Resolve the ELEMENT type of a method's Array-typed return, substituting
// the receiver's type arguments through the return element type param:
// Map<string,int>.keys() declares Array<K> -> element type "string" (KI-22).
// Returns nullptr when the method's return type is not a type-parameterized
// (Array<...>) type or cannot be resolved.
Type *methodReturnElementType( MethodCallExpression *mc );
// Infer a generic call's type arguments from its argument expressions'
// resolved/declared types when the caller wrote no explicit <...> list.
// Fills call->mTypeArgs; returns false (caller reports) if any generic
// param stays unbound.
bool inferCallTypeArgs( CallExpression *call, FunctionDefinition *funcDef );
// Map a type declared inside a generic struct to the concrete form for a
// given instance (Map<K,V>'s Array<K> -> Array<string> for Map<string,int>).
// nullptr when nothing needed mapping.
Type *mapTypeForInstance( Type *declared, StructDefinition *structDef,
Type *instanceType );
// Field type resolution helper (for FieldAccessExpression)
std::string getFieldTypeName( FieldAccessExpression *fa );
Type *getFieldType( FieldAccessExpression *fa );
// Memory allocation helpers
llvm::Function *getOrDeclareMalloc();
llvm::Function *getOrDeclareBlangAlloc();
llvm::Function *getOrDeclareFree();
// BLang runtime library declarations
llvm::Function *getOrDeclareRcAlloc();
llvm::Function *getOrDeclareRcAllocSync();
llvm::Function *getOrDeclareRcRetain();
llvm::Function *getOrDeclareRcRelease();
llvm::Function *getOrDeclareSyncLock();
llvm::Function *getOrDeclareSyncUnlock();
llvm::Function *getOrDeclareSysInit();
llvm::Function *getOrDeclareRuntimeInit();
llvm::Function *getOrDeclareSpawn();
llvm::Function *getOrDeclareSpawnWait();
llvm::Function *getOrDeclareSpawnTaskDestroy();
llvm::Function *getOrDeclareWaitAll();
llvm::Function *getOrDeclareRuntimeShutdown();
llvm::Function *getOrDeclareChanCreate();
llvm::Function *getOrDeclareChanSend();
llvm::Function *getOrDeclareChanRecv();
llvm::Function *getOrDeclareChanClose();
llvm::Function *getOrDeclareChanDestroy();
llvm::Function *getOrDeclareEventOn();
llvm::Function *getOrDeclareAsyncCall();
llvm::Function *getOrDeclareAwait();
llvm::Function *getOrDeclareTaskDestroy();
// Builtin to_json(value): compile-time dispatch to StructName_to_json
llvm::Value *genToJsonCall( CallExpression *call );
// JSON codegen (@json annotation)
bool genJsonToJson( StructDefinition *structDef );
bool genJsonFromJson( StructDefinition *structDef );
// JSON runtime declarations
llvm::Function *getOrDeclareJsonObject();
llvm::Function *getOrDeclareJsonInt();
llvm::Function *getOrDeclareJsonFloat();
llvm::Function *getOrDeclareJsonString();
llvm::Function *getOrDeclareJsonBool();
llvm::Function *getOrDeclareJsonObjectSet();
llvm::Function *getOrDeclareJsonObjectGet();
llvm::Function *getOrDeclareJsonEncode();
llvm::Function *getOrDeclareJsonDecode();
llvm::Function *getOrDeclareJsonFree();
llvm::Function *getOrDeclareJsonGetInt();
llvm::Function *getOrDeclareJsonGetFloat();
llvm::Function *getOrDeclareJsonGetString();
llvm::Function *getOrDeclareJsonGetBool();
// Database query codegen
llvm::Value *genQueryExpression( QueryExpression *query );
llvm::Value *genInsertExpression( InsertExpression *insert );
llvm::Value *genUpdateExpression( UpdateExpression *update );
llvm::Value *genDeleteExpression( DeleteExpression *del );
// Database runtime declarations
llvm::Function *getOrDeclareDbQuery();
llvm::Function *getOrDeclareDbExec();
llvm::Function *getOrDeclareDbResultCount();
llvm::Function *getOrDeclareDbResultGet();
llvm::Function *getOrDeclareDbResultGetInt();
llvm::Function *getOrDeclareDbResultGetFloat();
llvm::Function *getOrDeclareDbResultFree();
llvm::Function *getOrDeclareDbDefault();
llvm::Function *getOrDeclareDbGet();
llvm::Function *getOrDeclareDbOpen();
llvm::Function *getOrDeclareDbSetDefault();
llvm::Function *getOrDeclareDbRegister();
// Resolve the connection pointer for a query on table `tableName`:
// __blang_db_get("name") if the table struct carries @db("name"),
// otherwise __blang_db_default().
llvm::Value *genDbConnForTable( const std::string &tableName );
// Build an [N x i8*] array of C-string param values from the runtime
// expressions backing SQL `?` placeholders; returns an i8** to element 0
// (or a null i8** when there are no params). Sets outCount to N.
llvm::Value *buildParamArray( const std::vector<const Expression*> ¶mExprs,
int &outCount );
// Convert an evaluated value to a NUL-terminated C string (i8*) suitable
// for binding as a SQL parameter.
llvm::Value *paramToCString( llvm::Value *val );
// Compile-time validation that query/update/delete field references and
// insert field names exist on the target table struct. Reports located
// errors via reportError (the single diagnostic path).
void validateQueryFields( const std::string &tableName,
const std::vector<QueryPipelineStep> &steps, Expression *node );
void validateInsertFields( InsertExpression *insert );
// Recursively collect .field references (QueryFieldExpression) from an expr.
void collectQueryFieldRefs( const Expression *expr,
std::vector<std::string> &out );
// ForIn codegen
void genForInStatement( ForInStatement *forInStmt );
// Helper to get the alloca for an expression's address (for GEP)
llvm::AllocaInst *getExpressionAddress( Expression *expr );
// Type mapping
llvm::Type *getLLVMType( Type *type );
// Shared helper for declaring external functions (reduces getOrDeclare boilerplate)
llvm::Function *declareExtern( const char *name, llvm::Type *retType,
std::initializer_list<llvm::Type*> paramTypes, bool isVariadic = false );
// LLVM state
std::unique_ptr<llvm::LLVMContext> mContext;
std::unique_ptr<llvm::Module> mModule;
std::unique_ptr<llvm::IRBuilder<>> mBuilder;
// Debug info (DWARF, U3). Off by default so a non-`-g` build is
// byte-identical to pre-U3. Enabled via setDebugInfo(true) from qcc's -g arg.
bool mDebugInfo = false;
bool mDebugFinalized = false; // guards finalizeDebugInfo() (idempotent)
std::unique_ptr<llvm::DIBuilder> mDIBuilder;
llvm::DICompileUnit *mDICompileUnit = nullptr;
// Per-source-path DIFile cache (--combine gives each .b its own DIFile so
// line tables point at the correct source).
std::map<std::string, llvm::DIFile*> mDIFileCache;
// The DISubprogram scope of the function currently being generated (null
// outside a function / when debug info is off). DebugLocs resolve against it.
llvm::DISubprogram *mCurrentDISubprogram = nullptr;
// Debug-info helpers (all no-ops when !mDebugInfo). Defined in CGDebug.cpp.
llvm::DIFile *getOrCreateDIFile( const std::string &path );
llvm::DISubprogram *createDISubprogram( llvm::Function *llvmFunc,
const SourceLocation &loc, const std::string &name );
void applyDebugLoc( const SourceLocation &loc );
void clearDebugLoc();
void finalizeDebugInfo();
// Raw text from the most recent failing verify(); surfaced only under
// --debug-compiler (U2, FR-010).
std::string mVerifyError;
// Maps from AST nodes to LLVM values
std::map<VariableDefinition*, llvm::AllocaInst*> mVariableMap;
std::map<FunctionDefinition*, llvm::Function*> mFunctionMap;
// Struct type maps
std::map<std::string, llvm::StructType*> mStructTypeMap;
std::map<std::string, StructDefinition*> mStructDefMap;
// Maps self parameters to their owning struct definition
std::map<VariableDefinition*, StructDefinition*> mSelfStructMap;
// Maps self parameters to the mangled struct name (for generic struct methods)
std::map<VariableDefinition*, std::string> mSelfStructMangledName;
std::map<std::string, EnumDefinition*> mEnumDefMap;
// Protocols, for generic-constraint checks on inferred calls (the
// explicit-type-arg path is checked in Sema)
std::map<std::string, ProtocolDefinition*> mProtocolDefMap;
// Owns enums synthesized at codegen time (e.g. built-in Option/Result).
std::vector<SmartPtr<EnumDefinition>> mSyntheticEnums;
// Owns QLang types synthesized at codegen time (e.g. Option<T> for chan recv).
std::vector<SmartPtr<Type>> mSyntheticTypes;
std::map<std::string, llvm::StructType*> mEnumTypeMap;
// Generic instantiation tracking
std::map<std::string, llvm::StructType*> mGenericInstanceMap; // "Box_int" -> LLVM type
std::map<std::string, llvm::Function*> mGenericFunctionMap; // "identity_int" -> LLVM func
std::map<std::string, Type*> mTypeSubstitution; // active during generic instantiation
// Lambda/callback thunk cache: named function -> thunk wrapper
std::map<std::string, llvm::Function*> mThunkMap;
int mLambdaCounter = 0;
// Module scope for type resolution
Scope *mScope = nullptr;
QLang::Module *mQLangModule = nullptr;
// Module prefix for namespace name mangling (empty for user code)
std::string mModulePrefix;
// Database configuration (from blang.toml [database], forwarded by bcc).
std::string mDbDriver; // "sqlite" / "postgres" (default sqlite)
std::string mDbUrl; // connection string; empty => runtime env fallback
struct DbNamedConn { std::string name, driver, url; };
std::vector<DbNamedConn> mDbNamedConns;
// Loop break/continue target stack (for nested loops)
std::vector<std::pair<llvm::BasicBlock*, llvm::BasicBlock*>> mLoopStack;
// Each entry is (continueBB, exitBB)
// ARC tracking: shared/sync variables per scope depth
std::vector<std::vector<llvm::AllocaInst*>> mArcScopeStack;
// String refcount tracking: string variables per scope depth
// Each entry is (alloca, varDef) so we can skip moved variables
std::vector<std::vector<std::pair<llvm::AllocaInst*, VariableDefinition*>>> mStringScopeStack;
// Array refcount tracking: array variables per scope depth
std::vector<std::vector<std::pair<llvm::AllocaInst*, VariableDefinition*>>> mArrayScopeStack;
// Buffer refcount tracking: buffer variables per scope depth
std::vector<std::vector<std::pair<llvm::AllocaInst*, VariableDefinition*>>> mBufferScopeStack;
// Lambda/fn-typed variable tracking: release ctx on scope exit
std::vector<std::vector<std::pair<llvm::AllocaInst*, VariableDefinition*>>> mLambdaScopeStack;
// Struct variable tracking: heap-allocated struct variables per scope depth.
// All user-defined structs are heap-allocated via __blang_rc_alloc and refcounted.
// At scope exit, __blang_rc_release is called, which invokes the destructor to
// release refcounted fields when the refcount reaches zero.
std::vector<std::vector<llvm::AllocaInst*>> mStructScopeStack;
// Generate a destructor function for a struct type that releases refcounted fields.
// Returns nullptr if the struct has no refcounted fields.
llvm::Function *getOrGenStructDestructor( StructDefinition *sd,
const std::map<std::string, std::string> &typeSub );
// Cache of generated struct destructor functions
std::map<std::string, llvm::Function*> mStructDtorMap;
// ---- Cross-module construction ABI (library-emitted factory) ----
//
// Construction is caller-allocating inside a module: the call site computes
// the struct's alloc size and generates its destructor from the field list.
// A consumer of a .bmod has neither, so a struct that arrives through an
// interface is constructed by calling a factory the DEFINING module emitted:
//
// ptr __<Struct>_new(<init params>)
// = __blang_rc_alloc_dtor(size, dtor) + <Struct>_init(self, args)
//
// Release needs no counterpart: __blang_rc_release invokes the destructor
// pointer stored in the allocation header, so it is already layout-free.
//
// The factory symbol lives in the reserved "__" family (alongside
// __<Struct>_dtor) so it can never collide with a user method named `new`
// and can never be called from source. Both sides derive it from the struct
// name alone, so the two modules agree without the name crossing the .bmod
// as a symbol.
// Emitting side: mirrors method mangling, so two namespaced modules that
// both define a `Socket` get distinct factory symbols.
static std::string mangleStructFactoryName( const std::string &structName,
const std::string &modulePrefix );
// Consuming side: prefix-free, because a consumer cannot know the defining
// module's codegen prefix (it is not carried in the .bmod). Sound while only
// unprefixed `bcc build` library projects produce .bmod files; see the
// comment at the definition for what breaks if that changes.
static std::string mangleImportedStructFactoryName( const std::string &structName );
// LLVM signature of a struct's factory: ptr(<init params, self dropped>).
// nullptr when the struct declares no init.
llvm::FunctionType *structFactoryType( StructDefinition *structDef );
// Library side: emit the factory body for a non-generic struct whose init
// has a body. No-op for generic structs — their construction is
// consumer-side by design (bodies ship in the .bmod and the consumer
// monomorphizes, computing size and dtor locally).
void genStructFactory( StructDefinition *structDef );
// Consumer side: declare (never define) the factory and the method
// signatures of a struct that arrived through a .bmod, so call sites resolve
// and the symbols link from the library archive.
void declareInterfaceStructMembers( StructDefinition *structDef );
// Check if a type name refers to a user-defined struct (not a builtin)
bool isUserStructType( const std::string &typeName );
// Enum variable tracking: release refcounted payloads at scope exit.
// Each entry pairs an alloca with the enum definition for tag-based cleanup.
// mConcreteType carries the subject's concrete instantiation (e.g.
// Result<int,string>) when the enum is generic (built-in Option/Result), so
// a generic-param payload (T/E) can be resolved to its concrete refcounted
// type at release time; nullptr for non-generic enums whose payload types are
// already concrete in the definition.
struct EnumCleanupEntry
{
llvm::AllocaInst *alloca;
EnumDefinition *enumDef;
Type *concreteType;
};
std::vector<std::vector<EnumCleanupEntry>> mEnumScopeStack;
// Emit cleanup code for an enum variable's refcounted payload. concreteEnumType
// (optional) supplies type arguments for a generic enum so generic-param
// payloads resolve to their concrete refcounted types.
void emitEnumPayloadRelease( llvm::AllocaInst *alloca, EnumDefinition *enumDef,
Type *concreteEnumType = nullptr );
// Register a payload-carrying enum RVALUE passed directly as a call argument
// (e.g. `pick(Option.some("hi"))`) for scope-exit payload release. The
// callee borrows its parameters, so without this no one owns the temp
// enum's refcounted payload and it leaks (ARC ledger #7). declParamType is
// the callee's declared parameter type — the best source of the concrete
// instantiation (Option<string>) since an EnumConstructExpression carries
// no Sema-resolved type. No-op for variables/fields/index reads (their
// declaration sites own the payload) and for payload-free enums.
void trackEnumArgTemp( Expression *argExpr, llvm::Value *argVal,
Type *declParamType );
llvm::Function *getOrDeclareStringEqualsCstr();
// --- Recursive enums (boxed enum payloads) ---
// A variant payload whose type names a registered enum is stored as a
// POINTER to a heap-allocated copy (a "box", __blang_rc_alloc_dtor'd), so
// self-/mutually-recursive enums (enum Expr { add(Expr, Expr) ... }) have
// finite layout. Non-generic enums only: a generic enum's payload slots
// stay type-erased.
//
// Emit release calls for one enum value's refcounted payloads, reading
// through enumPtr (a pointer to the enum struct). Shared by the scope-exit
// release (emitEnumPayloadRelease) and the generated box destructor.
void emitEnumPayloadReleaseFromPtr( llvm::Value *enumPtr,
EnumDefinition *enumDef, Type *concreteEnumType );
// __enum_<Name>_box_dtor(void*): releases the boxed value's refcounted
// payloads when the box's refcount hits zero (recursion happens at runtime
// through child boxes' own dtors). Returns nullptr when the enum has no
// refcounted payloads (plain __blang_rc_alloc suffices).
llvm::Function *getOrGenEnumBoxDtor( EnumDefinition *enumDef );
// __enum_<Name>_payload_retain(void*): retains the refcounted payloads of
// the enum value at the pointer — used when a box is filled by COPYING
// from an existing owner (variable/field source), whose own release still
// runs. Returns nullptr when the enum has no refcounted payloads.
llvm::Function *getOrGenEnumPayloadRetain( EnumDefinition *enumDef );
// True if any variant payload (resolved for concreteEnumType) is
// refcounted: string/Array/Buffer/user struct/boxed enum.
bool enumHasRefcountedPayload( EnumDefinition *enumDef, Type *concreteEnumType );
// Resolve a variant's associated type to a concrete type: if it names one of
// the enum's generic parameters, substitute the matching argument from
// concreteEnumType; otherwise return it unchanged. Returns the input when no
// substitution applies (never null for a non-null input).
Type *resolveVariantPayloadType( Type *assocType, EnumDefinition *enumDef,
Type *concreteEnumType );
// Runtime declaration for __blang_rc_alloc_dtor
llvm::Function *getOrDeclareRcAllocDtor();
// Temporary string tracking: strings created during expression evaluation
// (concat results, string literals in expressions, method return values)
// that need to be released after the enclosing statement completes.
std::vector<llvm::Value*> mTempStrings;
// Helper to register a temporary string for deferred release
void trackTempString( llvm::Value *val );
// Release and clear all tracked temporary strings
void releaseTempStrings();
// Remove a value from the temp list (when it becomes owned by a variable)
void untrackTempString( llvm::Value *val );
// Temporary lambda context tracking: inline lambdas (not stored to a variable)
// that need their context released after the enclosing statement completes.
std::vector<llvm::Value*> mTempLambdaCtxs;
void trackTempLambdaCtx( llvm::Value *ctxPtr );
void releaseTempLambdaCtxs();
void untrackTempLambdaCtx( llvm::Value *ctxPtr );
// Temporary struct tracking: struct literals created as expression temporaries
// (e.g., function arguments) that need to be released after the enclosing statement.
std::vector<llvm::Value*> mTempStructs;
void trackTempStruct( llvm::Value *structPtr );
void releaseTempStructs();
void untrackTempStruct( llvm::Value *structPtr );
// Temporary array tracking: arrays produced as expression rvalues (a call or
// method that returns Array<T>) that are not bound to a variable and must be
// released after the enclosing statement. Mirrors the struct-temp discipline:
// tracked at the producing call/method, untracked when ownership transfers
// (stored into a variable / struct field / enum payload / returned).
std::vector<llvm::Value*> mTempArrays;
void trackTempArray( llvm::Value *arrPtr );
void releaseTempArrays();
void untrackTempArray( llvm::Value *arrPtr );
// Ownership move tracking: own variables that have been moved
std::set<VariableDefinition*> mMovedVariables;
// Flag set when inside a loop body (for move-in-loop detection)
bool mInsideLoop = false;
// Set of own variables from outer scope when inside a spawn body
std::set<VariableDefinition*> mSpawnOuterOwnVars;
// Flag indicating module uses concurrency features
bool mUsesConcurrency = false;
// Flag indicating a codegen error occurred (e.g., ownership violation)
bool mHasError = false;
// Buffer a user-facing codegen error through the single diagnostic path
// (gDiag, code "codegen") with the node's source location, and set
// mHasError so generate() reports failure. The driver renders everything
// via DiagnosticEngine::finish() at exit — the same located
// `file:line:col: error:` shape as parse/sema errors, and the LSP can
// publish them. Falls back to stderr if no engine is installed.
// ICE-style internal errors (verifier failures) stay direct stderr in
// the driver.
void reportError( const Statement *node, const std::string &message );
// Test-runner mode (qcc --emit-test-main); see setTestMode().
bool mTestMode = false;
// Current function context (for contract support)
FunctionDefinition *mCurrentFunction = nullptr;
llvm::AllocaInst *mResultAlloca = nullptr;
// Async wrapper context: when non-null, return statements should
// store the value here and branch to mAsyncExitBB instead of ret
llvm::AllocaInst *mAsyncResultAlloca = nullptr;
llvm::BasicBlock *mAsyncExitBB = nullptr;
llvm::Type *mAsyncReturnType = nullptr;
// Hint for empty array literals: set by variable declaration handler
// to the LLVM element type from the Array<T> type parameter.
// Reset to nullptr after use by genArrayLiteral.
llvm::Type *mArrayElemTypeHint = nullptr;
std::string mArrayElemTypeNameHint; // semantic type name for array element dtor
};
} // namespace QLang
#endif // BLANG_CODEGEN_H_