blob: d18869fe8f81c9e12b6412273d312481cf58e739 [file] [log] [blame]
// 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(const char *name, 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