blob: 9f66115cb7027e9c4f03a93a707eaf92862e0259 [file] [log] [blame]
// Copyright 2016 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_Nucleus_hpp
#define rr_Nucleus_hpp
#include <atomic>
#include <cassert>
#include <cstdarg>
#include <cstdint>
#include <memory>
#include <vector>
#ifdef None
#undef None // b/127920555
#endif
namespace rr
{
class Type;
class Value;
class SwitchCases;
class BasicBlock;
class Routine;
// Optimization holds the optimization settings for code generation.
class Optimization
{
public:
enum class Level
{
None,
Less,
Default,
Aggressive,
};
enum class Pass
{
Disabled,
InstructionCombining,
CFGSimplification,
LICM,
AggressiveDCE,
GVN,
Reassociate,
DeadStoreElimination,
SCCP,
ScalarReplAggregates,
EarlyCSEPass,
Count,
};
using Passes = std::vector<Pass>;
Optimization() = default;
Optimization(Level level, const Passes & passes) : level(level), passes(passes) {}
Level getLevel() const { return level; }
const Passes & getPasses() const { return passes; }
private:
Level level = Level::Default;
Passes passes;
};
// Config holds the Reactor configuration settings.
class Config
{
public:
// Edit holds a number of modifications to a config, that can be applied
// on an existing Config to produce a new Config with the specified
// changes.
class Edit
{
public:
static const Edit None;
Edit & set(Optimization::Level level) { optLevel = level; optLevelChanged = true; return *this; }
Edit & add(Optimization::Pass pass) { optPassEdits.push_back({ListEdit::Add, pass}); return *this; }
Edit & remove(Optimization::Pass pass) { optPassEdits.push_back({ListEdit::Remove, pass}); return *this; }
Edit & clearOptimizationPasses() { optPassEdits.push_back({ListEdit::Clear, Optimization::Pass::Disabled}); return *this; }
Config apply(const Config &cfg) const;
private:
enum class ListEdit { Add, Remove, Clear };
using OptPassesEdit = std::pair<ListEdit, Optimization::Pass>;
template <typename T>
void apply(const std::vector<std::pair<ListEdit, T>> & edits, std::vector<T>& list) const;
Optimization::Level optLevel;
bool optLevelChanged = false;
std::vector<OptPassesEdit> optPassEdits;
};
Config() = default;
Config(const Optimization & optimization) : optimization(optimization) {}
const Optimization & getOptimization() const { return optimization; }
private:
Optimization optimization;
};
class Nucleus
{
public:
Nucleus();
virtual ~Nucleus();
// Default configuration to use when no other configuration is specified.
// The new configuration will be applied to subsequent reactor calls.
static void setDefaultConfig(const Config &cfg);
static void adjustDefaultConfig(const Config::Edit &cfgEdit);
static Config getDefaultConfig();
std::shared_ptr<Routine> acquireRoutine(const char *name, const Config::Edit &cfgEdit = Config::Edit::None);
static Value *allocateStackVariable(Type *type, int arraySize = 0);
static BasicBlock *createBasicBlock();
static BasicBlock *getInsertBlock();
static void setInsertBlock(BasicBlock *basicBlock);
static void createFunction(Type *ReturnType, std::vector<Type*> &Params);
static Value *getArgument(unsigned int index);
// Coroutines
using CoroutineHandle = void*;
template <typename... ARGS>
using CoroutineBegin = CoroutineHandle(ARGS...);
using CoroutineAwait = bool(CoroutineHandle, void* yieldValue);
using CoroutineDestroy = void(CoroutineHandle);
enum CoroutineEntries
{
CoroutineEntryBegin = 0,
CoroutineEntryAwait,
CoroutineEntryDestroy,
CoroutineEntryCount
};
static void createCoroutine(Type *ReturnType, std::vector<Type*> &Params);
std::shared_ptr<Routine> acquireCoroutine(const char *name, const Config::Edit &cfg = Config::Edit::None);
static void yield(Value*);
// Terminators
static void createRetVoid();
static void createRet(Value *V);
static void createBr(BasicBlock *dest);
static void createCondBr(Value *cond, BasicBlock *ifTrue, BasicBlock *ifFalse);
// Binary operators
static Value *createAdd(Value *lhs, Value *rhs);
static Value *createSub(Value *lhs, Value *rhs);
static Value *createMul(Value *lhs, Value *rhs);
static Value *createUDiv(Value *lhs, Value *rhs);
static Value *createSDiv(Value *lhs, Value *rhs);
static Value *createFAdd(Value *lhs, Value *rhs);
static Value *createFSub(Value *lhs, Value *rhs);
static Value *createFMul(Value *lhs, Value *rhs);
static Value *createFDiv(Value *lhs, Value *rhs);
static Value *createURem(Value *lhs, Value *rhs);
static Value *createSRem(Value *lhs, Value *rhs);
static Value *createFRem(Value *lhs, Value *rhs);
static Value *createShl(Value *lhs, Value *rhs);
static Value *createLShr(Value *lhs, Value *rhs);
static Value *createAShr(Value *lhs, Value *rhs);
static Value *createAnd(Value *lhs, Value *rhs);
static Value *createOr(Value *lhs, Value *rhs);
static Value *createXor(Value *lhs, Value *rhs);
// Unary operators
static Value *createNeg(Value *V);
static Value *createFNeg(Value *V);
static Value *createNot(Value *V);
// Memory instructions
static Value *createLoad(Value *ptr, Type *type, bool isVolatile = false, unsigned int alignment = 0, bool atomic = false , std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createStore(Value *value, Value *ptr, Type *type, bool isVolatile = false, unsigned int aligment = 0, bool atomic = false, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex);
// Masked Load / Store instructions
static Value *createMaskedLoad(Value *base, Type *elementType, Value *mask, unsigned int alignment, bool zeroMaskedLanes);
static void createMaskedStore(Value *base, Value *value, Value *mask, unsigned int alignment);
// Scatter / Gather instructions
static Value *createGather(Value *base, Type *elementType, Value *offsets, Value *mask, unsigned int alignment, bool zeroMaskedLanes);
static void createScatter(Value *base, Value *value, Value *offsets, Value *mask, unsigned int alignment);
// Barrier instructions
static void createFence(std::memory_order memoryOrder);
// Atomic instructions
static Value *createAtomicAdd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicSub(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicAnd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicOr(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicXor(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicUMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicUMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicExchange(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
static Value *createAtomicCompareExchange(Value *ptr, Value *value, Value *compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal);
// Cast/Conversion Operators
static Value *createTrunc(Value *V, Type *destType);
static Value *createZExt(Value *V, Type *destType);
static Value *createSExt(Value *V, Type *destType);
static Value *createFPToSI(Value *V, Type *destType);
static Value *createSIToFP(Value *V, Type *destType);
static Value *createFPTrunc(Value *V, Type *destType);
static Value *createFPExt(Value *V, Type *destType);
static Value *createBitCast(Value *V, Type *destType);
// Compare instructions
static Value *createPtrEQ(Value *lhs, Value *rhs);
static Value *createICmpEQ(Value *lhs, Value *rhs);
static Value *createICmpNE(Value *lhs, Value *rhs);
static Value *createICmpUGT(Value *lhs, Value *rhs);
static Value *createICmpUGE(Value *lhs, Value *rhs);
static Value *createICmpULT(Value *lhs, Value *rhs);
static Value *createICmpULE(Value *lhs, Value *rhs);
static Value *createICmpSGT(Value *lhs, Value *rhs);
static Value *createICmpSGE(Value *lhs, Value *rhs);
static Value *createICmpSLT(Value *lhs, Value *rhs);
static Value *createICmpSLE(Value *lhs, Value *rhs);
static Value *createFCmpOEQ(Value *lhs, Value *rhs);
static Value *createFCmpOGT(Value *lhs, Value *rhs);
static Value *createFCmpOGE(Value *lhs, Value *rhs);
static Value *createFCmpOLT(Value *lhs, Value *rhs);
static Value *createFCmpOLE(Value *lhs, Value *rhs);
static Value *createFCmpONE(Value *lhs, Value *rhs);
static Value *createFCmpORD(Value *lhs, Value *rhs);
static Value *createFCmpUNO(Value *lhs, Value *rhs);
static Value *createFCmpUEQ(Value *lhs, Value *rhs);
static Value *createFCmpUGT(Value *lhs, Value *rhs);
static Value *createFCmpUGE(Value *lhs, Value *rhs);
static Value *createFCmpULT(Value *lhs, Value *rhs);
static Value *createFCmpULE(Value *lhs, Value *rhs);
static Value *createFCmpUNE(Value *lhs, Value *rhs);
// Vector instructions
static Value *createExtractElement(Value *vector, Type *type, int index);
static Value *createInsertElement(Value *vector, Value *element, int index);
static Value *createShuffleVector(Value *V1, Value *V2, const int *select);
// Other instructions
static Value *createSelect(Value *C, Value *ifTrue, Value *ifFalse);
static SwitchCases *createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases);
static void addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch);
static void createUnreachable();
// Constant values
static Value *createNullValue(Type *type);
static Value *createConstantLong(int64_t i);
static Value *createConstantInt(int i);
static Value *createConstantInt(unsigned int i);
static Value *createConstantBool(bool b);
static Value *createConstantByte(signed char i);
static Value *createConstantByte(unsigned char i);
static Value *createConstantShort(short i);
static Value *createConstantShort(unsigned short i);
static Value *createConstantFloat(float x);
static Value *createNullPointer(Type *type);
static Value *createConstantVector(const int64_t *constants, Type *type);
static Value *createConstantVector(const double *constants, Type *type);
static Type *getPointerType(Type *elementType);
};
}
#endif // rr_Nucleus_hpp