| // 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 |