• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
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_JIT
9 #define SKSL_JIT
10 
11 #ifdef SK_LLVM_AVAILABLE
12 
13 #include "ir/SkSLBinaryExpression.h"
14 #include "ir/SkSLBreakStatement.h"
15 #include "ir/SkSLContinueStatement.h"
16 #include "ir/SkSLExpression.h"
17 #include "ir/SkSLDoStatement.h"
18 #include "ir/SkSLForStatement.h"
19 #include "ir/SkSLFunctionCall.h"
20 #include "ir/SkSLFunctionDefinition.h"
21 #include "ir/SkSLIfStatement.h"
22 #include "ir/SkSLIndexExpression.h"
23 #include "ir/SkSLPrefixExpression.h"
24 #include "ir/SkSLPostfixExpression.h"
25 #include "ir/SkSLProgram.h"
26 #include "ir/SkSLReturnStatement.h"
27 #include "ir/SkSLStatement.h"
28 #include "ir/SkSLSwizzle.h"
29 #include "ir/SkSLTernaryExpression.h"
30 #include "ir/SkSLVarDeclarationsStatement.h"
31 #include "ir/SkSLVariableReference.h"
32 #include "ir/SkSLWhileStatement.h"
33 
34 #include "llvm-c/Analysis.h"
35 #include "llvm-c/Core.h"
36 #include "llvm-c/OrcBindings.h"
37 #include "llvm-c/Support.h"
38 #include "llvm-c/Target.h"
39 #include "llvm-c/Transforms/PassManagerBuilder.h"
40 #include "llvm-c/Types.h"
41 #include <stack>
42 
43 class SkRasterPipeline;
44 
45 namespace SkSL {
46 
47 struct AppendStage;
48 
49 /**
50  * A just-in-time compiler for SkSL code which uses an LLVM backend. Only available when the
51  * skia_llvm_path gn arg is set.
52  *
53  * Example of using SkSLJIT to set up an SkJumper pipeline stage:
54  *
55  * #ifdef SK_LLVM_AVAILABLE
56  *   SkSL::Compiler compiler;
57  *   SkSL::Program::Settings settings;
58  *   std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
59          SkSL::Program::kPipelineStage_Kind,
60  *       "void swap(int x, int y, inout float4 color) {"
61  *       "    color.rb = color.br;"
62  *       "}",
63  *       settings);
64  *   if (!program) {
65  *       printf("%s\n", compiler.errorText().c_str());
66  *       abort();
67  *   }
68  *   SkSL::JIT& jit = *scratch->make<SkSL::JIT>(&compiler);
69  *   std::unique_ptr<SkSL::JIT::Module> module = jit.compile(std::move(program));
70  *   void* func = module->getJumperStage("swap");
71  *   p->append(func, nullptr);
72  * #endif
73  */
74 class JIT {
75     typedef int StackIndex;
76 
77 public:
78     class Module {
79     public:
80         /**
81          * Returns the address of a symbol in the module.
82          */
83         void* getSymbol(const char* name);
84 
85         /**
86          * Returns the address of a function as an SkJumper pipeline stage. The function must have
87          * the signature void <name>(int x, int y, inout float4 color). The returned function will
88          * have the correct signature to function as an SkJumper stage (meaning it will actually
89          * have a different signature at runtime, accepting vector parameters and operating on
90          * multiple pixels simultaneously as is normal for SkJumper stages).
91          */
92         void* getJumperStage(const char* name);
93 
~Module()94         ~Module() {
95             LLVMOrcDisposeSharedModuleRef(fSharedModule);
96         }
97 
98     private:
Module(std::unique_ptr<Program> program,LLVMSharedModuleRef sharedModule,LLVMOrcJITStackRef jitStack)99         Module(std::unique_ptr<Program> program,
100                LLVMSharedModuleRef sharedModule,
101                LLVMOrcJITStackRef jitStack)
102         : fProgram(std::move(program))
103         , fSharedModule(sharedModule)
104         , fJITStack(jitStack) {}
105 
106         std::unique_ptr<Program> fProgram;
107         LLVMSharedModuleRef fSharedModule;
108         LLVMOrcJITStackRef fJITStack;
109 
110         friend class JIT;
111     };
112 
113     JIT(Compiler* compiler);
114 
115     ~JIT();
116 
117     /**
118      * Just-in-time compiles an SkSL program and returns the resulting Module. The JIT must not be
119      * destroyed before all of its Modules are destroyed.
120      */
121     std::unique_ptr<Module> compile(std::unique_ptr<Program> program);
122 
123 private:
124     static constexpr int CHANNELS = 4;
125 
126     enum TypeKind {
127         kFloat_TypeKind,
128         kInt_TypeKind,
129         kUInt_TypeKind,
130         kBool_TypeKind
131     };
132 
133     class LValue {
134     public:
~LValue()135         virtual ~LValue() {}
136 
137         virtual LLVMValueRef load(LLVMBuilderRef builder) = 0;
138 
139         virtual void store(LLVMBuilderRef builder, LLVMValueRef value) = 0;
140     };
141 
142     void addBuiltinFunction(const char* ourName, const char* realName, LLVMTypeRef returnType,
143                             std::vector<LLVMTypeRef> parameters);
144 
145     void loadBuiltinFunctions();
146 
147     void setBlock(LLVMBuilderRef builder, LLVMBasicBlockRef block);
148 
149     LLVMTypeRef getType(const Type& type);
150 
151     TypeKind typeKind(const Type& type);
152 
153     std::unique_ptr<LValue> getLValue(LLVMBuilderRef builder, const Expression& expr);
154 
155     void vectorize(LLVMBuilderRef builder, LLVMValueRef* value, int columns);
156 
157     void vectorize(LLVMBuilderRef builder, const BinaryExpression& b, LLVMValueRef* left,
158                    LLVMValueRef* right);
159 
160     LLVMValueRef compileBinary(LLVMBuilderRef builder, const BinaryExpression& b);
161 
162     LLVMValueRef compileConstructor(LLVMBuilderRef builder, const Constructor& c);
163 
164     LLVMValueRef compileFunctionCall(LLVMBuilderRef builder, const FunctionCall& fc);
165 
166     LLVMValueRef compileIndex(LLVMBuilderRef builder, const IndexExpression& v);
167 
168     LLVMValueRef compilePostfix(LLVMBuilderRef builder, const PostfixExpression& p);
169 
170     LLVMValueRef compilePrefix(LLVMBuilderRef builder, const PrefixExpression& p);
171 
172     LLVMValueRef compileSwizzle(LLVMBuilderRef builder, const Swizzle& s);
173 
174     LLVMValueRef compileVariableReference(LLVMBuilderRef builder, const VariableReference& v);
175 
176     LLVMValueRef compileTernary(LLVMBuilderRef builder, const TernaryExpression& t);
177 
178     LLVMValueRef compileExpression(LLVMBuilderRef builder, const Expression& expr);
179 
180     void appendStage(LLVMBuilderRef builder, const AppendStage& a);
181 
182     void compileBlock(LLVMBuilderRef builder, const Block& block);
183 
184     void compileBreak(LLVMBuilderRef builder, const BreakStatement& b);
185 
186     void compileContinue(LLVMBuilderRef builder, const ContinueStatement& c);
187 
188     void compileDo(LLVMBuilderRef builder, const DoStatement& d);
189 
190     void compileFor(LLVMBuilderRef builder, const ForStatement& f);
191 
192     void compileIf(LLVMBuilderRef builder, const IfStatement& i);
193 
194     void compileReturn(LLVMBuilderRef builder, const ReturnStatement& r);
195 
196     void compileVarDeclarations(LLVMBuilderRef builder, const VarDeclarationsStatement& decls);
197 
198     void compileWhile(LLVMBuilderRef builder, const WhileStatement& w);
199 
200     void compileStatement(LLVMBuilderRef builder, const Statement& stmt);
201 
202     // The "Vector" variants of functions attempt to compile a given expression or statement as part
203     // of a vectorized SkJumper stage function - that is, with r, g, b, and a each being vectors of
204     // fVectorCount floats. So a statement like "color.r = 0;" looks like it modifies a single
205     // channel of a single pixel, but the compiled code will actually modify the red channel of
206     // fVectorCount pixels at once.
207     //
208     // As not everything can be vectorized, these calls return a bool to indicate whether they were
209     // successful. If anything anywhere in the function cannot be vectorized, the JIT will fall back
210     // to looping over the pixels instead.
211     //
212     // Since we process multiple pixels at once, and each pixel consists of multiple color channels,
213     // expressions may effectively result in a vector-of-vectors. We produce zero to four outputs
214     // when compiling expression, each of which is a vector, so that e.g. float2(1, 0) actually
215     // produces two vectors, one containing all 1s, the other all 0s. The out parameter always
216     // allows for 4 channels, but the functions produce 0 to 4 channels depending on the type they
217     // are operating on. Thus evaluating "color.rgb" actually fills in out[0] through out[2],
218     // leaving out[3] uninitialized.
219     // As the number of outputs can be inferred from the type of the expression, it is not
220     // explicitly signalled anywhere.
221     bool compileVectorBinary(LLVMBuilderRef builder, const BinaryExpression& b,
222                              LLVMValueRef out[CHANNELS]);
223 
224     bool compileVectorConstructor(LLVMBuilderRef builder, const Constructor& c,
225                                   LLVMValueRef out[CHANNELS]);
226 
227     bool compileVectorFloatLiteral(LLVMBuilderRef builder, const FloatLiteral& f,
228                                    LLVMValueRef out[CHANNELS]);
229 
230     bool compileVectorSwizzle(LLVMBuilderRef builder, const Swizzle& s,
231                               LLVMValueRef out[CHANNELS]);
232 
233     bool compileVectorVariableReference(LLVMBuilderRef builder, const VariableReference& v,
234                                         LLVMValueRef out[CHANNELS]);
235 
236     bool compileVectorExpression(LLVMBuilderRef builder, const Expression& expr,
237                                  LLVMValueRef out[CHANNELS]);
238 
239     bool getVectorLValue(LLVMBuilderRef builder, const Expression& e, LLVMValueRef out[CHANNELS]);
240 
241     /**
242      * Evaluates the left and right operands of a binary operation, promoting one of them to a
243      * vector if necessary to make the types match.
244      */
245     bool getVectorBinaryOperands(LLVMBuilderRef builder, const Expression& left,
246                                  LLVMValueRef outLeft[CHANNELS], const Expression& right,
247                                  LLVMValueRef outRight[CHANNELS]);
248 
249     bool compileVectorStatement(LLVMBuilderRef builder, const Statement& stmt);
250 
251     /**
252      * Returns true if this function has the signature void(int, int, inout float4) and thus can be
253      * used as an SkJumper stage.
254      */
255     bool hasStageSignature(const FunctionDeclaration& f);
256 
257     /**
258      * Attempts to compile a vectorized stage function, returning true on success. A stage function
259      * of e.g. "color.r = 0;" will produce code which sets the entire red vector to zeros in a
260      * single instruction, thus calculating several pixels at once.
261      */
262     bool compileStageFunctionVector(const FunctionDefinition& f, LLVMValueRef newFunc);
263 
264     /**
265      * Fallback function which loops over the pixels, for when vectorization fails. A stage function
266      * of e.g. "color.r = 0;" will produce a loop which iterates over the entries in the red vector,
267      * setting each one to zero individually.
268      */
269     void compileStageFunctionLoop(const FunctionDefinition& f, LLVMValueRef newFunc);
270 
271     /**
272      * Called when compiling a function which has the signature of an SkJumper stage. Produces a
273      * version of the function which can be plugged into SkJumper (thus having a signature which
274      * accepts four vectors, one for each color channel, containing the color data of multiple
275      * pixels at once). To go from SkSL code which operates on a single pixel at a time to CPU code
276      * which operates on multiple pixels at once, the code is either vectorized using
277      * compileStageFunctionVector or wrapped in a loop using compileStageFunctionLoop.
278      */
279     LLVMValueRef compileStageFunction(const FunctionDefinition& f);
280 
281     /**
282      * Compiles an SkSL function to an LLVM function. If the function has the signature of an
283      * SkJumper stage, it will *also* be compiled by compileStageFunction, resulting in both a stage
284      * and non-stage version of the function.
285      */
286     LLVMValueRef compileFunction(const FunctionDefinition& f);
287 
288     void createModule();
289 
290     void optimize();
291 
292     bool isColorRef(const Expression& expr);
293 
294     static uint64_t resolveSymbol(const char* name, JIT* jit);
295 
296     const char* fCPU;
297     int fVectorCount;
298     Compiler& fCompiler;
299     std::unique_ptr<Program> fProgram;
300     LLVMContextRef fContext;
301     LLVMModuleRef fModule;
302     LLVMSharedModuleRef fSharedModule;
303     LLVMOrcJITStackRef fJITStack;
304     LLVMValueRef fCurrentFunction;
305     LLVMBasicBlockRef fAllocaBlock;
306     LLVMBasicBlockRef fCurrentBlock;
307     LLVMTypeRef fVoidType;
308     LLVMTypeRef fInt1Type;
309     LLVMTypeRef fInt1VectorType;
310     LLVMTypeRef fInt1Vector2Type;
311     LLVMTypeRef fInt1Vector3Type;
312     LLVMTypeRef fInt1Vector4Type;
313     LLVMTypeRef fInt8Type;
314     LLVMTypeRef fInt8PtrType;
315     LLVMTypeRef fInt32Type;
316     LLVMTypeRef fInt32VectorType;
317     LLVMTypeRef fInt32Vector2Type;
318     LLVMTypeRef fInt32Vector3Type;
319     LLVMTypeRef fInt32Vector4Type;
320     LLVMTypeRef fInt64Type;
321     LLVMTypeRef fSizeTType;
322     LLVMTypeRef fFloat32Type;
323     LLVMTypeRef fFloat32VectorType;
324     LLVMTypeRef fFloat32Vector2Type;
325     LLVMTypeRef fFloat32Vector3Type;
326     LLVMTypeRef fFloat32Vector4Type;
327     // Our SkSL stage functions have a single float4 for color, but the actual SkJumper stage
328     // function has four separate vectors, one for each channel. These four values are references to
329     // the red, green, blue, and alpha vectors respectively.
330     LLVMValueRef fChannels[CHANNELS];
331     // when processing a stage function, this points to the SkSL color parameter (an inout float4)
332     const Variable* fColorParam;
333     std::unordered_map<const FunctionDeclaration*, LLVMValueRef> fFunctions;
334     std::unordered_map<const Variable*, LLVMValueRef> fVariables;
335     // LLVM function parameters are read-only, so when modifying function parameters we need to
336     // first promote them to variables. This keeps track of which parameters have been promoted.
337     std::set<const Variable*> fPromotedParameters;
338     std::vector<LLVMBasicBlockRef> fBreakTarget;
339     std::vector<LLVMBasicBlockRef> fContinueTarget;
340 
341     LLVMValueRef fFoldAnd2Func;
342     LLVMValueRef fFoldOr2Func;
343     LLVMValueRef fFoldAnd3Func;
344     LLVMValueRef fFoldOr3Func;
345     LLVMValueRef fFoldAnd4Func;
346     LLVMValueRef fFoldOr4Func;
347     LLVMValueRef fAppendFunc;
348     LLVMValueRef fAppendCallbackFunc;
349     LLVMValueRef fDebugFunc;
350 };
351 
352 } // namespace
353 
354 #endif // SK_LLVM_AVAILABLE
355 
356 #endif // SKSL_JIT
357