blob: 4c08ddd7bed257f3c3194fe323ed0c3001bdb011 [file] [log] [blame]
Nicolas Capens0bac2852016-05-07 06:09:58 -04001// 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
Nicolas Capens48461502018-08-06 14:20:45 -040015#ifndef rr_Nucleus_hpp
16#define rr_Nucleus_hpp
Nicolas Capens0bac2852016-05-07 06:09:58 -040017
Ben Clayton6897e9b2019-07-16 17:27:27 +010018#include <atomic>
Nicolas Capens01a97962017-07-28 17:30:51 -040019#include <cassert>
Nicolas Capens3bbc5e12016-09-27 10:49:52 -040020#include <cstdarg>
21#include <cstdint>
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -050022#include <functional>
Ben Clayton6897e9b2019-07-16 17:27:27 +010023#include <memory>
Antonio Maiorano62427e02020-02-13 09:18:05 -050024#include <string>
Nicolas Capens0bac2852016-05-07 06:09:58 -040025#include <vector>
Nicolas Capens0bac2852016-05-07 06:09:58 -040026
Ben Clayton68cfc782019-06-29 12:31:08 +010027#ifdef None
Ben Clayton713b8d32019-12-17 20:37:56 +000028# undef None // TODO(b/127920555)
Ben Clayton68cfc782019-06-29 12:31:08 +010029#endif
30
Nicolas Capensb3a473e2019-12-09 11:41:03 -050031static_assert(sizeof(short) == 2, "Reactor's 'Short' type is 16-bit, and requires the C++ 'short' to match that.");
32static_assert(sizeof(int) == 4, "Reactor's 'Int' type is 32-bit, and requires the C++ 'int' to match that.");
33
Nicolas Capens157ba262019-12-10 17:49:14 -050034namespace rr {
35
36class Type;
37class Value;
38class SwitchCases;
39class BasicBlock;
40class Routine;
41
42// Optimization holds the optimization settings for code generation.
43class Optimization
Nicolas Capens0bac2852016-05-07 06:09:58 -040044{
Nicolas Capens157ba262019-12-10 17:49:14 -050045public:
46 enum class Level
Nicolas Capens0bac2852016-05-07 06:09:58 -040047 {
Nicolas Capens157ba262019-12-10 17:49:14 -050048 None,
49 Less,
50 Default,
51 Aggressive,
52 };
53
54 enum class Pass
55 {
56 Disabled,
57 InstructionCombining,
58 CFGSimplification,
59 LICM,
60 AggressiveDCE,
61 GVN,
62 Reassociate,
63 DeadStoreElimination,
64 SCCP,
65 ScalarReplAggregates,
66 EarlyCSEPass,
67
68 Count,
69 };
70
71 using Passes = std::vector<Pass>;
72
Ben Clayton713b8d32019-12-17 20:37:56 +000073 Optimization(Level level = Level::Default, const Passes &passes = {})
74 : level(level)
75 , passes(passes)
Nicolas Capens157ba262019-12-10 17:49:14 -050076 {
Ben Clayton713b8d32019-12-17 20:37:56 +000077#if defined(REACTOR_DEFAULT_OPT_LEVEL)
Ben Clayton55bc37a2019-07-04 12:17:12 +010078 {
Nicolas Capens157ba262019-12-10 17:49:14 -050079 this->level = Level::REACTOR_DEFAULT_OPT_LEVEL;
Antonio Maiorano062dc182019-12-09 11:52:31 -050080 }
Ben Clayton713b8d32019-12-17 20:37:56 +000081#endif
Nicolas Capens157ba262019-12-10 17:49:14 -050082 }
Ben Clayton55bc37a2019-07-04 12:17:12 +010083
Nicolas Capens157ba262019-12-10 17:49:14 -050084 Level getLevel() const { return level; }
Ben Clayton713b8d32019-12-17 20:37:56 +000085 const Passes &getPasses() const { return passes; }
Ben Clayton55bc37a2019-07-04 12:17:12 +010086
Nicolas Capens157ba262019-12-10 17:49:14 -050087private:
88 Level level = Level::Default;
89 Passes passes;
90};
Nicolas Capens0bac2852016-05-07 06:09:58 -040091
Nicolas Capens157ba262019-12-10 17:49:14 -050092// Config holds the Reactor configuration settings.
93class Config
94{
95public:
96 // Edit holds a number of modifications to a config, that can be applied
97 // on an existing Config to produce a new Config with the specified
98 // changes.
99 class Edit
Ben Clayton68cfc782019-06-29 12:31:08 +0100100 {
Ben Clayton55bc37a2019-07-04 12:17:12 +0100101 public:
Nicolas Capens157ba262019-12-10 17:49:14 -0500102 static const Edit None;
Ben Clayton55bc37a2019-07-04 12:17:12 +0100103
Ben Clayton713b8d32019-12-17 20:37:56 +0000104 Edit &set(Optimization::Level level)
105 {
106 optLevel = level;
107 optLevelChanged = true;
108 return *this;
109 }
110 Edit &add(Optimization::Pass pass)
111 {
112 optPassEdits.push_back({ ListEdit::Add, pass });
113 return *this;
114 }
115 Edit &remove(Optimization::Pass pass)
116 {
117 optPassEdits.push_back({ ListEdit::Remove, pass });
118 return *this;
119 }
120 Edit &clearOptimizationPasses()
121 {
122 optPassEdits.push_back({ ListEdit::Clear, Optimization::Pass::Disabled });
123 return *this;
124 }
Ben Clayton55bc37a2019-07-04 12:17:12 +0100125
Nicolas Capens157ba262019-12-10 17:49:14 -0500126 Config apply(const Config &cfg) const;
Ben Clayton55bc37a2019-07-04 12:17:12 +0100127
128 private:
Ben Clayton713b8d32019-12-17 20:37:56 +0000129 enum class ListEdit
130 {
131 Add,
132 Remove,
133 Clear
134 };
Nicolas Capens157ba262019-12-10 17:49:14 -0500135 using OptPassesEdit = std::pair<ListEdit, Optimization::Pass>;
136
Ben Clayton713b8d32019-12-17 20:37:56 +0000137 template<typename T>
138 void apply(const std::vector<std::pair<ListEdit, T>> &edits, std::vector<T> &list) const;
Nicolas Capens157ba262019-12-10 17:49:14 -0500139
140 Optimization::Level optLevel;
141 bool optLevelChanged = false;
142 std::vector<OptPassesEdit> optPassEdits;
Ben Clayton68cfc782019-06-29 12:31:08 +0100143 };
144
Nicolas Capens157ba262019-12-10 17:49:14 -0500145 Config() = default;
Ben Clayton713b8d32019-12-17 20:37:56 +0000146 Config(const Optimization &optimization)
147 : optimization(optimization)
148 {}
Nicolas Capens157ba262019-12-10 17:49:14 -0500149
Ben Clayton713b8d32019-12-17 20:37:56 +0000150 const Optimization &getOptimization() const { return optimization; }
Nicolas Capens157ba262019-12-10 17:49:14 -0500151
152private:
153 Optimization optimization;
154};
155
156class Nucleus
157{
158public:
159 Nucleus();
160
161 virtual ~Nucleus();
162
163 // Default configuration to use when no other configuration is specified.
164 // The new configuration will be applied to subsequent reactor calls.
165 static void setDefaultConfig(const Config &cfg);
166 static void adjustDefaultConfig(const Config::Edit &cfgEdit);
167 static Config getDefaultConfig();
168
169 std::shared_ptr<Routine> acquireRoutine(const char *name, const Config::Edit &cfgEdit = Config::Edit::None);
170
171 static Value *allocateStackVariable(Type *type, int arraySize = 0);
172 static BasicBlock *createBasicBlock();
173 static BasicBlock *getInsertBlock();
174 static void setInsertBlock(BasicBlock *basicBlock);
175
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500176 static void createFunction(Type *returnType, const std::vector<Type *> &paramTypes);
Nicolas Capens157ba262019-12-10 17:49:14 -0500177 static Value *getArgument(unsigned int index);
178
179 // Coroutines
Ben Clayton713b8d32019-12-17 20:37:56 +0000180 using CoroutineHandle = void *;
Nicolas Capens157ba262019-12-10 17:49:14 -0500181
Ben Clayton713b8d32019-12-17 20:37:56 +0000182 template<typename... ARGS>
Nicolas Capens157ba262019-12-10 17:49:14 -0500183 using CoroutineBegin = CoroutineHandle(ARGS...);
Ben Clayton713b8d32019-12-17 20:37:56 +0000184 using CoroutineAwait = bool(CoroutineHandle, void *yieldValue);
Nicolas Capens157ba262019-12-10 17:49:14 -0500185 using CoroutineDestroy = void(CoroutineHandle);
186
187 enum CoroutineEntries
Nicolas Capens0bac2852016-05-07 06:09:58 -0400188 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500189 CoroutineEntryBegin = 0,
190 CoroutineEntryAwait,
191 CoroutineEntryDestroy,
192 CoroutineEntryCount
Nicolas Capens0bac2852016-05-07 06:09:58 -0400193 };
Nicolas Capens157ba262019-12-10 17:49:14 -0500194
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500195 // Begins the generation of the three coroutine functions: CoroutineBegin, CoroutineAwait, and CoroutineDestroy,
196 // which will be returned by Routine::getEntry() with arg CoroutineEntryBegin, CoroutineEntryAwait, and CoroutineEntryDestroy
197 // respectively. Called by Coroutine constructor.
198 // Params are used to generate the params to CoroutineBegin, while ReturnType is used as the YieldType for the coroutine,
199 // returned via CoroutineAwait..
200 static void createCoroutine(Type *returnType, const std::vector<Type *> &params);
201 // Generates code to store the passed in value, and to suspend execution of the coroutine, such that the next call to
202 // CoroutineAwait can set the output yieldValue and resume execution of the coroutine.
203 static void yield(Value *val);
204 // Called to finalize coroutine creation. After this call, Routine::getEntry can be called to retrieve the entry point to any
205 // of the three coroutine functions. Called by Coroutine::finalize.
Nicolas Capens157ba262019-12-10 17:49:14 -0500206 std::shared_ptr<Routine> acquireCoroutine(const char *name, const Config::Edit &cfg = Config::Edit::None);
Antonio Maiorano5ba2a5b2020-01-17 15:29:37 -0500207 // Called by Coroutine::operator() to execute CoroutineEntryBegin wrapped up in func. This is needed in case
208 // the call must be run on a separate thread of execution (e.g. on a fiber).
209 static CoroutineHandle invokeCoroutineBegin(Routine &routine, std::function<CoroutineHandle()> func);
Nicolas Capens157ba262019-12-10 17:49:14 -0500210
211 // Terminators
212 static void createRetVoid();
213 static void createRet(Value *V);
214 static void createBr(BasicBlock *dest);
215 static void createCondBr(Value *cond, BasicBlock *ifTrue, BasicBlock *ifFalse);
216
217 // Binary operators
218 static Value *createAdd(Value *lhs, Value *rhs);
219 static Value *createSub(Value *lhs, Value *rhs);
220 static Value *createMul(Value *lhs, Value *rhs);
221 static Value *createUDiv(Value *lhs, Value *rhs);
222 static Value *createSDiv(Value *lhs, Value *rhs);
223 static Value *createFAdd(Value *lhs, Value *rhs);
224 static Value *createFSub(Value *lhs, Value *rhs);
225 static Value *createFMul(Value *lhs, Value *rhs);
226 static Value *createFDiv(Value *lhs, Value *rhs);
227 static Value *createURem(Value *lhs, Value *rhs);
228 static Value *createSRem(Value *lhs, Value *rhs);
229 static Value *createFRem(Value *lhs, Value *rhs);
230 static Value *createShl(Value *lhs, Value *rhs);
231 static Value *createLShr(Value *lhs, Value *rhs);
232 static Value *createAShr(Value *lhs, Value *rhs);
233 static Value *createAnd(Value *lhs, Value *rhs);
234 static Value *createOr(Value *lhs, Value *rhs);
235 static Value *createXor(Value *lhs, Value *rhs);
236
237 // Unary operators
238 static Value *createNeg(Value *V);
239 static Value *createFNeg(Value *V);
240 static Value *createNot(Value *V);
241
242 // Memory instructions
Ben Clayton713b8d32019-12-17 20:37:56 +0000243 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);
Nicolas Capens157ba262019-12-10 17:49:14 -0500244 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);
245 static Value *createGEP(Value *ptr, Type *type, Value *index, bool unsignedIndex);
246
247 // Masked Load / Store instructions
248 static Value *createMaskedLoad(Value *base, Type *elementType, Value *mask, unsigned int alignment, bool zeroMaskedLanes);
249 static void createMaskedStore(Value *base, Value *value, Value *mask, unsigned int alignment);
250
251 // Barrier instructions
252 static void createFence(std::memory_order memoryOrder);
253
254 // Atomic instructions
255 static Value *createAtomicAdd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
256 static Value *createAtomicSub(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
257 static Value *createAtomicAnd(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
258 static Value *createAtomicOr(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
259 static Value *createAtomicXor(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
260 static Value *createAtomicMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
261 static Value *createAtomicMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
262 static Value *createAtomicUMin(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
263 static Value *createAtomicUMax(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
264 static Value *createAtomicExchange(Value *ptr, Value *value, std::memory_order memoryOrder = std::memory_order_relaxed);
265 static Value *createAtomicCompareExchange(Value *ptr, Value *value, Value *compare, std::memory_order memoryOrderEqual, std::memory_order memoryOrderUnequal);
266
267 // Cast/Conversion Operators
268 static Value *createTrunc(Value *V, Type *destType);
269 static Value *createZExt(Value *V, Type *destType);
270 static Value *createSExt(Value *V, Type *destType);
271 static Value *createFPToUI(Value *V, Type *destType);
272 static Value *createFPToSI(Value *V, Type *destType);
273 static Value *createSIToFP(Value *V, Type *destType);
274 static Value *createFPTrunc(Value *V, Type *destType);
275 static Value *createFPExt(Value *V, Type *destType);
276 static Value *createBitCast(Value *V, Type *destType);
277
278 // Compare instructions
279 static Value *createPtrEQ(Value *lhs, Value *rhs);
280 static Value *createICmpEQ(Value *lhs, Value *rhs);
281 static Value *createICmpNE(Value *lhs, Value *rhs);
282 static Value *createICmpUGT(Value *lhs, Value *rhs);
283 static Value *createICmpUGE(Value *lhs, Value *rhs);
284 static Value *createICmpULT(Value *lhs, Value *rhs);
285 static Value *createICmpULE(Value *lhs, Value *rhs);
286 static Value *createICmpSGT(Value *lhs, Value *rhs);
287 static Value *createICmpSGE(Value *lhs, Value *rhs);
288 static Value *createICmpSLT(Value *lhs, Value *rhs);
289 static Value *createICmpSLE(Value *lhs, Value *rhs);
290 static Value *createFCmpOEQ(Value *lhs, Value *rhs);
291 static Value *createFCmpOGT(Value *lhs, Value *rhs);
292 static Value *createFCmpOGE(Value *lhs, Value *rhs);
293 static Value *createFCmpOLT(Value *lhs, Value *rhs);
294 static Value *createFCmpOLE(Value *lhs, Value *rhs);
295 static Value *createFCmpONE(Value *lhs, Value *rhs);
296 static Value *createFCmpORD(Value *lhs, Value *rhs);
297 static Value *createFCmpUNO(Value *lhs, Value *rhs);
298 static Value *createFCmpUEQ(Value *lhs, Value *rhs);
299 static Value *createFCmpUGT(Value *lhs, Value *rhs);
300 static Value *createFCmpUGE(Value *lhs, Value *rhs);
301 static Value *createFCmpULT(Value *lhs, Value *rhs);
302 static Value *createFCmpULE(Value *lhs, Value *rhs);
303 static Value *createFCmpUNE(Value *lhs, Value *rhs);
304
305 // Vector instructions
306 static Value *createExtractElement(Value *vector, Type *type, int index);
307 static Value *createInsertElement(Value *vector, Value *element, int index);
308 static Value *createShuffleVector(Value *V1, Value *V2, const int *select);
309
310 // Other instructions
311 static Value *createSelect(Value *C, Value *ifTrue, Value *ifFalse);
312 static SwitchCases *createSwitch(Value *control, BasicBlock *defaultBranch, unsigned numCases);
313 static void addSwitchCase(SwitchCases *switchCases, int label, BasicBlock *branch);
314 static void createUnreachable();
315
316 // Constant values
317 static Value *createNullValue(Type *type);
318 static Value *createConstantLong(int64_t i);
319 static Value *createConstantInt(int i);
320 static Value *createConstantInt(unsigned int i);
321 static Value *createConstantBool(bool b);
322 static Value *createConstantByte(signed char i);
323 static Value *createConstantByte(unsigned char i);
324 static Value *createConstantShort(short i);
325 static Value *createConstantShort(unsigned short i);
326 static Value *createConstantFloat(float x);
327 static Value *createNullPointer(Type *type);
328 static Value *createConstantVector(const int64_t *constants, Type *type);
329 static Value *createConstantVector(const double *constants, Type *type);
Antonio Maiorano62427e02020-02-13 09:18:05 -0500330 static Value *createConstantString(const char *v);
331 static Value *createConstantString(const std::string &v) { return createConstantString(v.c_str()); }
Nicolas Capens157ba262019-12-10 17:49:14 -0500332
Antonio Maiorano62427e02020-02-13 09:18:05 -0500333 static Type *getType(Value *value);
334 static Type *getContainedType(Type *vectorType);
Nicolas Capens157ba262019-12-10 17:49:14 -0500335 static Type *getPointerType(Type *elementType);
Antonio Maiorano62427e02020-02-13 09:18:05 -0500336 static Type *getPrintfStorageType(Type *valueType);
Nicolas Capens157ba262019-12-10 17:49:14 -0500337};
338
339} // namespace rr
Nicolas Capens0bac2852016-05-07 06:09:58 -0400340
Ben Clayton713b8d32019-12-17 20:37:56 +0000341#endif // rr_Nucleus_hpp