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