• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_BYTECODEGENERATOR
9 #define SKSL_BYTECODEGENERATOR
10 
11 #include <algorithm>
12 #include <stack>
13 #include <unordered_map>
14 
15 #include "src/sksl/SkSLByteCode.h"
16 #include "src/sksl/SkSLCodeGenerator.h"
17 #include "src/sksl/SkSLMemoryLayout.h"
18 #include "src/sksl/ir/SkSLBinaryExpression.h"
19 #include "src/sksl/ir/SkSLBlock.h"
20 #include "src/sksl/ir/SkSLBoolLiteral.h"
21 #include "src/sksl/ir/SkSLBreakStatement.h"
22 #include "src/sksl/ir/SkSLConstructor.h"
23 #include "src/sksl/ir/SkSLContinueStatement.h"
24 #include "src/sksl/ir/SkSLDoStatement.h"
25 #include "src/sksl/ir/SkSLExpressionStatement.h"
26 #include "src/sksl/ir/SkSLExternalFunctionCall.h"
27 #include "src/sksl/ir/SkSLExternalValueReference.h"
28 #include "src/sksl/ir/SkSLFieldAccess.h"
29 #include "src/sksl/ir/SkSLFloatLiteral.h"
30 #include "src/sksl/ir/SkSLForStatement.h"
31 #include "src/sksl/ir/SkSLFunctionCall.h"
32 #include "src/sksl/ir/SkSLFunctionDeclaration.h"
33 #include "src/sksl/ir/SkSLFunctionDefinition.h"
34 #include "src/sksl/ir/SkSLIfStatement.h"
35 #include "src/sksl/ir/SkSLIndexExpression.h"
36 #include "src/sksl/ir/SkSLIntLiteral.h"
37 #include "src/sksl/ir/SkSLInterfaceBlock.h"
38 #include "src/sksl/ir/SkSLNullLiteral.h"
39 #include "src/sksl/ir/SkSLPostfixExpression.h"
40 #include "src/sksl/ir/SkSLPrefixExpression.h"
41 #include "src/sksl/ir/SkSLProgramElement.h"
42 #include "src/sksl/ir/SkSLReturnStatement.h"
43 #include "src/sksl/ir/SkSLStatement.h"
44 #include "src/sksl/ir/SkSLSwitchStatement.h"
45 #include "src/sksl/ir/SkSLSwizzle.h"
46 #include "src/sksl/ir/SkSLTernaryExpression.h"
47 #include "src/sksl/ir/SkSLVarDeclarations.h"
48 #include "src/sksl/ir/SkSLVarDeclarationsStatement.h"
49 #include "src/sksl/ir/SkSLVariableReference.h"
50 #include "src/sksl/ir/SkSLWhileStatement.h"
51 #include "src/sksl/spirv.h"
52 
53 namespace SkSL {
54 
55 class ByteCodeGenerator : public CodeGenerator {
56 public:
57     ByteCodeGenerator(const Program* program, ErrorReporter* errors, ByteCode* output);
58 
59     bool generateCode() override;
60 
61 private:
62     // Intrinsics which do not simply map to a single opcode
63     enum class SpecialIntrinsic {
64         kDot,
65         kInverse,
66     };
67 
68     struct Intrinsic {
IntrinsicIntrinsic69         Intrinsic(ByteCode::Instruction instruction)
70             : fIsSpecial(false)
71             , fValue(instruction) {}
72 
IntrinsicIntrinsic73         Intrinsic(SpecialIntrinsic special)
74             : fIsSpecial(true)
75             , fValue(special) {}
76 
77         bool fIsSpecial;
78 
79         union Value {
Value(ByteCode::Instruction instruction)80             Value(ByteCode::Instruction instruction)
81                 : fInstruction(instruction) {}
82 
Value(SpecialIntrinsic special)83             Value(SpecialIntrinsic special)
84                 : fSpecial(special) {}
85 
86             ByteCode::Instruction fInstruction;
87             SpecialIntrinsic fSpecial;
88         } fValue;
89     };
90 
91     class LValue {
92     public:
LValue(ByteCodeGenerator & generator)93         LValue(ByteCodeGenerator& generator)
94             : fGenerator(generator) {}
95 
~LValue()96         virtual ~LValue() {}
97 
98         virtual void load(ByteCode::Register result) = 0;
99 
100         virtual void store(ByteCode::Register src) = 0;
101 
102     protected:
103         ByteCodeGenerator& fGenerator;
104     };
105 
106     struct Location {
107         enum {
108             kPointer_Kind,
109             kRegister_Kind
110         } fKind;
111 
112         union {
113             ByteCode::Pointer fPointer;
114             ByteCode::Register fRegister;
115         };
116 
LocationLocation117         Location(ByteCode::Pointer p)
118             : fKind(kPointer_Kind)
119             , fPointer(p) {}
120 
LocationLocation121         Location(ByteCode::Register r)
122             : fKind(kRegister_Kind)
123             , fRegister(r) {}
124 
125         /**
126          * Returns this location offset by 'offset' bytes. For pointers, this is a compile-time
127          * operation, while for registers there will be CPU instructions output to handle the
128          * runtime calculation of the address.
129          */
offsetLocation130         Location offset(ByteCodeGenerator& generator, int offset) {
131             if (!offset) {
132                 return *this;
133             }
134             if (fKind == kPointer_Kind) {
135                 return Location(fPointer + offset);
136             }
137             ByteCode::Register a = generator.next(1);
138             generator.write(ByteCode::Instruction::kImmediate);
139             generator.write(a);
140             generator.write(ByteCode::Immediate{offset});
141             ByteCode::Register result = generator.next(1);
142             generator.write(ByteCode::Instruction::kAddI);
143             generator.write(result);
144             generator.write(fRegister);
145             generator.write(a);
146             return result;
147         }
148 
149         /**
150          * Returns this location offset by the number of bytes stored in the 'offset' register. This
151          * will output the necessary CPU instructions to perform the math and return a new register
152          * location.
153          */
offsetLocation154         Location offset(ByteCodeGenerator& generator, ByteCode::Register offset) {
155             ByteCode::Register current;
156             switch (fKind) {
157                 case kPointer_Kind:
158                     current = generator.next(1);
159                     generator.write(ByteCode::Instruction::kImmediate);
160                     generator.write(current);
161                     generator.write(ByteCode::Immediate{fPointer.fAddress});
162                     break;
163                 case kRegister_Kind:
164                     current = fRegister;
165             }
166             ByteCode::Register result = generator.next(1);
167             generator.write(ByteCode::Instruction::kAddI);
168             generator.write(result);
169             generator.write(current);
170             generator.write(offset);
171             return result;
172         }
173     };
174 
175     // reserves 16 bits in the output code, to be filled in later with an address once we determine
176     // it
177     class DeferredLocation {
178     public:
DeferredLocation(ByteCodeGenerator * generator)179         explicit DeferredLocation(ByteCodeGenerator* generator)
180             : fGenerator(*generator)
181             , fOffset(generator->fCode->size()) {
182             generator->write(ByteCode::Pointer{65535});
183         }
184 
set()185         void set() {
186             SkASSERT(fGenerator.fCode->size() <= ByteCode::kPointerMax);
187             static_assert(sizeof(ByteCode::Pointer) == 2,
188                           "failed assumption that ByteCode::Pointer is uint16_t");
189             void* dst = &(*fGenerator.fCode)[fOffset];
190             // ensure that the placeholder value 65535 hasn't been modified yet
191             SkASSERT(((uint8_t*) dst)[0] == 255 && ((uint8_t*) dst)[1] == 255);
192             ByteCode::Pointer target{(uint16_t) fGenerator.fCode->size()};
193             memcpy(dst, &target, sizeof(target));
194         }
195 
196     private:
197         ByteCodeGenerator& fGenerator;
198         size_t fOffset;
199     };
200 
201     template<typename T>
write(T value)202     void write(T value) {
203         size_t n = fCode->size();
204         fCode->resize(n + sizeof(value));
205         memcpy(fCode->data() + n, &value, sizeof(value));
206     }
207 
208     ByteCode::Register next(int slotCount);
209 
210     void write(ByteCode::Instruction inst, int count);
211 
212     /**
213      * Based on 'type', writes the s (signed), u (unsigned), or f (float) instruction.
214      */
215     void writeTypedInstruction(const Type& type, ByteCode::Instruction s, ByteCode::Instruction u,
216                                ByteCode::Instruction f);
217 
218     ByteCode::Instruction getLoadInstruction(Location location, Variable::Storage storage);
219 
220     ByteCode::Instruction getStoreInstruction(Location location, Variable::Storage storage);
221 
222     static int SlotCount(const Type& type);
223 
224     Location getLocation(const Variable& var);
225 
226     Location getLocation(const Expression& expr);
227 
228     Variable::Storage getStorage(const Expression& expr);
229 
230     std::unique_ptr<LValue> getLValue(const Expression& expr);
231 
232     void writeFunction(const FunctionDefinition& f);
233 
234     // For compound values, the result argument specifies the first component. Subsequent components
235     // will be in subsequent registers.
236 
237     void writeBinaryInstruction(const Type& operandType, ByteCode::Register left,
238                                 ByteCode::Register right, ByteCode::Instruction s,
239                                 ByteCode::Instruction u, ByteCode::Instruction f,
240                                 ByteCode::Register result);
241 
242     void writeVectorBinaryInstruction(const Type& operandType, ByteCode::Register left,
243                                       ByteCode::Register right, ByteCode::Instruction s,
244                                       ByteCode::Instruction u, ByteCode::Instruction f,
245                                       ByteCode::Register result);
246 
247     void writeBinaryExpression(const BinaryExpression& expr, ByteCode::Register result);
248 
249     void writeConstructor(const Constructor& c, ByteCode::Register result);
250 
251     void writeExternalFunctionCall(const ExternalFunctionCall& f, ByteCode::Register result);
252 
253     void writeExternalValue(const ExternalValueReference& e, ByteCode::Register result);
254 
255     void writeIntrinsicCall(const FunctionCall& c, Intrinsic intrinsic, ByteCode::Register result);
256 
257     void writeFunctionCall(const FunctionCall& c, ByteCode::Register result);
258 
259     void incOrDec(Token::Kind op, Expression& operand, bool prefix, ByteCode::Register result);
260 
261     void writePostfixExpression(const PostfixExpression& p, ByteCode::Register result);
262 
263     void writePrefixExpression(const PrefixExpression& p, ByteCode::Register result);
264 
265     void writeSwizzle(const Swizzle& s, ByteCode::Register result);
266 
267     void writeTernaryExpression(const TernaryExpression& t, ByteCode::Register result);
268 
269     void writeVariableExpression(const Expression& e, ByteCode::Register result);
270 
271     void writeExpression(const Expression& expr, ByteCode::Register result);
272 
273     ByteCode::Register writeExpression(const Expression& expr);
274 
275     void writeBlock(const Block& b);
276 
277     void writeDoStatement(const DoStatement& d);
278 
279     void writeForStatement(const ForStatement& f);
280 
281     void writeIfStatement(const IfStatement& i);
282 
283     void writeReturn(const ReturnStatement& r);
284 
285     void writeVarDeclarations(const VarDeclarations& v);
286 
287     void writeWhileStatement(const WhileStatement& w);
288 
289     void writeStatement(const Statement& s);
290 
291     void gatherUniforms(const Type& type, const String& name);
292 
293     ByteCode* fOutput;
294 
295     int fNextRegister = 0;
296 
297     const FunctionDefinition* fFunction;
298 
299     std::vector<const FunctionDefinition*> fFunctions;
300 
301     std::vector<uint8_t>* fCode;
302 
303     std::vector<const Variable*> fLocals;
304 
305     int fParameterCount;
306 
307     int fConditionCount;
308 
309     const std::unordered_map<String, Intrinsic> fIntrinsics;
310 
311     friend class DeferredLocation;
312     friend class ByteCodeExternalValueLValue;
313     friend class ByteCodeSimpleLValue;
314     friend class ByteCodeSwizzleLValue;
315 
316     typedef CodeGenerator INHERITED;
317 };
318 
319 template<>
write(ByteCodeGenerator::Location loc)320 inline void ByteCodeGenerator::write(ByteCodeGenerator::Location loc) {
321     switch (loc.fKind) {
322         case ByteCodeGenerator::Location::kPointer_Kind:
323             this->write(loc.fPointer);
324             break;
325         case ByteCodeGenerator::Location::kRegister_Kind:
326             this->write(loc.fRegister);
327             break;
328     }
329 }
330 
331 }
332 
333 #endif
334