1// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef rr_Nucleus_hpp
16#define rr_Nucleus_hpp
17
18#include <atomic>
19#include <cassert>
20#include <cstdarg>
21#include <cstdint>
22#include <memory>
23#include <vector>
24
25#ifdef None
26#undef None // b/127920555
27#endif
28
29namespace rr
30{
31 class Type;
32 class Value;
33 class SwitchCases;
34 class BasicBlock;
35 class Routine;
36
37 // Optimization holds the optimization settings for code generation.
38 class Optimization
39 {
40 public:
41 enum class Level
42 {
43 None,
44 Less,
45 Default,
46 Aggressive,
47 };
48
49 enum class Pass
50 {
51 Disabled,
52 InstructionCombining,
53 CFGSimplification,
54 LICM,
55 AggressiveDCE,
56 GVN,
57 Reassociate,
58 DeadStoreElimination,
59 SCCP,
60 ScalarReplAggregates,
61 EarlyCSEPass,
62
63 Count,
64 };
65
66 using Passes = std::vector<Pass>;
67
68 Optimization() = default;
69 Optimization(Level level, const Passes & passes) : level(level), passes(passes) {}
70
71 Level getLevel() const { return level; }
72 const Passes & getPasses() const { return passes; }
73
74 private:
75 Level level = Level::Default;
76 Passes passes;
77 };
78
79 // Config holds the Reactor configuration settings.
80 class Config
81 {
82 public:
83 // Edit holds a number of modifications to a config, that can be applied
84 // on an existing Config to produce a new Config with the specified
85 // changes.
86 class Edit
87 {
88 public:
89 static const Edit None;
90
91 Edit & set(Optimization::Level level) { optLevel = level; optLevelChanged = true; return *this; }
92 Edit & add(Optimization::Pass pass) { optPassEdits.push_back({ListEdit::Add, pass}); return *this; }
93 Edit & remove(Optimization::Pass pass) { optPassEdits.push_back({ListEdit::Remove, pass}); return *this; }
94 Edit & clearOptimizationPasses() { optPassEdits.push_back({ListEdit::Clear, Optimization::Pass::Disabled}); return *this; }
95
96 Config apply(const Config &cfg) const;
97
98 private:
99 enum class ListEdit { Add, Remove, Clear };
100 using OptPassesEdit = std::pair<ListEdit, Optimization::Pass>;
101
102 template <typename T>
103 void apply(const std::vector<std::pair<ListEdit, T>> & edits, std::vector<T>& list) const;
104
105 Optimization::Level optLevel;
106 bool optLevelChanged = false;
107 std::vector<OptPassesEdit> optPassEdits;
108 };
109
110 Config() = default;
111 Config(const Optimization & optimization) : optimization(optimization) {}
112
113 const Optimization & getOptimization() const { return optimization; }
114
115 private:
116 Optimization optimization;
117 };
118
119 class Nucleus
120 {
121 public:
122 Nucleus();
123
124 virtual ~Nucleus();
125
126 // Default configuration to use when no other configuration is specified.
127 // The new configuration will be applied to subsequent reactor calls.
128 static void setDefaultConfig(const Config &cfg);
129 static void adjustDefaultConfig(const Config::Edit &cfgEdit);
130 static Config getDefaultConfig();
131
132 std::shared_ptr<Routine> acquireRoutine(const char *name, const Config::Edit &cfgEdit = Config::Edit::None);
133
134 static Value *allocateStackVariable(Type *type, int arraySize = 0);
135 static BasicBlock *createBasicBlock();
136 static BasicBlock *getInsertBlock();
137 static void setInsertBlock(BasicBlock *basicBlock);
138
139 static void createFunction(Type *ReturnType, std::vector<Type*> &Params);
140 static Value *getArgument(unsigned int index);
141
142 // Coroutines
143 using CoroutineHandle = void*;
144
145 template <typename... ARGS>
146 using CoroutineBegin = CoroutineHandle(ARGS...);
147 using CoroutineAwait = bool(CoroutineHandle, void* yieldValue);
148 using CoroutineDestroy = void(CoroutineHandle);
149
150 enum CoroutineEntries
151 {
152 CoroutineEntryBegin = 0,
153 CoroutineEntryAwait,
154 CoroutineEntryDestroy,
155 CoroutineEntryCount
156 };
157
158 static void createCoroutine(Type *ReturnType, std::vector<Type*> &Params);
159 std::shared_ptr<Routine> acquireCoroutine(const char *name, const Config::Edit &cfg = Config::Edit::None);
160 static void yield(Value*);
161
162 // Terminators
163 static void createRetVoid();
164 static void createRet(Value *V);
165 static void createBr(BasicBlock *dest);
166 static void createCondBr(Value *cond, BasicBlock *ifTrue, BasicBlock *ifFalse);
167
168 // Binary operators
169 static Value *createAdd(Value *lhs, Value *rhs);
170 static Value *createSub(Value *lhs, Value *rhs);
171 static Value *createMul(Value *lhs, Value *rhs);
172 static Value *createUDiv(Value *lhs, Value *rhs);
173 static Value *createSDiv(Value *lhs, Value *rhs);
174 static Value *createFAdd(Value *lhs, Value *rhs);
175 static Value *createFSub(Value *lhs, Value *rhs);
176 static Value *createFMul(Value *lhs, Value *rhs);
177 static Value *createFDiv(Value *lhs, Value *rhs);
178 static Value *createURem(Value *lhs, Value *rhs);
179 static Value *createSRem(Value *lhs, Value *rhs);
180 static Value *createFRem(Value *lhs, Value *rhs);
181 static Value *createShl(Value *lhs, Value *rhs);
182 static Value *createLShr(Value *lhs, Value *rhs);
183 static Value *createAShr(Value *lhs, Value *rhs);
184 static Value *createAnd(Value *lhs, Value *rhs);
185 static Value *createOr(Value *lhs, Value *rhs);
186 static Value *createXor(Value *lhs, Value *rhs);
187
188 // Unary operators
189 static Value *createNeg(Value *V);
190 static Value *createFNeg(Value *V);
191 static Value *createNot(Value *V);
192
193 // Memory instructions
194 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);
195 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);
196 static Value *createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex);
197
198 // Masked Load / Store instructions
199 static Value *createMaskedLoad(Value *base, Type *elementType, Value *mask, unsigned int alignment, bool zeroMaskedLanes);
200 static void createMaskedStore(Value *base, Value *value, Value *mask, unsigned int alignment);
201
202 // Scatter / Gather instructions
203 static Value *createGather(Value *base, Type *elementType, Value *offsets, Value *mask, unsigned int alignment, bool zeroMaskedLanes);
204 static void createScatter(Value *base, Value *value, Value *offsets, Value *mask, unsigned int alignment);
205
206 // Barrier instructions
207 static void createFence(std::memory_order memoryOrder);
208
209 // Atomic instructions
210 static Value *createAtomicAdd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
211 static Value *createAtomicSub(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
212 static Value *createAtomicAnd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
213 static Value *createAtomicOr(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
214 static Value *createAtomicXor(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
215 static Value *createAtomicMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
216 static Value *createAtomicMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
217 static Value *createAtomicUMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
218 static Value *createAtomicUMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
219 static Value *createAtomicExchange(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
220 static Value *createAtomicCompareExchange(Value *ptr, Value *value, Value *compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal);
221
222 // Cast/Conversion Operators
223 static Value *createTrunc(Value *V, Type *destType);
224 static Value *createZExt(Value *V, Type *destType);
225 static Value *createSExt(Value *V, Type *destType);
226 static Value *createFPToSI(Value *V, Type *destType);
227 static Value *createSIToFP(Value *V, Type *destType);
228 static Value *createFPTrunc(Value *V, Type *destType);
229 static Value *createFPExt(Value *V, Type *destType);
230 static Value *createBitCast(Value *V, Type *destType);
231
232 // Compare instructions
233 static Value *createPtrEQ(Value *lhs, Value *rhs);
234 static Value *createICmpEQ(Value *lhs, Value *rhs);
235 static Value *createICmpNE(Value *lhs, Value *rhs);
236 static Value *createICmpUGT(Value *lhs, Value *rhs);
237 static Value *createICmpUGE(Value *lhs, Value *rhs);
238 static Value *createICmpULT(Value *lhs, Value *rhs);
239 static Value *createICmpULE(Value *lhs, Value *rhs);
240 static Value *createICmpSGT(Value *lhs, Value *rhs);
241 static Value *createICmpSGE(Value *lhs, Value *rhs);
242 static Value *createICmpSLT(Value *lhs, Value *rhs);
243 static Value *createICmpSLE(Value *lhs, Value *rhs);
244 static Value *createFCmpOEQ(Value *lhs, Value *rhs);
245 static Value *createFCmpOGT(Value *lhs, Value *rhs);
246 static Value *createFCmpOGE(Value *lhs, Value *rhs);
247 static Value *createFCmpOLT(Value *lhs, Value *rhs);
248 static Value *createFCmpOLE(Value *lhs, Value *rhs);
249 static Value *createFCmpONE(Value *lhs, Value *rhs);
250 static Value *createFCmpORD(Value *lhs, Value *rhs);
251 static Value *createFCmpUNO(Value *lhs, Value *rhs);
252 static Value *createFCmpUEQ(Value *lhs, Value *rhs);
253 static Value *createFCmpUGT(Value *lhs, Value *rhs);
254 static Value *createFCmpUGE(Value *lhs, Value *rhs);
255 static Value *createFCmpULT(Value *lhs, Value *rhs);
256 static Value *createFCmpULE(Value *lhs, Value *rhs);
257 static Value *createFCmpUNE(Value *lhs, Value *rhs);
258
259 // Vector instructions
260 static Value *createExtractElement(Value *vector, Type *type, int index);
261 static Value *createInsertElement(Value *vector, Value *element, int index);
262 static Value *createShuffleVector(Value *V1, Value *V2, const int *select);
263
264 // Other instructions
265 static Value *createSelect(Value *C, Value *ifTrue, Value *ifFalse);
266 static SwitchCases *createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases);
267 static void addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch);
268 static void createUnreachable();
269
270 // Constant values
271 static Value *createNullValue(Type *type);
272 static Value *createConstantLong(int64_t i);
273 static Value *createConstantInt(int i);
274 static Value *createConstantInt(unsigned int i);
275 static Value *createConstantBool(bool b);
276 static Value *createConstantByte(signed char i);
277 static Value *createConstantByte(unsigned char i);
278 static Value *createConstantShort(short i);
279 static Value *createConstantShort(unsigned short i);
280 static Value *createConstantFloat(float x);
281 static Value *createNullPointer(Type *type);
282 static Value *createConstantVector(const int64_t *constants, Type *type);
283 static Value *createConstantVector(const double *constants, Type *type);
284
285 static Type *getPointerType(Type *elementType);
286 };
287}
288
289#endif // rr_Nucleus_hpp
290