|  | // 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_LLVMReactor_hpp | 
|  | #define rr_LLVMReactor_hpp | 
|  |  | 
|  | #include "Nucleus.hpp" | 
|  |  | 
|  | #include "Debug.hpp" | 
|  | #include "LLVMReactorDebugInfo.hpp" | 
|  | #include "Print.hpp" | 
|  |  | 
|  | #ifdef _MSC_VER | 
|  | __pragma(warning(push)) | 
|  | __pragma(warning(disable : 4146))  // unary minus operator applied to unsigned type, result still unsigned | 
|  | #endif | 
|  |  | 
|  | #include "llvm/IR/IRBuilder.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  |  | 
|  | #ifdef _MSC_VER | 
|  | __pragma(warning(pop)) | 
|  | #endif | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | namespace llvm | 
|  | { | 
|  |  | 
|  | class Type; | 
|  | class Value; | 
|  |  | 
|  | }  // namespace llvm | 
|  |  | 
|  | namespace rr { | 
|  |  | 
|  | class Type; | 
|  | class Value; | 
|  |  | 
|  | llvm::Type *T(Type *t); | 
|  |  | 
|  | inline Type *T(llvm::Type *t) | 
|  | { | 
|  | return reinterpret_cast<Type *>(t); | 
|  | } | 
|  |  | 
|  | inline llvm::Value *V(Value *t) | 
|  | { | 
|  | return reinterpret_cast<llvm::Value *>(t); | 
|  | } | 
|  |  | 
|  | inline Value *V(llvm::Value *t) | 
|  | { | 
|  | return reinterpret_cast<Value *>(t); | 
|  | } | 
|  |  | 
|  | inline std::vector<llvm::Value *> V(const std::vector<Value *> &values) | 
|  | { | 
|  | std::vector<llvm::Value *> result; | 
|  | result.reserve(values.size()); | 
|  | for(auto &v : values) | 
|  | { | 
|  | result.push_back(V(v)); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | // Emits a no-op instruction that will not be optimized away. | 
|  | // Useful for emitting something that can have a source location without | 
|  | // effect. | 
|  | void Nop(); | 
|  |  | 
|  | class Routine; | 
|  | class Config; | 
|  |  | 
|  | // JITBuilder holds all the LLVM state for building routines. | 
|  | class JITBuilder | 
|  | { | 
|  | public: | 
|  | JITBuilder(const rr::Config &config); | 
|  |  | 
|  | void optimize(const rr::Config &cfg); | 
|  |  | 
|  | std::shared_ptr<rr::Routine> acquireRoutine(llvm::Function **funcs, size_t count, const rr::Config &cfg); | 
|  |  | 
|  | const Config config; | 
|  | llvm::LLVMContext context; | 
|  | std::unique_ptr<llvm::Module> module; | 
|  | std::unique_ptr<llvm::IRBuilder<>> builder; | 
|  | llvm::Function *function = nullptr; | 
|  |  | 
|  | struct CoroutineState | 
|  | { | 
|  | llvm::Function *await = nullptr; | 
|  | llvm::Function *destroy = nullptr; | 
|  | llvm::Value *handle = nullptr; | 
|  | llvm::Value *id = nullptr; | 
|  | llvm::Value *promise = nullptr; | 
|  | llvm::Type *yieldType = nullptr; | 
|  | llvm::BasicBlock *entryBlock = nullptr; | 
|  | llvm::BasicBlock *suspendBlock = nullptr; | 
|  | llvm::BasicBlock *endBlock = nullptr; | 
|  | llvm::BasicBlock *destroyBlock = nullptr; | 
|  | }; | 
|  | CoroutineState coroutine; | 
|  |  | 
|  | #ifdef ENABLE_RR_DEBUG_INFO | 
|  | std::unique_ptr<rr::DebugInfo> debugInfo; | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | inline std::memory_order atomicOrdering(llvm::AtomicOrdering memoryOrder) | 
|  | { | 
|  | switch(memoryOrder) | 
|  | { | 
|  | case llvm::AtomicOrdering::Monotonic: return std::memory_order_relaxed;  // https://llvm.org/docs/Atomics.html#monotonic | 
|  | case llvm::AtomicOrdering::Acquire: return std::memory_order_acquire; | 
|  | case llvm::AtomicOrdering::Release: return std::memory_order_release; | 
|  | case llvm::AtomicOrdering::AcquireRelease: return std::memory_order_acq_rel; | 
|  | case llvm::AtomicOrdering::SequentiallyConsistent: return std::memory_order_seq_cst; | 
|  | default: | 
|  | UNREACHABLE("memoryOrder: %d", int(memoryOrder)); | 
|  | return std::memory_order_acq_rel; | 
|  | } | 
|  | } | 
|  |  | 
|  | inline llvm::AtomicOrdering atomicOrdering(bool atomic, std::memory_order memoryOrder) | 
|  | { | 
|  | if(!atomic) | 
|  | { | 
|  | return llvm::AtomicOrdering::NotAtomic; | 
|  | } | 
|  |  | 
|  | switch(memoryOrder) | 
|  | { | 
|  | case std::memory_order_relaxed: return llvm::AtomicOrdering::Monotonic;  // https://llvm.org/docs/Atomics.html#monotonic | 
|  | case std::memory_order_consume: return llvm::AtomicOrdering::Acquire;    // https://llvm.org/docs/Atomics.html#acquire: "It should also be used for C++11/C11 memory_order_consume." | 
|  | case std::memory_order_acquire: return llvm::AtomicOrdering::Acquire; | 
|  | case std::memory_order_release: return llvm::AtomicOrdering::Release; | 
|  | case std::memory_order_acq_rel: return llvm::AtomicOrdering::AcquireRelease; | 
|  | case std::memory_order_seq_cst: return llvm::AtomicOrdering::SequentiallyConsistent; | 
|  | default: | 
|  | UNREACHABLE("memoryOrder: %d", int(memoryOrder)); | 
|  | return llvm::AtomicOrdering::AcquireRelease; | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace rr | 
|  |  | 
|  | #endif  // rr_LLVMReactor_hpp |