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 class LValue { 58 public: LValue(ByteCodeGenerator & generator)59 LValue(ByteCodeGenerator& generator) 60 : fGenerator(generator) {} 61 ~LValue()62 virtual ~LValue() {} 63 64 /** 65 * Stack before call: ... lvalue 66 * Stack after call: ... lvalue load 67 */ 68 virtual void load() = 0; 69 70 /** 71 * Stack before call: ... lvalue value 72 * Stack after call: ... 73 */ 74 virtual void store(bool discard) = 0; 75 76 protected: 77 ByteCodeGenerator& fGenerator; 78 }; 79 80 ByteCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, 81 ByteCode* output); 82 83 bool generateCode() override; 84 85 void write8(uint8_t b); 86 87 void write16(uint16_t b); 88 89 void write32(uint32_t b); 90 91 void write(ByteCodeInstruction inst, int count = kUnusedStackCount); 92 93 /** 94 * Based on 'type', writes the s (signed), u (unsigned), or f (float) instruction. 95 */ 96 void writeTypedInstruction(const Type& type, ByteCodeInstruction s, ByteCodeInstruction u, 97 ByteCodeInstruction f, int count); 98 99 static int SlotCount(const Type& type); 100 101 private: 102 static constexpr int kUnusedStackCount = INT32_MAX; 103 static int StackUsage(ByteCodeInstruction, int count); 104 105 // reserves 16 bits in the output code, to be filled in later with an address once we determine 106 // it 107 class DeferredLocation { 108 public: DeferredLocation(ByteCodeGenerator * generator)109 DeferredLocation(ByteCodeGenerator* generator) 110 : fGenerator(*generator) 111 , fOffset(generator->fCode->size()) { 112 generator->write16(0); 113 } 114 115 #ifdef SK_DEBUG ~DeferredLocation()116 ~DeferredLocation() { 117 SkASSERT(fSet); 118 } 119 #endif 120 set()121 void set() { 122 int target = fGenerator.fCode->size(); 123 SkASSERT(target <= 65535); 124 (*fGenerator.fCode)[fOffset] = target; 125 (*fGenerator.fCode)[fOffset + 1] = target >> 8; 126 #ifdef SK_DEBUG 127 fSet = true; 128 #endif 129 } 130 131 private: 132 ByteCodeGenerator& fGenerator; 133 size_t fOffset; 134 #ifdef SK_DEBUG 135 bool fSet = false; 136 #endif 137 }; 138 139 // Intrinsics which do not simply map to a single opcode 140 enum class SpecialIntrinsic { 141 kDot, 142 }; 143 144 struct Intrinsic { IntrinsicIntrinsic145 Intrinsic(ByteCodeInstruction instruction) 146 : fIsSpecial(false) 147 , fValue(instruction) {} 148 IntrinsicIntrinsic149 Intrinsic(SpecialIntrinsic special) 150 : fIsSpecial(true) 151 , fValue(special) {} 152 153 bool fIsSpecial; 154 155 union Value { Value(ByteCodeInstruction instruction)156 Value(ByteCodeInstruction instruction) 157 : fInstruction(instruction) {} 158 Value(SpecialIntrinsic special)159 Value(SpecialIntrinsic special) 160 : fSpecial(special) {} 161 162 ByteCodeInstruction fInstruction; 163 SpecialIntrinsic fSpecial; 164 } fValue; 165 }; 166 167 /** 168 * Returns the local slot into which var should be stored, allocating a new slot if it has not 169 * already been assigned one. Compound variables (e.g. vectors) will consume more than one local 170 * slot, with the getLocation return value indicating where the first element should be stored. 171 */ 172 int getLocation(const Variable& var); 173 174 /** 175 * As above, but computes the (possibly dynamic) address of an expression involving indexing & 176 * field access. If the address is known, it's returned. If not, -1 is returned, and the 177 * location will be left on the top of the stack. 178 */ 179 int getLocation(const Expression& expr, Variable::Storage* storage); 180 181 std::unique_ptr<ByteCodeFunction> writeFunction(const FunctionDefinition& f); 182 183 void writeVarDeclarations(const VarDeclarations& decl); 184 185 void writeVariableExpression(const Expression& expr); 186 187 void writeExpression(const Expression& expr, bool discard = false); 188 189 /** 190 * Pushes whatever values are required by the lvalue onto the stack, and returns an LValue 191 * permitting loads and stores to it. 192 */ 193 std::unique_ptr<LValue> getLValue(const Expression& expr); 194 195 void writeIntrinsicCall(const FunctionCall& c); 196 197 void writeFunctionCall(const FunctionCall& c); 198 199 void writeConstructor(const Constructor& c); 200 201 void writeExternalFunctionCall(const ExternalFunctionCall& c); 202 203 void writeExternalValue(const ExternalValueReference& r); 204 205 void writeSwizzle(const Swizzle& swizzle); 206 207 bool writeBinaryExpression(const BinaryExpression& b, bool discard); 208 209 void writeTernaryExpression(const TernaryExpression& t); 210 211 void writeNullLiteral(const NullLiteral& n); 212 213 bool writePrefixExpression(const PrefixExpression& p, bool discard); 214 215 bool writePostfixExpression(const PostfixExpression& p, bool discard); 216 217 void writeBoolLiteral(const BoolLiteral& b); 218 219 void writeIntLiteral(const IntLiteral& i); 220 221 void writeFloatLiteral(const FloatLiteral& f); 222 223 void writeStatement(const Statement& s); 224 225 void writeBlock(const Block& b); 226 227 void writeBreakStatement(const BreakStatement& b); 228 229 void writeContinueStatement(const ContinueStatement& c); 230 231 void writeIfStatement(const IfStatement& stmt); 232 233 void writeForStatement(const ForStatement& f); 234 235 void writeWhileStatement(const WhileStatement& w); 236 237 void writeDoStatement(const DoStatement& d); 238 239 void writeSwitchStatement(const SwitchStatement& s); 240 241 void writeReturnStatement(const ReturnStatement& r); 242 243 // updates the current set of breaks to branch to the current location 244 void setBreakTargets(); 245 246 // updates the current set of continues to branch to the current location 247 void setContinueTargets(); 248 enterLoop()249 void enterLoop() { 250 fLoopCount++; 251 fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount); 252 } 253 exitLoop()254 void exitLoop() { 255 SkASSERT(fLoopCount > 0); 256 fLoopCount--; 257 } 258 enterCondition()259 void enterCondition() { 260 fConditionCount++; 261 fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount); 262 } 263 exitCondition()264 void exitCondition() { 265 SkASSERT(fConditionCount > 0); 266 fConditionCount--; 267 } 268 269 const Context& fContext; 270 271 ByteCode* fOutput; 272 273 const FunctionDefinition* fFunction; 274 275 std::vector<uint8_t>* fCode; 276 277 std::vector<const Variable*> fLocals; 278 279 std::stack<std::vector<DeferredLocation>> fContinueTargets; 280 281 std::stack<std::vector<DeferredLocation>> fBreakTargets; 282 283 std::vector<const FunctionDefinition*> fFunctions; 284 285 int fParameterCount; 286 int fStackCount; 287 int fMaxStackCount; 288 289 int fLoopCount; 290 int fMaxLoopCount; 291 int fConditionCount; 292 int fMaxConditionCount; 293 294 const std::unordered_map<String, Intrinsic> fIntrinsics; 295 296 friend class DeferredLocation; 297 friend class ByteCodeExpressionLValue; 298 friend class ByteCodeSwizzleLValue; 299 300 typedef CodeGenerator INHERITED; 301 }; 302 303 } 304 305 #endif 306