| 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: | 
|---|
| 59 | LValue(ByteCodeGenerator& generator) | 
|---|
| 60 | : fGenerator(generator) {} | 
|---|
| 61 |  | 
|---|
| 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: | 
|---|
| 109 | DeferredLocation(ByteCodeGenerator* generator) | 
|---|
| 110 | : fGenerator(*generator) | 
|---|
| 111 | , fOffset(generator->fCode->size()) { | 
|---|
| 112 | generator->write16(0); | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | #ifdef SK_DEBUG | 
|---|
| 116 | ~DeferredLocation() { | 
|---|
| 117 | SkASSERT(fSet); | 
|---|
| 118 | } | 
|---|
| 119 | #endif | 
|---|
| 120 |  | 
|---|
| 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 | kAll, | 
|---|
| 142 | kAny, | 
|---|
| 143 | kClamp, | 
|---|
| 144 | kDot, | 
|---|
| 145 | kLength, | 
|---|
| 146 | kMax, | 
|---|
| 147 | kMin, | 
|---|
| 148 | kMix, | 
|---|
| 149 | kNormalize, | 
|---|
| 150 | kSample, | 
|---|
| 151 | kSaturate, | 
|---|
| 152 | }; | 
|---|
| 153 |  | 
|---|
| 154 | struct Intrinsic { | 
|---|
| 155 | Intrinsic(SpecialIntrinsic    s) : is_special(true), special(s) {} | 
|---|
| 156 | Intrinsic(ByteCodeInstruction i) : Intrinsic(i, i, i) {} | 
|---|
| 157 | Intrinsic(ByteCodeInstruction f, | 
|---|
| 158 | ByteCodeInstruction s, | 
|---|
| 159 | ByteCodeInstruction u) : is_special(false), inst_f(f), inst_s(s), inst_u(u) {} | 
|---|
| 160 |  | 
|---|
| 161 | bool                is_special; | 
|---|
| 162 | SpecialIntrinsic    special; | 
|---|
| 163 | ByteCodeInstruction inst_f; | 
|---|
| 164 | ByteCodeInstruction inst_s; | 
|---|
| 165 | ByteCodeInstruction inst_u; | 
|---|
| 166 | }; | 
|---|
| 167 |  | 
|---|
| 168 |  | 
|---|
| 169 | // Similar to Variable::Storage, but locals and parameters are grouped together, and globals | 
|---|
| 170 | // are further subidivided into uniforms and other (writable) globals. | 
|---|
| 171 | enum class Storage { | 
|---|
| 172 | kLocal,    // include parameters | 
|---|
| 173 | kGlobal,   // non-uniform globals | 
|---|
| 174 | kUniform,  // uniform globals | 
|---|
| 175 | kChildFP,  // child fragment processors | 
|---|
| 176 | }; | 
|---|
| 177 |  | 
|---|
| 178 | struct Location { | 
|---|
| 179 | int     fSlot; | 
|---|
| 180 | Storage fStorage; | 
|---|
| 181 |  | 
|---|
| 182 | // Not really invalid, but a "safe" placeholder to be more explicit at call-sites | 
|---|
| 183 | static Location MakeInvalid() { return { 0, Storage::kLocal }; } | 
|---|
| 184 |  | 
|---|
| 185 | Location makeOnStack() { | 
|---|
| 186 | SkASSERT(fStorage != Storage::kChildFP); | 
|---|
| 187 | return { -1, fStorage }; | 
|---|
| 188 | } | 
|---|
| 189 | bool isOnStack() const { return fSlot < 0; } | 
|---|
| 190 |  | 
|---|
| 191 | Location operator+(int offset) { | 
|---|
| 192 | SkASSERT(fStorage != Storage::kChildFP); | 
|---|
| 193 | SkASSERT(fSlot >= 0); | 
|---|
| 194 | return { fSlot + offset, fStorage }; | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | ByteCodeInstruction selectLoad(ByteCodeInstruction local, | 
|---|
| 198 | ByteCodeInstruction global, | 
|---|
| 199 | ByteCodeInstruction uniform) const { | 
|---|
| 200 | switch (fStorage) { | 
|---|
| 201 | case Storage::kLocal:   return local; | 
|---|
| 202 | case Storage::kGlobal:  return global; | 
|---|
| 203 | case Storage::kUniform: return uniform; | 
|---|
| 204 | case Storage::kChildFP: ABORT( "Trying to load an FP"); break; | 
|---|
| 205 | } | 
|---|
| 206 | return local; | 
|---|
| 207 | } | 
|---|
| 208 |  | 
|---|
| 209 | ByteCodeInstruction selectStore(ByteCodeInstruction local, | 
|---|
| 210 | ByteCodeInstruction global) const { | 
|---|
| 211 | switch (fStorage) { | 
|---|
| 212 | case Storage::kLocal:   return local; | 
|---|
| 213 | case Storage::kGlobal:  return global; | 
|---|
| 214 | case Storage::kUniform: ABORT( "Trying to store to a uniform"); break; | 
|---|
| 215 | case Storage::kChildFP: ABORT( "Trying to store an FP"); break; | 
|---|
| 216 | } | 
|---|
| 217 | return local; | 
|---|
| 218 | } | 
|---|
| 219 | }; | 
|---|
| 220 |  | 
|---|
| 221 | /** | 
|---|
| 222 | * Returns the local slot into which var should be stored, allocating a new slot if it has not | 
|---|
| 223 | * already been assigned one. Compound variables (e.g. vectors) will consume more than one local | 
|---|
| 224 | * slot, with the getLocation return value indicating where the first element should be stored. | 
|---|
| 225 | */ | 
|---|
| 226 | Location getLocation(const Variable& var); | 
|---|
| 227 |  | 
|---|
| 228 | /** | 
|---|
| 229 | * As above, but computes the (possibly dynamic) address of an expression involving indexing & | 
|---|
| 230 | * field access. If the address is known, it's returned. If not, -1 is returned, and the | 
|---|
| 231 | * location will be left on the top of the stack. | 
|---|
| 232 | */ | 
|---|
| 233 | Location getLocation(const Expression& expr); | 
|---|
| 234 |  | 
|---|
| 235 | void gatherUniforms(const Type& type, const String& name); | 
|---|
| 236 |  | 
|---|
| 237 | std::unique_ptr<ByteCodeFunction> writeFunction(const FunctionDefinition& f); | 
|---|
| 238 |  | 
|---|
| 239 | void writeVarDeclarations(const VarDeclarations& decl); | 
|---|
| 240 |  | 
|---|
| 241 | void writeVariableExpression(const Expression& expr); | 
|---|
| 242 |  | 
|---|
| 243 | void writeExpression(const Expression& expr, bool discard = false); | 
|---|
| 244 |  | 
|---|
| 245 | /** | 
|---|
| 246 | * Pushes whatever values are required by the lvalue onto the stack, and returns an LValue | 
|---|
| 247 | * permitting loads and stores to it. | 
|---|
| 248 | */ | 
|---|
| 249 | std::unique_ptr<LValue> getLValue(const Expression& expr); | 
|---|
| 250 |  | 
|---|
| 251 | void writeIntrinsicCall(const FunctionCall& c); | 
|---|
| 252 |  | 
|---|
| 253 | void writeFunctionCall(const FunctionCall& c); | 
|---|
| 254 |  | 
|---|
| 255 | void writeConstructor(const Constructor& c); | 
|---|
| 256 |  | 
|---|
| 257 | void writeExternalFunctionCall(const ExternalFunctionCall& c); | 
|---|
| 258 |  | 
|---|
| 259 | void writeExternalValue(const ExternalValueReference& r); | 
|---|
| 260 |  | 
|---|
| 261 | void writeSwizzle(const Swizzle& swizzle); | 
|---|
| 262 |  | 
|---|
| 263 | bool writeBinaryExpression(const BinaryExpression& b, bool discard); | 
|---|
| 264 |  | 
|---|
| 265 | void writeTernaryExpression(const TernaryExpression& t); | 
|---|
| 266 |  | 
|---|
| 267 | void writeNullLiteral(const NullLiteral& n); | 
|---|
| 268 |  | 
|---|
| 269 | bool writePrefixExpression(const PrefixExpression& p, bool discard); | 
|---|
| 270 |  | 
|---|
| 271 | bool writePostfixExpression(const PostfixExpression& p, bool discard); | 
|---|
| 272 |  | 
|---|
| 273 | void writeBoolLiteral(const BoolLiteral& b); | 
|---|
| 274 |  | 
|---|
| 275 | void writeIntLiteral(const IntLiteral& i); | 
|---|
| 276 |  | 
|---|
| 277 | void writeFloatLiteral(const FloatLiteral& f); | 
|---|
| 278 |  | 
|---|
| 279 | void writeStatement(const Statement& s); | 
|---|
| 280 |  | 
|---|
| 281 | void writeBlock(const Block& b); | 
|---|
| 282 |  | 
|---|
| 283 | void writeBreakStatement(const BreakStatement& b); | 
|---|
| 284 |  | 
|---|
| 285 | void writeContinueStatement(const ContinueStatement& c); | 
|---|
| 286 |  | 
|---|
| 287 | void writeIfStatement(const IfStatement& stmt); | 
|---|
| 288 |  | 
|---|
| 289 | void writeForStatement(const ForStatement& f); | 
|---|
| 290 |  | 
|---|
| 291 | void writeWhileStatement(const WhileStatement& w); | 
|---|
| 292 |  | 
|---|
| 293 | void writeDoStatement(const DoStatement& d); | 
|---|
| 294 |  | 
|---|
| 295 | void writeSwitchStatement(const SwitchStatement& s); | 
|---|
| 296 |  | 
|---|
| 297 | void writeReturnStatement(const ReturnStatement& r); | 
|---|
| 298 |  | 
|---|
| 299 | // updates the current set of breaks to branch to the current location | 
|---|
| 300 | void setBreakTargets(); | 
|---|
| 301 |  | 
|---|
| 302 | // updates the current set of continues to branch to the current location | 
|---|
| 303 | void setContinueTargets(); | 
|---|
| 304 |  | 
|---|
| 305 | void enterLoop() { | 
|---|
| 306 | fLoopCount++; | 
|---|
| 307 | fMaxLoopCount = std::max(fMaxLoopCount, fLoopCount); | 
|---|
| 308 | } | 
|---|
| 309 |  | 
|---|
| 310 | void exitLoop() { | 
|---|
| 311 | SkASSERT(fLoopCount > 0); | 
|---|
| 312 | fLoopCount--; | 
|---|
| 313 | } | 
|---|
| 314 |  | 
|---|
| 315 | void enterCondition() { | 
|---|
| 316 | fConditionCount++; | 
|---|
| 317 | fMaxConditionCount = std::max(fMaxConditionCount, fConditionCount); | 
|---|
| 318 | } | 
|---|
| 319 |  | 
|---|
| 320 | void exitCondition() { | 
|---|
| 321 | SkASSERT(fConditionCount > 0); | 
|---|
| 322 | fConditionCount--; | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | const Context& fContext; | 
|---|
| 326 |  | 
|---|
| 327 | ByteCode* fOutput; | 
|---|
| 328 |  | 
|---|
| 329 | const FunctionDefinition* fFunction; | 
|---|
| 330 |  | 
|---|
| 331 | std::vector<uint8_t>* fCode; | 
|---|
| 332 |  | 
|---|
| 333 | std::vector<const Variable*> fLocals; | 
|---|
| 334 |  | 
|---|
| 335 | std::stack<std::vector<DeferredLocation>> fContinueTargets; | 
|---|
| 336 |  | 
|---|
| 337 | std::stack<std::vector<DeferredLocation>> fBreakTargets; | 
|---|
| 338 |  | 
|---|
| 339 | std::vector<const FunctionDefinition*> fFunctions; | 
|---|
| 340 |  | 
|---|
| 341 | int fParameterCount; | 
|---|
| 342 | int fStackCount; | 
|---|
| 343 | int fMaxStackCount; | 
|---|
| 344 |  | 
|---|
| 345 | int fLoopCount; | 
|---|
| 346 | int fMaxLoopCount; | 
|---|
| 347 | int fConditionCount; | 
|---|
| 348 | int fMaxConditionCount; | 
|---|
| 349 |  | 
|---|
| 350 | const std::unordered_map<String, Intrinsic> fIntrinsics; | 
|---|
| 351 |  | 
|---|
| 352 | friend class DeferredLocation; | 
|---|
| 353 | friend class ByteCodeExpressionLValue; | 
|---|
| 354 | friend class ByteCodeSwizzleLValue; | 
|---|
| 355 |  | 
|---|
| 356 | typedef CodeGenerator INHERITED; | 
|---|
| 357 | }; | 
|---|
| 358 |  | 
|---|
| 359 | }  // namespace SkSL | 
|---|
| 360 |  | 
|---|
| 361 | #endif | 
|---|
| 362 |  | 
|---|