blob: c5b7ce5adfcc134b251d631eb80580c8e646b9c3 [file] [log] [blame]
Ethan Nicholas26a9aad2018-03-27 14:10:52 -04001/*
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
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040013#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
43class SkRasterPipeline;
44
45namespace SkSL {
46
Ethan Nicholas00543112018-07-31 09:44:36 -040047struct AppendStage;
48
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040049/**
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;
Ethan Nicholas00543112018-07-31 09:44:36 -040058 * std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
59 SkSL::Program::kPipelineStage_Kind,
Ethan Nicholas26a9aad2018-03-27 14:10:52 -040060 * "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 */
74class JIT {
75 typedef int StackIndex;
76
77public:
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
94 ~Module() {
95 LLVMOrcDisposeSharedModuleRef(fSharedModule);
96 }
97
98 private:
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
123private:
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:
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;
Ethan Nicholas00543112018-07-31 09:44:36 -0400309 LLVMTypeRef fInt1VectorType;
310 LLVMTypeRef fInt1Vector2Type;
311 LLVMTypeRef fInt1Vector3Type;
312 LLVMTypeRef fInt1Vector4Type;
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400313 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;
Ethan Nicholasee04df42018-08-02 14:32:22 -0400333 std::unordered_map<const FunctionDeclaration*, LLVMValueRef> fFunctions;
334 std::unordered_map<const Variable*, LLVMValueRef> fVariables;
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400335 // 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
Ethan Nicholas00543112018-07-31 09:44:36 -0400341 LLVMValueRef fFoldAnd2Func;
342 LLVMValueRef fFoldOr2Func;
343 LLVMValueRef fFoldAnd3Func;
344 LLVMValueRef fFoldOr3Func;
345 LLVMValueRef fFoldAnd4Func;
346 LLVMValueRef fFoldOr4Func;
Ethan Nicholas26a9aad2018-03-27 14:10:52 -0400347 LLVMValueRef fAppendFunc;
348 LLVMValueRef fAppendCallbackFunc;
349 LLVMValueRef fDebugFunc;
350};
351
352} // namespace
353
354#endif // SK_LLVM_AVAILABLE
355
356#endif // SKSL_JIT