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