Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright (c) 2021-2025 ChilliBits. All rights reserved. | ||
2 | |||
3 | #pragma once | ||
4 | |||
5 | #include <CompilerPass.h> | ||
6 | #include <ast/ParallelizableASTVisitor.h> | ||
7 | #include <irgenerator/DebugInfoGenerator.h> | ||
8 | #include <irgenerator/OpRuleConversionManager.h> | ||
9 | #include <irgenerator/StdFunctionManager.h> | ||
10 | #include <symboltablebuilder/Scope.h> | ||
11 | #include <util/DeferredLogic.h> | ||
12 | |||
13 | namespace spice::compiler { | ||
14 | |||
15 | // Forward declarations | ||
16 | class ExprNode; | ||
17 | |||
18 | const char *const ANON_GLOBAL_STRING_NAME = "anon.string."; | ||
19 | const char *const ANON_GLOBAL_ARRAY_NAME = "anon.array."; | ||
20 | const char *const CAPTURES_PARAM_NAME = "captures"; | ||
21 | static const std::string PRODUCER_STRING = | ||
22 | "spice version " + std::string(SPICE_VERSION) + " (https://github.com/spicelang/spice)"; | ||
23 | |||
24 | enum Likeliness : uint8_t { | ||
25 | UNSPECIFIED, | ||
26 | LIKELY, | ||
27 | UNLIKELY, | ||
28 | }; | ||
29 | |||
30 | // Forward declarations | ||
31 | class SourceFile; | ||
32 | |||
33 | class IRGenerator final : CompilerPass, public ParallelizableASTVisitor { | ||
34 | public: | ||
35 | // Type definitions | ||
36 | using ParamInfoList = std::vector<std::pair<std::string, SymbolTableEntry *>>; | ||
37 | |||
38 | // Constructors | ||
39 | IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile); | ||
40 | |||
41 | // Friend classes | ||
42 | friend class StdFunctionManager; | ||
43 | friend class OpRuleConversionManager; | ||
44 | friend class DebugInfoGenerator; | ||
45 | friend class ScopeHandle; | ||
46 | |||
47 | // Visitor methods | ||
48 | // Top level definitions | ||
49 | std::any visitEntry(const EntryNode *node) override; | ||
50 | std::any visitMainFctDef(const MainFctDefNode *node) override; | ||
51 | std::any visitFctDef(const FctDefNode *node) override; | ||
52 | std::any visitProcDef(const ProcDefNode *node) override; | ||
53 | std::any visitStructDef(const StructDefNode *node) override; | ||
54 | std::any visitInterfaceDef(const InterfaceDefNode *node) override; | ||
55 | std::any visitEnumDef(const EnumDefNode *node) override; | ||
56 | std::any visitGenericTypeDef(const GenericTypeDefNode *node) override; | ||
57 | std::any visitAliasDef(const AliasDefNode *node) override; | ||
58 | std::any visitGlobalVarDef(const GlobalVarDefNode *node) override; | ||
59 | std::any visitExtDecl(const ExtDeclNode *node) override; | ||
60 | // Control structures | ||
61 | std::any visitUnsafeBlockDef(const UnsafeBlockNode *node) override; | ||
62 | std::any visitForLoop(const ForLoopNode *node) override; | ||
63 | std::any visitForeachLoop(const ForeachLoopNode *node) override; | ||
64 | std::any visitWhileLoop(const WhileLoopNode *node) override; | ||
65 | std::any visitDoWhileLoop(const DoWhileLoopNode *node) override; | ||
66 | std::any visitIfStmt(const IfStmtNode *node) override; | ||
67 | std::any visitElseStmt(const ElseStmtNode *node) override; | ||
68 | std::any visitSwitchStmt(const SwitchStmtNode *node) override; | ||
69 | std::any visitCaseBranch(const CaseBranchNode *node) override; | ||
70 | std::any visitDefaultBranch(const DefaultBranchNode *node) override; | ||
71 | std::any visitAssertStmt(const AssertStmtNode *node) override; | ||
72 | std::any visitAnonymousBlockStmt(const AnonymousBlockStmtNode *node) override; | ||
73 | // Statements | ||
74 | std::any visitStmtLst(const StmtLstNode *node) override; | ||
75 | std::any visitTypeAltsLst(const TypeAltsLstNode *node) override; | ||
76 | std::any visitDeclStmt(const DeclStmtNode *node) override; | ||
77 | std::any visitQualifierLst(const QualifierLstNode *node) override; | ||
78 | std::any visitModAttr(const ModAttrNode *node) override; | ||
79 | std::any visitTopLevelDefinitionAttr(const TopLevelDefinitionAttrNode *node) override; | ||
80 | std::any visitCaseConstant(const CaseConstantNode *node) override; | ||
81 | std::any visitReturnStmt(const ReturnStmtNode *node) override; | ||
82 | std::any visitBreakStmt(const BreakStmtNode *node) override; | ||
83 | std::any visitContinueStmt(const ContinueStmtNode *node) override; | ||
84 | std::any visitFallthroughStmt(const FallthroughStmtNode *node) override; | ||
85 | // Builtin functions | ||
86 | std::any visitBuiltinCall(const BuiltinCallNode *node) override; | ||
87 | std::any visitPrintfCall(const PrintfCallNode *node) override; | ||
88 | std::any visitSizeofCall(const SizeofCallNode *node) override; | ||
89 | std::any visitAlignofCall(const AlignofCallNode *node) override; | ||
90 | std::any visitTypeidCall(const TypeidCallNode *node) override; | ||
91 | std::any visitLenCall(const LenCallNode *node) override; | ||
92 | std::any visitPanicCall(const PanicCallNode *node) override; | ||
93 | std::any visitSysCall(const SysCallNode *node) override; | ||
94 | // Expressions | ||
95 | std::any visitAssignExpr(const AssignExprNode *node) override; | ||
96 | std::any visitTernaryExpr(const TernaryExprNode *node) override; | ||
97 | std::any visitLogicalOrExpr(const LogicalOrExprNode *node) override; | ||
98 | std::any visitLogicalAndExpr(const LogicalAndExprNode *node) override; | ||
99 | std::any visitBitwiseOrExpr(const BitwiseOrExprNode *node) override; | ||
100 | std::any visitBitwiseXorExpr(const BitwiseXorExprNode *node) override; | ||
101 | std::any visitBitwiseAndExpr(const BitwiseAndExprNode *node) override; | ||
102 | std::any visitEqualityExpr(const EqualityExprNode *node) override; | ||
103 | std::any visitRelationalExpr(const RelationalExprNode *node) override; | ||
104 | std::any visitShiftExpr(const ShiftExprNode *node) override; | ||
105 | std::any visitAdditiveExpr(const AdditiveExprNode *node) override; | ||
106 | std::any visitMultiplicativeExpr(const MultiplicativeExprNode *node) override; | ||
107 | std::any visitCastExpr(const CastExprNode *node) override; | ||
108 | std::any visitPrefixUnaryExpr(const PrefixUnaryExprNode *node) override; | ||
109 | std::any visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) override; | ||
110 | std::any visitAtomicExpr(const AtomicExprNode *node) override; | ||
111 | // Values and types | ||
112 | std::any visitValue(const ValueNode *node) override; | ||
113 | std::any visitConstant(const ConstantNode *node) override; | ||
114 | std::any visitFctCall(const FctCallNode *node) override; | ||
115 | std::any visitArrayInitialization(const ArrayInitializationNode *node) override; | ||
116 | std::any visitStructInstantiation(const StructInstantiationNode *node) override; | ||
117 | std::any visitLambdaFunc(const LambdaFuncNode *node) override; | ||
118 | std::any visitLambdaProc(const LambdaProcNode *node) override; | ||
119 | std::any visitLambdaExpr(const LambdaExprNode *node) override; | ||
120 | std::any visitDataType(const DataTypeNode *node) override; | ||
121 | |||
122 | // Public methods | ||
123 |
9/22✓ Branch 0 (109→110) taken 443 times.
✗ Branch 1 (109→222) not taken.
✓ Branch 2 (133→134) taken 17 times.
✗ Branch 3 (133→229) not taken.
✓ Branch 4 (14→15) taken 2111 times.
✗ Branch 5 (14→80) not taken.
✓ Branch 6 (19→20) taken 8163 times.
✗ Branch 7 (19→107) not taken.
✓ Branch 8 (29→30) taken 393 times.
✗ Branch 9 (29→87) not taken.
✓ Branch 10 (45→46) taken 76 times.
✗ Branch 11 (45→94) not taken.
✓ Branch 12 (46→47) taken 2 times.
✗ Branch 13 (46→163) not taken.
✓ Branch 14 (76→77) taken 2 times.
✗ Branch 15 (76→176) not taken.
✓ Branch 16 (110→111) taken 6 times.
✗ Branch 17 (110→190) not taken.
✗ Branch 18 (137→138) not taken.
✗ Branch 19 (137→204) not taken.
✗ Branch 20 (143→144) not taken.
✗ Branch 21 (143→208) not taken.
|
26127 | llvm::Value *insertAlloca(llvm::Type *llvmType, std::string varName = ""); |
124 | llvm::Value *insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile = false, const std::string &varName = "") const; | ||
125 | void insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile = false) const; | ||
126 | llvm::Value *insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices, | ||
127 |
3/6✓ Branch 0 (38→39) taken 305 times.
✗ Branch 1 (38→143) not taken.
✓ Branch 2 (43→44) taken 2855 times.
✗ Branch 3 (43→147) not taken.
✓ Branch 4 (29→30) taken 13 times.
✗ Branch 5 (29→71) not taken.
|
8904 | std::string varName = "") const; |
128 |
17/28✓ Branch 0 (53→54) taken 665 times.
✗ Branch 1 (53→115) not taken.
✓ Branch 2 (57→58) taken 147 times.
✗ Branch 3 (57→119) not taken.
✓ Branch 4 (76→77) taken 70 times.
✗ Branch 5 (76→130) not taken.
✓ Branch 6 (83→84) taken 327 times.
✗ Branch 7 (83→136) not taken.
✓ Branch 8 (87→88) taken 2370 times.
✓ Branch 9 (87→91) taken 15 times.
✓ Branch 10 (65→66) taken 251 times.
✓ Branch 11 (65→125) taken 2095 times.
✓ Branch 12 (69→70) taken 106 times.
✗ Branch 13 (69→136) not taken.
✓ Branch 14 (83→84) taken 297 times.
✗ Branch 15 (83→131) not taken.
✓ Branch 16 (87→88) taken 97 times.
✓ Branch 17 (87→90) taken 200 times.
✓ Branch 18 (51→52) taken 710 times.
✗ Branch 19 (51→402) not taken.
✓ Branch 20 (55→56) taken 710 times.
✗ Branch 21 (55→407) not taken.
✓ Branch 22 (86→87) taken 45 times.
✗ Branch 23 (86→421) not taken.
✓ Branch 24 (90→91) taken 45 times.
✗ Branch 25 (90→535) not taken.
✓ Branch 26 (95→96) taken 16 times.
✗ Branch 27 (95→427) not taken.
|
14133 | llvm::Value *insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned index, std::string varName = "") const; |
129 | llvm::Value *resolveValue(const ExprNode *node); | ||
130 | llvm::Value *resolveValue(const ExprNode *node, LLVMExprResult &exprResult) const; | ||
131 | llvm::Value *resolveValue(const QualType &qualType, LLVMExprResult &exprResult) const; | ||
132 | llvm::Value *resolveAddress(const ASTNode *node); | ||
133 | llvm::Value *resolveAddress(LLVMExprResult &exprResult); | ||
134 | [[nodiscard]] llvm::Constant *getDefaultValueForSymbolType(const QualType &symbolType); | ||
135 | [[nodiscard]] static std::string getIRString(llvm::Module *llvmModule, bool comparableOutput); | ||
136 | |||
137 | private: | ||
138 | // Private methods | ||
139 | llvm::Constant *getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const; | ||
140 | llvm::BasicBlock *createBlock(const std::string &blockName = "") const; | ||
141 | void switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct = nullptr); | ||
142 | void terminateBlock(const StmtLstNode *stmtLstNode); | ||
143 | void insertJump(llvm::BasicBlock *targetBlock); | ||
144 | void insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock, | ||
145 | Likeliness likeliness = UNSPECIFIED); | ||
146 | void verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const; | ||
147 | void verifyModule(const CodeLoc &codeLoc) const; | ||
148 | LLVMExprResult doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node); | ||
149 | LLVMExprResult doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode, const ASTNode *node, | ||
150 | bool isDecl = false); | ||
151 | LLVMExprResult doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs, const QualType &rhsSType, | ||
152 | const ASTNode *node, bool isDecl); | ||
153 | void generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress, bool isVolatile) const; | ||
154 | void autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) const; | ||
155 | llvm::GlobalVariable *createGlobalConst(const std::string &baseName, llvm::Constant *constant) const; | ||
156 | llvm::GlobalVariable *createGlobalStringConst(const std::string &baseName, const std::string &value) const; | ||
157 | llvm::GlobalVariable *createGlobalStringConst(const std::string &baseName, const std::string &value, | ||
158 | const CodeLoc &codeLoc) const; | ||
159 | [[nodiscard]] std::string getUnusedGlobalName(const std::string &baseName) const; | ||
160 | static void materializeConstant(LLVMExprResult &exprResult); | ||
161 | const std::vector<const Function *> &getOpFctPointers(const ASTNode *node) const; | ||
162 | llvm::Value *buildFatFctPtr(Scope *bodyScope, llvm::Type *capturesStructType, llvm::Value *lambda); | ||
163 | llvm::Type *buildCapturesContainerType(const CaptureMap &captures) const; | ||
164 | void unpackCapturesToLocalVariables(const CaptureMap &captures, llvm::Value *val, llvm::Type *structType); | ||
165 | |||
166 | // Generate implicit | ||
167 | llvm::Value *doImplicitCast(llvm::Value *src, QualType dstSTy, QualType srcSTy); | ||
168 | void generateScopeCleanup(const StmtLstNode *node) const; | ||
169 | void generateFctDecl(const Function *fct, const std::vector<llvm::Value *> &args) const; | ||
170 | llvm::CallInst*generateFctCall(const Function *fct, const std::vector<llvm::Value *> &args) const; | ||
171 | llvm::Value *generateFctDeclAndCall(const Function *fct, const std::vector<llvm::Value *> &args) const; | ||
172 | void generateProcDeclAndCall(const Function *proc, const std::vector<llvm::Value *> &args) const; | ||
173 | void generateCtorOrDtorCall(const SymbolTableEntry *entry, const Function *ctorOrDtor, | ||
174 | const std::vector<llvm::Value *> &args) const; | ||
175 | void generateCtorOrDtorCall(llvm::Value *structAddr, const Function *ctorOrDtor, const std::vector<llvm::Value *> &args) const; | ||
176 | void generateDeallocCall(llvm::Value *variableAddress) const; | ||
177 | llvm::Function *generateImplicitFunction(const std::function<void(void)> &generateBody, const Function *spiceFunc); | ||
178 | llvm::Function *generateImplicitProcedure(const std::function<void(void)> &generateBody, const Function *spiceProc); | ||
179 | void generateCtorBodyPreamble(Scope *bodyScope); | ||
180 | void generateDefaultCtor(const Function *ctorFunction); | ||
181 | void generateCopyCtorBodyPreamble(const Function *copyCtorFunction); | ||
182 | void generateDefaultCopyCtor(const Function *copyCtorFunction); | ||
183 | void generateDtorBodyPreamble(const Function *dtorFunction) const; | ||
184 | void generateDefaultDtor(const Function *dtorFunction); | ||
185 | void generateTestMain(); | ||
186 | |||
187 | // Generate target dependent | ||
188 | std::string getSysCallAsmString(uint8_t numRegs) const; | ||
189 | std::string getSysCallConstraintString(uint8_t numRegs) const; | ||
190 | |||
191 | // Generate VTable | ||
192 | llvm::Constant *generateTypeInfoName(StructBase *spiceStruct) const; | ||
193 | llvm::Constant *generateTypeInfo(StructBase *spiceStruct) const; | ||
194 | llvm::Constant *generateVTable(StructBase *spiceStruct) const; | ||
195 | void generateVTableInitializer(const StructBase *spiceStruct) const; | ||
196 | |||
197 | // Private members | ||
198 | llvm::LLVMContext &context; | ||
199 | llvm::IRBuilder<> &builder; | ||
200 | llvm::Module *module; | ||
201 | OpRuleConversionManager conversionManager; | ||
202 | const StdFunctionManager stdFunctionManager; | ||
203 | DebugInfoGenerator diGenerator = DebugInfoGenerator(this); | ||
204 | struct CommonLLVMTypes { | ||
205 | llvm::StructType *fatPtrType = nullptr; | ||
206 | } llvmTypes; | ||
207 | std::vector<llvm::BasicBlock *> breakBlocks; | ||
208 | std::vector<llvm::BasicBlock *> continueBlocks; | ||
209 | std::stack<llvm::BasicBlock *> fallthroughBlocks; | ||
210 | llvm::BasicBlock *allocaInsertBlock = nullptr; | ||
211 | llvm::AllocaInst *allocaInsertInst = nullptr; | ||
212 | bool blockAlreadyTerminated = false; | ||
213 | bool isInCtorBody = false; | ||
214 | std::vector<DeferredLogic> deferredVTableInitializations; | ||
215 | }; | ||
216 | |||
217 | } // namespace spice::compiler | ||
218 |