1 /*
2  * Copyright 2019 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SKSL_BYTECODE
9 #define SKSL_BYTECODE
10 
11 #include "include/private/SkOnce.h"
12 #include "include/private/SkVx.h"
13 #include "src/sksl/SkSLString.h"
14 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
15 
16 #include <memory>
17 #include <vector>
18 
19 namespace SkSL {
20 
21 class ByteCode;
22 class ExternalValue;
23 
24 class ByteCodeFunction {
25 public:
26     // all counts are of 32-bit values, so a float4 counts as 4 parameter or return slots
27     struct Parameter {
28         int fSlotCount;
29         bool fIsOutParameter;
30     };
31 
32     /**
33      * Note that this is the actual number of parameters, not the number of parameter slots.
34      */
getParameterCount()35     int getParameterCount() const { return fParameters.size(); }
36 
getParameter(int idx)37     Parameter getParameter(int idx) const { return fParameters[idx]; }
38 
getParameterSlotCount()39     int getParameterSlotCount() const { return fParameterSlotCount; }
40 
getReturnSlotCount()41     int getReturnSlotCount() const { return fReturnSlotCount; }
42 
disassemble()43     void disassemble() const { }
44 
45 private:
ByteCodeFunction(const FunctionDeclaration * declaration)46     ByteCodeFunction(const FunctionDeclaration* declaration)
47         : fName(declaration->fName) {}
48 
49     String fName;
50 
51     std::vector<Parameter> fParameters;
52 
53     int fParameterSlotCount;
54 
55     int fReturnSlotCount;
56 
57     int fStackSlotCount;
58 
59     std::vector<uint8_t> fCode;
60 
61     friend class ByteCode;
62     friend class ByteCodeGenerator;
63     template<int width>
64     friend class Interpreter;
65 };
66 
67 enum class TypeCategory {
68     kBool,
69     kSigned,
70     kUnsigned,
71     kFloat,
72 };
73 
74 class SK_API ByteCode {
75 public:
76     ByteCode() = default;
77     ByteCode(ByteCode&&) = default;
78     ByteCode& operator =(ByteCode&&) = default;
79 
80     template<int width>
81     union Vector {
82         skvx::Vec<width, float> fFloat;
83         skvx::Vec<width, int32_t> fInt;
84         skvx::Vec<width, uint32_t> fUInt;
85 
86         Vector() = default;
87 
Vector(skvx::Vec<width,float> f)88         Vector(skvx::Vec<width, float> f)
89             : fFloat(f) {}
90 
Vector(skvx::Vec<width,int32_t> i)91         Vector(skvx::Vec<width, int32_t> i)
92             : fInt(i) {}
93 
Vector(skvx::Vec<width,uint32_t> u)94         Vector(skvx::Vec<width, uint32_t> u)
95             : fUInt(u) {}
96     };
97 
98 // All V(I) instructions have a second (vector) instruction, that is encoded with a uint8_t count
99 // immediately following the instruction (and before any other arguments).
100 #define V(Inst) Inst, Inst ## N
101 
102     enum class Instruction : uint8_t {
103         // no parameters
104         kNop,
105         // no parameters
106         kAbort,
107         // Register target, Register src1, Register src2
108         V(kAddF),
109         // Register target, Register src1, Register src2
110         V(kAddI),
111         // Register target, Register src1, Register src2
112         kAnd,
113         // Register index, int arrayLength
114         kBoundsCheck,
115         // Pointer target
116         kBranch,
117         // Pointer target
118         kBranchIfAllFalse,
119         // no parameters
120         kBreak,
121         // Register target, uint8_t functionIndex, Register parameters
122         kCall,
123         // Register target, uint8_t externalValueIndex, uint8_t targetSize, Register arguments,
124         // uint8_t argumentSize
125         kCallExternal,
126         // Register target, Register src1, Register src2
127         kCompareEQF,
128         // Register target, Register src1, Register src2
129         kCompareEQI,
130         // Register target, Register src1, Register src2
131         kCompareNEQF,
132         // Register target, Register src1, Register src2
133         kCompareNEQI,
134         // Register target, Register src1, Register src2
135         kCompareGTF,
136         // Register target, Register src1, Register src2
137         kCompareGTS,
138         // Register target, Register src1, Register src2
139         kCompareGTU,
140         // Register target, Register src1, Register src2
141         kCompareGTEQF,
142         // Register target, Register src1, Register src2
143         kCompareGTEQS,
144         // Register target, Register src1, Register src2
145         kCompareGTEQU,
146         // Register target, Register src1, Register src2
147         kCompareLTF,
148         // Register target, Register src1, Register src2
149         kCompareLTS,
150         // Register target, Register src1, Register src2
151         kCompareLTU,
152         // Register target, Register src1, Register src2
153         kCompareLTEQF,
154         // Register target, Register src1, Register src2
155         kCompareLTEQS,
156         // Register target, Register src1, Register src2
157         kCompareLTEQU,
158         // no parameters
159         kContinue,
160         // Register target, Register src
161         kCopy,
162         // Register target, Register src,
163         kCos,
164         // Register target, Register src1, Register src2
165         V(kDivideF),
166         // Register target, Register src1, Register src2
167         V(kDivideS),
168         // Register target, Register src1, Register src2
169         V(kDivideU),
170         // Register target, Register src
171         kFloatToSigned,
172         // Register target, Register src
173         kFloatToUnsigned,
174         // Load a constant into a register
175         // Register target, Immediate value
176         kImmediate,
177         // Register target, Register src
178         kInverse2x2,
179         // Register target, Register src
180         kInverse3x3,
181         // Register target, Register src
182         kInverse4x4,
183         // Load the memory cell pointed to by srcPtr into a register
184         // Register target, Register srcPtr
185         V(kLoad),
186         // Load the memory cell pointed to by src into a register
187         // Register target, Pointer src
188         V(kLoadDirect),
189         // Load the parameter slot pointed to by srcPtr into a register
190         // Register target, Register srcPtr
191         V(kLoadParameter),
192         // Load the parameter slot pointed to by src into a register
193         // Register target, Pointer src
194         V(kLoadParameterDirect),
195         // Load the stack cell pointed to by srcPtr + sp into a register
196         // Register target, Register srcPtr
197         V(kLoadStack),
198         // Load the stack cell pointed to by src + sp into a register
199         // Register target, Pointer src
200         V(kLoadStackDirect),
201         // Pushes a new loop onto the loop and continue stacks
202         // no parameters
203         kLoopBegin,
204         // Pops the loop and continue stacks
205         // no parameters
206         kLoopEnd,
207         // Register mask
208         kLoopMask,
209         // no parameters
210         kLoopNext,
211         // no parameters
212         kMaskNegate,
213         // no parameters
214         kMaskPop,
215         // Register mask
216         kMaskPush,
217         // Register target, Register left, Register right, uint8_t leftColsAndRightRows,
218         // uint8_t leftRows, uint8_t rightCols
219         kMatrixMultiply,
220         // Register target, Register src, uint8_t srcColumns, uint8_t srcRows, uint8_t dstColumns,
221         // uint8_t dstRows
222         kMatrixToMatrix,
223         // Register target, Register src1, Register src2
224         V(kMultiplyF),
225         // Register target, Register src1, Register src2
226         V(kMultiplyI),
227         // Register target, Register src
228         kNegateF,
229         // Register target, Register src
230         kNegateS,
231         // Register target, Register src
232         kNot,
233         // Register target, Register src1, Register src2
234         kOr,
235         // Register src
236         kPrint,
237         // Register target, uint8_t count, uint8_t index
238         kReadExternal,
239         // Register target, Register src1, Register src2
240         V(kRemainderF),
241         // Register target, Register src1, Register src2
242         V(kRemainderS),
243         // Register target, Register src1, Register src2
244         V(kRemainderU),
245         // no parameters
246         kReturn,
247         // Register value
248         kReturnValue,
249         // Register target, Register src, uint8_t columns, uint8_t rows
250         kScalarToMatrix,
251         // Register target, Register test, Register ifTrue, Register ifFalse
252         kSelect,
253         // Register target, Register src, uint8_t count
254         kShiftLeft,
255         // Register target, Register src, uint8_t count
256         kShiftRightS,
257         // Register target, Register src, uint8_t count
258         kShiftRightU,
259         // Register target, Register src
260         kSignedToFloat,
261         // Register target, Register src,
262         kSin,
263         // Duplicates the src to <count> targets
264         // uint8_t count, Register target, Register src
265         kSplat,
266         // Register target, Register src,
267         kSqrt,
268         // Store to the memory cell pointed to by dstPtr
269         // Register dstPtr, Register src
270         V(kStore),
271         // Store to the memory cell pointed to by dst
272         // Pointer dst, Register src
273         V(kStoreDirect),
274         // Store to the parameter slot pointed to by dstPtr
275         // Register dstPtr, Register src
276         V(kStoreParameter),
277         // Store to the parameter slot pointed to by dst
278         // Pointer dst, Register src
279         V(kStoreParameterDirect),
280         // Stores a register into the stack cell pointed to by dst + sp
281         // Register dst, Register src
282         V(kStoreStack),
283         // Stores a register into the stack cell pointed to by dstPtr + sp
284         // Pointer dst, Register src
285         V(kStoreStackDirect),
286         // Register target, Register src1, Register src2
287         V(kSubtractF),
288         // Register target, Register src1, Register src2
289         V(kSubtractI),
290         // Register target, Register src,
291         kTan,
292         // Register target, Register src,
293         kUnsignedToFloat,
294         // uint8_t index, uint8_t count, Register src
295         kWriteExternal,
296         // Register target, Register src1, Register src2
297         kXor,
298     };
299 
300 #undef V
301 
302     // Compound values like vectors span multiple Registers or Pointer addresses. We always refer to
303     // them by the address of their first slot, so for instance if you add two float4's together,
304     // the resulting Register contains the first channel of the result, with the other three
305     // channels following in the next three Registers.
306 
307     struct Register {
308         uint16_t fIndex;
309 
310         Register operator+(uint16_t offset) const {
311             return Register{(uint16_t) (fIndex + offset)};
312         }
313     };
314 
315     struct Pointer {
316         uint16_t fAddress;
317 
318         Pointer operator+(uint16_t offset) const {
319             return Pointer{(uint16_t) (fAddress + offset)};
320         }
321     };
322 
323     union Immediate {
324         float fFloat;
325         int32_t fInt;
326         uint32_t fUInt;
327 
Immediate()328         Immediate() {}
329 
Immediate(float f)330         Immediate(float f)
331             : fFloat(f) {}
332 
Immediate(int32_t i)333         Immediate(int32_t i)
334             : fInt(i) {}
335 
Immediate(uint32_t u)336         Immediate(uint32_t u)
337             : fUInt(u) {}
338     };
339 
340     static constexpr int kPointerMax = 65535;
341     static constexpr int kRegisterMax = 65535;
342 
getFunction(const char * name)343     const ByteCodeFunction* getFunction(const char* name) const {
344         for (const auto& f : fFunctions) {
345             if (f->fName == name) {
346                 return f.get();
347             }
348         }
349         return nullptr;
350     }
351 
getGlobalSlotCount()352     int getGlobalSlotCount() const {
353         return fGlobalSlotCount;
354     }
355 
356     struct Uniform {
357         SkSL::String fName;
358         TypeCategory fType;
359         int fColumns;
360         int fRows;
361         int fSlot;
362     };
363 
getUniformSlotCount()364     int getUniformSlotCount() const { return fUniformSlotCount; }
getUniformCount()365     int getUniformCount() const { return fUniforms.size(); }
getUniformLocation(const char * name)366     int getUniformLocation(const char* name) const {
367         for (int i = 0; i < (int)fUniforms.size(); ++i) {
368             if (fUniforms[i].fName == name) {
369                 return fUniforms[i].fSlot;
370             }
371         }
372         return -1;
373     }
getUniform(int i)374     const Uniform& getUniform(int i) const { return fUniforms[i]; }
375 
376 private:
377     ByteCode(const ByteCode&) = delete;
378     ByteCode& operator=(const ByteCode&) = delete;
379 
380     std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions;
381     std::vector<ExternalValue*> fExternalValues;
382 
383     int fGlobalSlotCount;
384 
385     int fUniformSlotCount = 0;
386     std::vector<Uniform> fUniforms;
387 
388     friend class ByteCodeGenerator;
389     template<int width>
390     friend class Interpreter;
391 };
392 
393 } // namespace
394 
395 #endif
396