| // Copyright 2019 The SwiftShader Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #ifndef rr_LLVMReactorDebugInfo_hpp | |
| #define rr_LLVMReactorDebugInfo_hpp | |
| #include "Reactor.hpp" | |
| #ifdef ENABLE_RR_DEBUG_INFO | |
| #include <unordered_set> | |
| #include <unordered_map> | |
| #include <vector> | |
| #include <memory> | |
| // Forward declarations | |
| namespace llvm | |
| { | |
| class BasicBlock; | |
| class ConstantFolder; | |
| class DIBuilder; | |
| class DICompileUnit; | |
| class DIFile; | |
| class DILocation; | |
| class DIScope; | |
| class DISubprogram; | |
| class DIType; | |
| class Function; | |
| class Instruction; | |
| class IRBuilderDefaultInserter; | |
| class JITEventListener; | |
| class LLVMContext; | |
| class LoadedObjectInfo; | |
| class Module; | |
| class Type; | |
| class Value; | |
| namespace object | |
| { | |
| class ObjectFile; | |
| } | |
| template <typename T, typename Inserter> class IRBuilder; | |
| } // namespace llvm | |
| namespace rr | |
| { | |
| class Type; | |
| class Value; | |
| // DebugInfo generates LLVM DebugInfo IR from the C++ source that calls | |
| // into Reactor functions. See docs/ReactorDebugInfo.mk for more information. | |
| class DebugInfo | |
| { | |
| public: | |
| using IRBuilder = llvm::IRBuilder<llvm::ConstantFolder, llvm::IRBuilderDefaultInserter>; | |
| DebugInfo(IRBuilder *builder, | |
| llvm::LLVMContext *context, | |
| llvm::Module *module, | |
| llvm::Function *function); | |
| ~DebugInfo(); | |
| // Finalize debug info generation. Must be called before the LLVM module | |
| // is built. | |
| void Finalize(); | |
| // Updates the current source location. | |
| void EmitLocation(); | |
| // Binds the value to its symbol in the source file. | |
| // See docs/ReactorDebugInfo.mk for more information. | |
| void EmitVariable(Value *value); | |
| // Forcefully flush the binding of the last variable name. | |
| // Used for binding the initializer of `For` loops. | |
| void Flush(); | |
| // NotifyObjectEmitted informs any attached debuggers of the JIT'd | |
| // object. | |
| static void NotifyObjectEmitted(const llvm::object::ObjectFile &Obj, const llvm::LoadedObjectInfo &L); | |
| // NotifyFreeingObject informs any attached debuggers that the JIT'd | |
| // object is now invalid. | |
| static void NotifyFreeingObject(const llvm::object::ObjectFile &Obj); | |
| private: | |
| struct Token | |
| { | |
| enum Kind | |
| { | |
| Identifier, | |
| Return | |
| }; | |
| Kind kind; | |
| std::string identifier; | |
| }; | |
| using LineTokens = std::unordered_map<unsigned int, Token>; | |
| struct FunctionLocation | |
| { | |
| std::string name; | |
| std::string file; | |
| bool operator == (const FunctionLocation &rhs) const { return name == rhs.name && file == rhs.file; } | |
| bool operator != (const FunctionLocation &rhs) const { return !(*this == rhs); } | |
| struct Hash | |
| { | |
| std::size_t operator()(const FunctionLocation &l) const noexcept | |
| { | |
| return std::hash<std::string>()(l.file) * 31 + | |
| std::hash<std::string>()(l.name); | |
| } | |
| }; | |
| }; | |
| struct Location | |
| { | |
| FunctionLocation function; | |
| unsigned int line = 0; | |
| bool operator == (const Location &rhs) const { return function == rhs.function && line == rhs.line; } | |
| bool operator != (const Location &rhs) const { return !(*this == rhs); } | |
| struct Hash | |
| { | |
| std::size_t operator()(const Location &l) const noexcept | |
| { | |
| return FunctionLocation::Hash()(l.function) * 31 + | |
| std::hash<unsigned int>()(l.line); | |
| } | |
| }; | |
| }; | |
| using Backtrace = std::vector<Location>; | |
| struct Pending | |
| { | |
| std::string name; | |
| Location location; | |
| llvm::DILocation *diLocation = nullptr; | |
| llvm::Value *value = nullptr; | |
| llvm::Instruction *insertAfter = nullptr; | |
| llvm::BasicBlock *block = nullptr; | |
| llvm::DIScope *scope = nullptr; | |
| bool addNopOnNextLine = false; | |
| }; | |
| struct Scope | |
| { | |
| Location location; | |
| llvm::DIScope *di; | |
| std::unordered_set<std::string> symbols; | |
| Pending pending; | |
| }; | |
| void registerBasicTypes(); | |
| void emitPending(Scope &scope, IRBuilder *builder); | |
| // Returns the source location of the non-Reactor calling function. | |
| Location getCallerLocation() const; | |
| // Returns the backtrace for the callstack, starting at the first | |
| // non-Reactor file. If limit is non-zero, then a maximum of limit | |
| // frames will be returned. | |
| Backtrace getCallerBacktrace(size_t limit = 0) const; | |
| llvm::DILocation* getLocation(const Backtrace &backtrace, size_t i); | |
| llvm::DIType *getOrCreateType(llvm::Type* type); | |
| llvm::DIFile *getOrCreateFile(const char* path); | |
| LineTokens const *getOrParseFileTokens(const char* path); | |
| // Synchronizes diScope with the current backtrace. | |
| void syncScope(Backtrace const& backtrace); | |
| IRBuilder *builder; | |
| llvm::LLVMContext *context; | |
| llvm::Module *module; | |
| llvm::Function *function; | |
| std::unique_ptr<llvm::DIBuilder> diBuilder; | |
| llvm::DICompileUnit *diCU; | |
| llvm::DISubprogram *diSubprogram; | |
| llvm::DILocation *diRootLocation; | |
| std::vector<Scope> diScope; | |
| std::unordered_map<std::string, llvm::DIFile*> diFiles; | |
| std::unordered_map<llvm::Type*, llvm::DIType*> diTypes; | |
| std::unordered_map<std::string, std::unique_ptr<LineTokens>> fileTokens; | |
| std::vector<void const*> pushed; | |
| }; | |
| } // namespace rr | |
| #endif // ENABLE_RR_DEBUG_INFO | |
| #endif // rr_LLVMReactorDebugInfo_hpp |