blob: c5a5d2c303232a3747b1c51b2fa7ff4d1c787a15 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 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 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04008#include "SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
ethannicholasb3058bd2016-07-01 08:22:01 -070010#include "GLSL.std.450.h"
11
12#include "ir/SkSLExpressionStatement.h"
13#include "ir/SkSLExtension.h"
14#include "ir/SkSLIndexExpression.h"
15#include "ir/SkSLVariableReference.h"
ethannicholas5961bc92016-10-12 06:39:56 -070016#include "SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
18namespace SkSL {
19
ethannicholasb3058bd2016-07-01 08:22:01 -070020static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
21
22void SPIRVCodeGenerator::setupIntrinsics() {
23#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
24 GLSLstd450 ## x, GLSLstd450 ## x)
25#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
26 GLSLstd450 ## ifFloat, \
27 GLSLstd450 ## ifInt, \
28 GLSLstd450 ## ifUInt, \
29 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040030#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
31 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070032#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
33 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
34 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040035 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
36 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
37 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
38 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
39 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
40 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
41 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
42 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
43 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
44 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
45 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
46 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
47 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
48 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
49 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
50 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
51 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
52 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
53 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
54 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
55 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
56 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
57 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
58 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
59 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
60 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
61 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
62 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040063 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
64 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040065 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
66 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
67 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050068 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050069 fIntrinsicMap[String("min")] = SPECIAL(Min);
70 fIntrinsicMap[String("max")] = SPECIAL(Max);
71 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040072 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040073 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050074 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040075 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
76 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
77 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
78 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
79 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070080
Ethan Nicholas0df1b042017-03-31 13:56:23 -040081#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
82 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070083 PACK(Snorm4x8);
84 PACK(Unorm4x8);
85 PACK(Snorm2x16);
86 PACK(Unorm2x16);
87 PACK(Half2x16);
88 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040089 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
90 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
91 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
92 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
93 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
94 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
95 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
96 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
97 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
98 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040099 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400100 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400101 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400102 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400103 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400104 fIntrinsicMap[String("texture")] = SPECIAL(Texture);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400105 fIntrinsicMap[String("texelFetch")] = SPECIAL(TexelFetch);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400106 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500107
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400108 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400109 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400110 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400111 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400112 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400113 SpvOpFOrdEqual, SpvOpIEqual,
114 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400116 SpvOpFOrdNotEqual, SpvOpINotEqual,
117 SpvOpINotEqual,
118 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400119 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500120 SpvOpFOrdLessThan, SpvOpSLessThan,
121 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400122 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500123 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpSLessThanEqual,
125 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400126 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400127 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500128 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpSGreaterThan,
130 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500133 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpSGreaterThanEqual,
135 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400137 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
138 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700139// interpolateAt* not yet supported...
140}
141
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400142void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700143 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700144}
145
ethannicholasd598f792016-07-25 10:08:54 -0700146static bool is_float(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700147 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700148 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700149 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400150 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
151 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700152}
153
ethannicholasd598f792016-07-25 10:08:54 -0700154static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700155 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700156 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700157 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400158 return type == *context.fInt_Type || type == *context.fShort_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700159}
160
ethannicholasd598f792016-07-25 10:08:54 -0700161static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700163 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400165 return type == *context.fUInt_Type || type == *context.fUShort_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700166}
167
ethannicholasd598f792016-07-25 10:08:54 -0700168static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700169 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700170 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700171 }
ethannicholasd598f792016-07-25 10:08:54 -0700172 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700173}
174
ethannicholasd598f792016-07-25 10:08:54 -0700175static bool is_out(const Variable& var) {
176 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700177}
178
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400179void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -0500180 ASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700181 ASSERT(opCode != SpvOpUndef);
182 switch (opCode) {
183 case SpvOpReturn: // fall through
184 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700185 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700186 case SpvOpBranch: // fall through
187 case SpvOpBranchConditional:
188 ASSERT(fCurrentBlock);
189 fCurrentBlock = 0;
190 break;
191 case SpvOpConstant: // fall through
192 case SpvOpConstantTrue: // fall through
193 case SpvOpConstantFalse: // fall through
194 case SpvOpConstantComposite: // fall through
195 case SpvOpTypeVoid: // fall through
196 case SpvOpTypeInt: // fall through
197 case SpvOpTypeFloat: // fall through
198 case SpvOpTypeBool: // fall through
199 case SpvOpTypeVector: // fall through
200 case SpvOpTypeMatrix: // fall through
201 case SpvOpTypeArray: // fall through
202 case SpvOpTypePointer: // fall through
203 case SpvOpTypeFunction: // fall through
204 case SpvOpTypeRuntimeArray: // fall through
205 case SpvOpTypeStruct: // fall through
206 case SpvOpTypeImage: // fall through
207 case SpvOpTypeSampledImage: // fall through
208 case SpvOpVariable: // fall through
209 case SpvOpFunction: // fall through
210 case SpvOpFunctionParameter: // fall through
211 case SpvOpFunctionEnd: // fall through
212 case SpvOpExecutionMode: // fall through
213 case SpvOpMemoryModel: // fall through
214 case SpvOpCapability: // fall through
215 case SpvOpExtInstImport: // fall through
216 case SpvOpEntryPoint: // fall through
217 case SpvOpSource: // fall through
218 case SpvOpSourceExtension: // fall through
219 case SpvOpName: // fall through
220 case SpvOpMemberName: // fall through
221 case SpvOpDecorate: // fall through
222 case SpvOpMemberDecorate:
223 break;
224 default:
225 ASSERT(fCurrentBlock);
226 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700227 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700228}
229
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400230void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700231 fCurrentBlock = label;
232 this->writeInstruction(SpvOpLabel, label, out);
233}
234
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400235void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700236 this->writeOpCode(opCode, 1, out);
237}
238
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400239void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700240 this->writeOpCode(opCode, 2, out);
241 this->writeWord(word1, out);
242}
243
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700244void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400245 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 switch (length % 4) {
247 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500248 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 // fall through
250 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500251 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 // fall through
253 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500254 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700255 break;
256 default:
257 this->writeWord(0, out);
258 }
259}
260
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700261void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
262 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
263 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700264}
265
266
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700267void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400268 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700269 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700270 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700271 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700272}
273
Greg Daniel64773e62016-11-22 09:44:03 -0500274void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700275 StringFragment string, OutputStream& out) {
276 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700277 this->writeWord(word1, out);
278 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700279 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700280}
281
Greg Daniel64773e62016-11-22 09:44:03 -0500282void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400283 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700284 this->writeOpCode(opCode, 3, out);
285 this->writeWord(word1, out);
286 this->writeWord(word2, out);
287}
288
Greg Daniel64773e62016-11-22 09:44:03 -0500289void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400290 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700291 this->writeOpCode(opCode, 4, out);
292 this->writeWord(word1, out);
293 this->writeWord(word2, out);
294 this->writeWord(word3, out);
295}
296
Greg Daniel64773e62016-11-22 09:44:03 -0500297void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400298 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 this->writeOpCode(opCode, 5, out);
300 this->writeWord(word1, out);
301 this->writeWord(word2, out);
302 this->writeWord(word3, out);
303 this->writeWord(word4, out);
304}
305
Greg Daniel64773e62016-11-22 09:44:03 -0500306void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
307 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400308 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700309 this->writeOpCode(opCode, 6, out);
310 this->writeWord(word1, out);
311 this->writeWord(word2, out);
312 this->writeWord(word3, out);
313 this->writeWord(word4, out);
314 this->writeWord(word5, out);
315}
316
Greg Daniel64773e62016-11-22 09:44:03 -0500317void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700318 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400319 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700320 this->writeOpCode(opCode, 7, out);
321 this->writeWord(word1, out);
322 this->writeWord(word2, out);
323 this->writeWord(word3, out);
324 this->writeWord(word4, out);
325 this->writeWord(word5, out);
326 this->writeWord(word6, out);
327}
328
Greg Daniel64773e62016-11-22 09:44:03 -0500329void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700330 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400331 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700332 this->writeOpCode(opCode, 8, out);
333 this->writeWord(word1, out);
334 this->writeWord(word2, out);
335 this->writeWord(word3, out);
336 this->writeWord(word4, out);
337 this->writeWord(word5, out);
338 this->writeWord(word6, out);
339 this->writeWord(word7, out);
340}
341
Greg Daniel64773e62016-11-22 09:44:03 -0500342void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700343 int32_t word3, int32_t word4, int32_t word5,
344 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400345 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700346 this->writeOpCode(opCode, 9, out);
347 this->writeWord(word1, out);
348 this->writeWord(word2, out);
349 this->writeWord(word3, out);
350 this->writeWord(word4, out);
351 this->writeWord(word5, out);
352 this->writeWord(word6, out);
353 this->writeWord(word7, out);
354 this->writeWord(word8, out);
355}
356
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400357void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700358 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
359 if (fCapabilities & bit) {
360 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
361 }
362 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400363 if (fProgram.fKind == Program::kGeometry_Kind) {
364 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
365 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700366}
367
368SpvId SPIRVCodeGenerator::nextId() {
369 return fIdCount++;
370}
371
Ethan Nicholas19671772016-11-28 16:30:17 -0500372void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
373 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700374 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
375 // go ahead and write all of the field types, so we don't inadvertently write them while we're
376 // in the middle of writing the struct instruction
377 std::vector<SpvId> types;
378 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500379 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700380 }
381 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
382 this->writeWord(resultId, fConstantBuffer);
383 for (SpvId id : types) {
384 this->writeWord(id, fConstantBuffer);
385 }
386 size_t offset = 0;
387 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500388 size_t size = memoryLayout.size(*type.fields()[i].fType);
389 size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
390 const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
391 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500392 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700393 fErrors.error(type.fOffset,
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500394 "offset of field '" + type.fields()[i].fName + "' must be at "
395 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500396 }
397 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700398 fErrors.error(type.fOffset,
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500399 "offset of field '" + type.fields()[i].fName + "' must be a multiple"
400 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500401 }
402 offset = fieldLayout.fOffset;
403 } else {
404 size_t mod = offset % alignment;
405 if (mod) {
406 offset += alignment - mod;
407 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700408 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700409 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500410 this->writeLayout(fieldLayout, resultId, i);
ethannicholasb3058bd2016-07-01 08:22:01 -0700411 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500412 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700413 (SpvId) offset, fDecorationBuffer);
414 }
ethannicholas0730be72016-09-01 07:59:02 -0700415 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500416 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700417 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500418 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholas19671772016-11-28 16:30:17 -0500419 (SpvId) memoryLayout.stride(*type.fields()[i].fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800420 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 }
422 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -0700423 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700424 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
425 offset += alignment - offset % alignment;
426 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700427 }
428}
429
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400430Type SPIRVCodeGenerator::getActualType(const Type& type) {
431 if (type == *fContext.fHalf_Type) {
432 return *fContext.fFloat_Type;
433 }
434 if (type == *fContext.fShort_Type) {
435 return *fContext.fInt_Type;
436 }
437 if (type == *fContext.fUShort_Type) {
438 return *fContext.fUInt_Type;
439 }
440 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
441 if (type.componentType() == *fContext.fHalf_Type) {
442 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
443 }
444 if (type.componentType() == *fContext.fShort_Type) {
445 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
446 }
447 if (type.componentType() == *fContext.fUShort_Type) {
448 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
449 }
450 }
451 return type;
452}
453
ethannicholasb3058bd2016-07-01 08:22:01 -0700454SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800455 return this->getType(type, fDefaultLayout);
456}
457
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400458SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
459 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400460 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800461 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700462 if (entry == fTypeMap.end()) {
463 SpvId result = this->nextId();
464 switch (type.kind()) {
465 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700466 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700467 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700468 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700470 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700471 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700472 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700474 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700475 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
476 } else {
477 ASSERT(false);
478 }
479 break;
480 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500481 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800482 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700483 type.columns(), fConstantBuffer);
484 break;
485 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500486 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800487 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 type.columns(), fConstantBuffer);
489 break;
490 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800491 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700492 break;
493 case Type::kArray_Kind: {
494 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700495 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500496 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800497 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500499 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400500 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800501 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 } else {
Greg Daniel64773e62016-11-22 09:44:03 -0500503 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800504 this->getType(type.componentType(), layout),
505 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400506 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
507 (int32_t) layout.stride(type),
508 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 }
510 break;
511 }
512 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500513 SpvId image = result;
514 if (SpvDimSubpassData != type.dimensions()) {
515 image = this->nextId();
516 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400517 if (SpvDimBuffer == type.dimensions()) {
518 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
519 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800520 this->writeInstruction(SpvOpTypeImage, image,
521 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700522 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500523 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700524 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400525 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500526 if (SpvDimSubpassData != type.dimensions()) {
527 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
528 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 break;
530 }
531 default:
ethannicholasd598f792016-07-25 10:08:54 -0700532 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
534 } else {
535 ABORT("invalid type: %s", type.description().c_str());
536 }
537 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800538 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700539 return result;
540 }
541 return entry->second;
542}
543
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400544SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
545 ASSERT(type.kind() == Type::kSampler_Kind);
546 this->getType(type);
547 String key = type.name() + to_string((int) fDefaultLayout.fStd);
548 ASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
549 return fImageTypeMap[key];
550}
551
ethannicholasd598f792016-07-25 10:08:54 -0700552SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400553 String key = function.fReturnType.description() + "(";
554 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700555 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700556 key += separator;
557 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700558 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 }
560 key += ")";
561 auto entry = fTypeMap.find(key);
562 if (entry == fTypeMap.end()) {
563 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700564 int32_t length = 3 + (int32_t) function.fParameters.size();
565 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700566 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700567 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500568 // glslang seems to treat all function arguments as pointers whether they need to be or
569 // not. I was initially puzzled by this until I ran bizarre failures with certain
570 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700571 // failure case:
572 //
573 // void sphere(float x) {
574 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500575 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 // void map() {
577 // sphere(1.0);
578 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500579 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 // void main() {
581 // for (int i = 0; i < 1; i++) {
582 // map();
583 // }
584 // }
585 //
Greg Daniel64773e62016-11-22 09:44:03 -0500586 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
587 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700588 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
589 // the spec makes this make sense.
590// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700591 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700592 SpvStorageClassFunction));
593// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700594// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700595// }
596 }
597 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
598 this->writeWord(result, fConstantBuffer);
599 this->writeWord(returnType, fConstantBuffer);
600 for (SpvId id : parameterTypes) {
601 this->writeWord(id, fConstantBuffer);
602 }
603 fTypeMap[key] = result;
604 return result;
605 }
606 return entry->second;
607}
608
ethannicholas8ac838d2016-11-22 08:39:36 -0800609SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
610 return this->getPointerType(type, fDefaultLayout, storageClass);
611}
612
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400613SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700614 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400615 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400616 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 auto entry = fTypeMap.find(key);
618 if (entry == fTypeMap.end()) {
619 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500620 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700621 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 fTypeMap[key] = result;
623 return result;
624 }
625 return entry->second;
626}
627
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400628SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 switch (expr.fKind) {
630 case Expression::kBinary_Kind:
631 return this->writeBinaryExpression((BinaryExpression&) expr, out);
632 case Expression::kBoolLiteral_Kind:
633 return this->writeBoolLiteral((BoolLiteral&) expr);
634 case Expression::kConstructor_Kind:
635 return this->writeConstructor((Constructor&) expr, out);
636 case Expression::kIntLiteral_Kind:
637 return this->writeIntLiteral((IntLiteral&) expr);
638 case Expression::kFieldAccess_Kind:
639 return this->writeFieldAccess(((FieldAccess&) expr), out);
640 case Expression::kFloatLiteral_Kind:
641 return this->writeFloatLiteral(((FloatLiteral&) expr));
642 case Expression::kFunctionCall_Kind:
643 return this->writeFunctionCall((FunctionCall&) expr, out);
644 case Expression::kPrefix_Kind:
645 return this->writePrefixExpression((PrefixExpression&) expr, out);
646 case Expression::kPostfix_Kind:
647 return this->writePostfixExpression((PostfixExpression&) expr, out);
648 case Expression::kSwizzle_Kind:
649 return this->writeSwizzle((Swizzle&) expr, out);
650 case Expression::kVariableReference_Kind:
651 return this->writeVariableReference((VariableReference&) expr, out);
652 case Expression::kTernary_Kind:
653 return this->writeTernaryExpression((TernaryExpression&) expr, out);
654 case Expression::kIndex_Kind:
655 return this->writeIndexExpression((IndexExpression&) expr, out);
656 default:
657 ABORT("unsupported expression: %s", expr.description().c_str());
658 }
659 return -1;
660}
661
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400662SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700663 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -0700664 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700665 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400666 if (c.fArguments.size() > 0) {
667 const Type& type = c.fArguments[0]->fType;
668 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
669 intrinsicId = std::get<1>(intrinsic->second);
670 } else if (is_signed(fContext, type)) {
671 intrinsicId = std::get<2>(intrinsic->second);
672 } else if (is_unsigned(fContext, type)) {
673 intrinsicId = std::get<3>(intrinsic->second);
674 } else if (is_bool(fContext, type)) {
675 intrinsicId = std::get<4>(intrinsic->second);
676 } else {
677 intrinsicId = std::get<1>(intrinsic->second);
678 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700679 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400680 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700681 }
682 switch (std::get<0>(intrinsic->second)) {
683 case kGLSL_STD_450_IntrinsicKind: {
684 SpvId result = this->nextId();
685 std::vector<SpvId> arguments;
686 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400687 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
688 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
689 } else {
690 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
691 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700692 }
693 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700694 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700695 this->writeWord(result, out);
696 this->writeWord(fGLSLExtendedInstructions, out);
697 this->writeWord(intrinsicId, out);
698 for (SpvId id : arguments) {
699 this->writeWord(id, out);
700 }
701 return result;
702 }
703 case kSPIRV_IntrinsicKind: {
704 SpvId result = this->nextId();
705 std::vector<SpvId> arguments;
706 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400707 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
708 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
709 } else {
710 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
711 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700712 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400713 if (c.fType != *fContext.fVoid_Type) {
714 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
715 this->writeWord(this->getType(c.fType), out);
716 this->writeWord(result, out);
717 } else {
718 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
719 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700720 for (SpvId id : arguments) {
721 this->writeWord(id, out);
722 }
723 return result;
724 }
725 case kSpecial_IntrinsicKind:
726 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
727 default:
728 ABORT("unsupported intrinsic kind");
729 }
730}
731
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500732std::vector<SpvId> SPIRVCodeGenerator::vectorize(
733 const std::vector<std::unique_ptr<Expression>>& args,
734 OutputStream& out) {
735 int vectorSize = 0;
736 for (const auto& a : args) {
737 if (a->fType.kind() == Type::kVector_Kind) {
738 if (vectorSize) {
739 ASSERT(a->fType.columns() == vectorSize);
740 }
741 else {
742 vectorSize = a->fType.columns();
743 }
744 }
745 }
746 std::vector<SpvId> result;
747 for (const auto& a : args) {
748 SpvId raw = this->writeExpression(*a, out);
749 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
750 SpvId vector = this->nextId();
751 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
752 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
753 this->writeWord(vector, out);
754 for (int i = 0; i < vectorSize; i++) {
755 this->writeWord(raw, out);
756 }
757 result.push_back(vector);
758 } else {
759 result.push_back(raw);
760 }
761 }
762 return result;
763}
764
765void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
766 SpvId signedInst, SpvId unsignedInst,
767 const std::vector<SpvId>& args,
768 OutputStream& out) {
769 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
770 this->writeWord(this->getType(type), out);
771 this->writeWord(id, out);
772 this->writeWord(fGLSLExtendedInstructions, out);
773
774 if (is_float(fContext, type)) {
775 this->writeWord(floatInst, out);
776 } else if (is_signed(fContext, type)) {
777 this->writeWord(signedInst, out);
778 } else if (is_unsigned(fContext, type)) {
779 this->writeWord(unsignedInst, out);
780 } else {
781 ASSERT(false);
782 }
783 for (SpvId a : args) {
784 this->writeWord(a, out);
785 }
786}
787
Greg Daniel64773e62016-11-22 09:44:03 -0500788SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400789 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700790 SpvId result = this->nextId();
791 switch (kind) {
792 case kAtan_SpecialIntrinsic: {
793 std::vector<SpvId> arguments;
794 for (size_t i = 0; i < c.fArguments.size(); i++) {
795 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
796 }
797 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700798 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700799 this->writeWord(result, out);
800 this->writeWord(fGLSLExtendedInstructions, out);
801 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
802 for (SpvId id : arguments) {
803 this->writeWord(id, out);
804 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400805 break;
806 }
807 case kSubpassLoad_SpecialIntrinsic: {
808 SpvId img = this->writeExpression(*c.fArguments[0], out);
809 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700810 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
811 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
812 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400813 SpvId coords = this->writeConstantVector(ctor);
814 if (1 == c.fArguments.size()) {
815 this->writeInstruction(SpvOpImageRead,
816 this->getType(c.fType),
817 result,
818 img,
819 coords,
820 out);
821 } else {
822 ASSERT(2 == c.fArguments.size());
823 SpvId sample = this->writeExpression(*c.fArguments[1], out);
824 this->writeInstruction(SpvOpImageRead,
825 this->getType(c.fType),
826 result,
827 img,
828 coords,
829 SpvImageOperandsSampleMask,
830 sample,
831 out);
832 }
833 break;
834 }
835 case kTexelFetch_SpecialIntrinsic: {
836 ASSERT(c.fArguments.size() == 2);
837 SpvId image = this->nextId();
838 this->writeInstruction(SpvOpImage,
839 this->getImageType(c.fArguments[0]->fType),
840 image,
841 this->writeExpression(*c.fArguments[0], out),
842 out);
843 this->writeInstruction(SpvOpImageFetch,
844 this->getType(c.fType),
845 result,
846 image,
847 this->writeExpression(*c.fArguments[1], out),
848 out);
849 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 }
851 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500852 SpvOp_ op = SpvOpImageSampleImplicitLod;
853 switch (c.fArguments[0]->fType.dimensions()) {
854 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400855 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500856 op = SpvOpImageSampleProjImplicitLod;
857 } else {
858 ASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
859 }
860 break;
861 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400862 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500863 op = SpvOpImageSampleProjImplicitLod;
864 } else {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400865 ASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500866 }
867 break;
868 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400869 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500870 op = SpvOpImageSampleProjImplicitLod;
871 } else {
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400872 ASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500873 }
874 break;
875 case SpvDimCube: // fall through
876 case SpvDimRect: // fall through
877 case SpvDimBuffer: // fall through
878 case SpvDimSubpassData:
879 break;
880 }
ethannicholasd598f792016-07-25 10:08:54 -0700881 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700882 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
883 SpvId uv = this->writeExpression(*c.fArguments[1], out);
884 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500885 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700886 SpvImageOperandsBiasMask,
887 this->writeExpression(*c.fArguments[2], out),
888 out);
889 } else {
890 ASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500891 if (fProgram.fSettings.fSharpenTextures) {
892 FloatLiteral lodBias(fContext, -1, -0.5);
893 this->writeInstruction(op, type, result, sampler, uv,
894 SpvImageOperandsBiasMask,
895 this->writeFloatLiteral(lodBias),
896 out);
897 } else {
898 this->writeInstruction(op, type, result, sampler, uv,
899 out);
900 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700901 }
902 break;
903 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500904 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500905 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
906 ASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500907 const Type& operandType = c.fArguments[0]->fType;
908 SpvOp_ op;
909 if (is_float(fContext, operandType)) {
910 op = SpvOpFMod;
911 } else if (is_signed(fContext, operandType)) {
912 op = SpvOpSMod;
913 } else if (is_unsigned(fContext, operandType)) {
914 op = SpvOpUMod;
915 } else {
916 ASSERT(false);
917 return 0;
918 }
919 this->writeOpCode(op, 5, out);
920 this->writeWord(this->getType(operandType), out);
921 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500922 this->writeWord(args[0], out);
923 this->writeWord(args[1], out);
924 break;
925 }
926 case kClamp_SpecialIntrinsic: {
927 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
928 ASSERT(args.size() == 3);
929 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
930 GLSLstd450UClamp, args, out);
931 break;
932 }
933 case kMax_SpecialIntrinsic: {
934 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
935 ASSERT(args.size() == 2);
936 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
937 GLSLstd450UMax, args, out);
938 break;
939 }
940 case kMin_SpecialIntrinsic: {
941 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
942 ASSERT(args.size() == 2);
943 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
944 GLSLstd450UMin, args, out);
945 break;
946 }
947 case kMix_SpecialIntrinsic: {
948 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
949 ASSERT(args.size() == 3);
950 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
951 SpvOpUndef, args, out);
952 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500953 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700954 }
955 return result;
956}
957
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400958SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700959 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 if (entry == fFunctionMap.end()) {
961 return this->writeIntrinsicCall(c, out);
962 }
963 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
964 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
965 std::vector<SpvId> arguments;
966 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500967 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700968 // passed directly
969 SpvId tmpVar;
970 // if we need a temporary var to store this argument, this is the value to store in the var
971 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700972 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
974 SpvId ptr = lv->getPointer();
975 if (ptr) {
976 arguments.push_back(ptr);
977 continue;
978 } else {
979 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
980 // copy it into a temp, call the function, read the value out of the temp, and then
981 // update the lvalue.
982 tmpValueId = lv->load(out);
983 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700984 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -0700985 std::move(lv)));
986 }
987 } else {
988 // see getFunctionType for an explanation of why we're always using pointer parameters
989 tmpValueId = this->writeExpression(*c.fArguments[i], out);
990 tmpVar = this->nextId();
991 }
Greg Daniel64773e62016-11-22 09:44:03 -0500992 this->writeInstruction(SpvOpVariable,
993 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700994 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -0500995 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -0700996 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -0700997 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700998 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
999 arguments.push_back(tmpVar);
1000 }
1001 SpvId result = this->nextId();
1002 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001003 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 this->writeWord(result, out);
1005 this->writeWord(entry->second, out);
1006 for (SpvId id : arguments) {
1007 this->writeWord(id, out);
1008 }
1009 // now that the call is complete, we may need to update some lvalues with the new values of out
1010 // arguments
1011 for (const auto& tuple : lvalues) {
1012 SpvId load = this->nextId();
1013 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1014 std::get<2>(tuple)->store(load, out);
1015 }
1016 return result;
1017}
1018
ethannicholasf789b382016-08-03 12:43:36 -07001019SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001020 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 SpvId result = this->nextId();
1022 std::vector<SpvId> arguments;
1023 for (size_t i = 0; i < c.fArguments.size(); i++) {
1024 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1025 }
ethannicholasd598f792016-07-25 10:08:54 -07001026 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 if (c.fArguments.size() == 1) {
1028 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001029 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001030 this->writeWord(type, fConstantBuffer);
1031 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001032 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 this->writeWord(arguments[0], fConstantBuffer);
1034 }
1035 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001036 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001037 fConstantBuffer);
1038 this->writeWord(type, fConstantBuffer);
1039 this->writeWord(result, fConstantBuffer);
1040 for (SpvId id : arguments) {
1041 this->writeWord(id, fConstantBuffer);
1042 }
1043 }
1044 return result;
1045}
1046
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001047SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001048 ASSERT(c.fType.isFloat());
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001050 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 SpvId result = this->nextId();
1052 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001053 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001054 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001056 } else {
1057 ASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001058 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001060 }
1061 return result;
1062}
1063
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001064SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001065 ASSERT(c.fType.isSigned());
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001067 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001068 SpvId result = this->nextId();
1069 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001070 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001071 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001072 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001073 }
1074 else {
1075 ASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001076 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001078 }
1079 return result;
1080}
1081
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001082SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001083 ASSERT(c.fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001084 ASSERT(c.fArguments.size() == 1);
1085 ASSERT(c.fArguments[0]->fType.isNumber());
1086 SpvId result = this->nextId();
1087 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001088 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001089 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1090 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001091 } else {
1092 ASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001093 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1094 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001095 }
1096 return result;
1097}
1098
Ethan Nicholas84645e32017-02-09 13:57:14 -05001099void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001100 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001101 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001102 SpvId zeroId = this->writeFloatLiteral(zero);
1103 std::vector<SpvId> columnIds;
1104 for (int column = 0; column < type.columns(); column++) {
1105 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1106 out);
1107 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1108 out);
1109 SpvId columnId = this->nextId();
1110 this->writeWord(columnId, out);
1111 columnIds.push_back(columnId);
1112 for (int row = 0; row < type.columns(); row++) {
1113 this->writeWord(row == column ? diagonal : zeroId, out);
1114 }
1115 }
1116 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1117 out);
1118 this->writeWord(this->getType(type), out);
1119 this->writeWord(id, out);
1120 for (SpvId id : columnIds) {
1121 this->writeWord(id, out);
1122 }
1123}
1124
1125void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001126 const Type& dstType, OutputStream& out) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001127 ASSERT(srcType.kind() == Type::kMatrix_Kind);
1128 ASSERT(dstType.kind() == Type::kMatrix_Kind);
1129 ASSERT(srcType.componentType() == dstType.componentType());
1130 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1131 srcType.rows(),
1132 1));
1133 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1134 dstType.rows(),
1135 1));
1136 SpvId zeroId;
1137 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001138 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001139 zeroId = this->writeFloatLiteral(zero);
1140 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001141 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001142 zeroId = this->writeIntLiteral(zero);
1143 } else {
1144 ABORT("unsupported matrix component type");
1145 }
1146 SpvId zeroColumn = 0;
1147 SpvId columns[4];
1148 for (int i = 0; i < dstType.columns(); i++) {
1149 if (i < srcType.columns()) {
1150 // we're still inside the src matrix, copy the column
1151 SpvId srcColumn = this->nextId();
1152 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
1153 SpvId dstColumn;
1154 if (srcType.rows() == dstType.rows()) {
1155 // columns are equal size, don't need to do anything
1156 dstColumn = srcColumn;
1157 }
1158 else if (dstType.rows() > srcType.rows()) {
1159 // dst column is bigger, need to zero-pad it
1160 dstColumn = this->nextId();
1161 int delta = dstType.rows() - srcType.rows();
1162 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1163 this->writeWord(dstColumnType, out);
1164 this->writeWord(dstColumn, out);
1165 this->writeWord(srcColumn, out);
1166 for (int i = 0; i < delta; ++i) {
1167 this->writeWord(zeroId, out);
1168 }
1169 }
1170 else {
1171 // dst column is smaller, need to swizzle the src column
1172 dstColumn = this->nextId();
1173 int count = dstType.rows();
1174 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1175 this->writeWord(dstColumnType, out);
1176 this->writeWord(dstColumn, out);
1177 this->writeWord(srcColumn, out);
1178 this->writeWord(srcColumn, out);
1179 for (int i = 0; i < count; i++) {
1180 this->writeWord(i, out);
1181 }
1182 }
1183 columns[i] = dstColumn;
1184 } else {
1185 // we're past the end of the src matrix, need a vector of zeroes
1186 if (!zeroColumn) {
1187 zeroColumn = this->nextId();
1188 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1189 this->writeWord(dstColumnType, out);
1190 this->writeWord(zeroColumn, out);
1191 for (int i = 0; i < dstType.rows(); ++i) {
1192 this->writeWord(zeroId, out);
1193 }
1194 }
1195 columns[i] = zeroColumn;
1196 }
1197 }
1198 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1199 this->writeWord(this->getType(dstType), out);
1200 this->writeWord(id, out);
1201 for (int i = 0; i < dstType.columns(); i++) {
1202 this->writeWord(columns[i], out);
1203 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05001204}
1205
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001206SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001207 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001208 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1209 // an instruction
1210 std::vector<SpvId> arguments;
1211 for (size_t i = 0; i < c.fArguments.size(); i++) {
1212 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1213 }
1214 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001215 int rows = c.fType.rows();
1216 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001217 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1218 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1219 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1220 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001221 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
1222 ASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1223 ASSERT(c.fArguments[0]->fType.columns() == 4);
1224 SpvId componentType = this->getType(c.fType.componentType());
1225 SpvId v[4];
1226 for (int i = 0; i < 4; ++i) {
1227 v[i] = this->nextId();
1228 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1229 }
1230 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1231 SpvId column1 = this->nextId();
1232 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1233 SpvId column2 = this->nextId();
1234 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1235 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1236 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001237 } else {
1238 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001239 // ids of vectors and scalars we have written to the current column so far
1240 std::vector<SpvId> currentColumn;
1241 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001242 int currentCount = 0;
1243 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001244 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
1245 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1246 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001247 ASSERT(currentCount == 0);
1248 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001249 } else {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001250 currentColumn.push_back(arguments[i]);
1251 currentCount += c.fArguments[i]->fType.columns();
1252 if (currentCount == rows) {
1253 currentCount = 0;
1254 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn.size(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001255 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1256 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001257 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001258 SpvId columnId = this->nextId();
1259 this->writeWord(columnId, out);
1260 columnIds.push_back(columnId);
1261 for (SpvId id : currentColumn) {
1262 this->writeWord(id, out);
1263 }
1264 currentColumn.clear();
ethannicholasb3058bd2016-07-01 08:22:01 -07001265 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001266 ASSERT(currentCount < rows);
ethannicholasb3058bd2016-07-01 08:22:01 -07001267 }
1268 }
1269 ASSERT(columnIds.size() == (size_t) columns);
1270 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001271 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001272 this->writeWord(result, out);
1273 for (SpvId id : columnIds) {
1274 this->writeWord(id, out);
1275 }
1276 }
1277 return result;
1278}
1279
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001280SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001281 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001282 if (c.isConstant()) {
1283 return this->writeConstantVector(c);
1284 }
1285 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1286 // an instruction
1287 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001288 for (size_t i = 0; i < c.fArguments.size(); i++) {
1289 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1290 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1291 // extract the components and convert them in that case manually. On top of that,
1292 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1293 // doesn't handle vector arguments at all, so we always extract vector components and
1294 // pass them into OpCreateComposite individually.
1295 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1296 SpvOp_ op = SpvOpUndef;
1297 const Type& src = c.fArguments[i]->fType.componentType();
1298 const Type& dst = c.fType.componentType();
1299 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1300 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1301 if (c.fArguments.size() == 1) {
1302 return vec;
1303 }
1304 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1305 op = SpvOpConvertSToF;
1306 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1307 op = SpvOpConvertUToF;
1308 } else {
1309 ASSERT(false);
1310 }
1311 } else if (dst == *fContext.fInt_Type || dst == *fContext.fShort_Type) {
1312 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1313 op = SpvOpConvertFToS;
1314 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1315 if (c.fArguments.size() == 1) {
1316 return vec;
1317 }
1318 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1319 op = SpvOpBitcast;
1320 } else {
1321 ASSERT(false);
1322 }
1323 } else if (dst == *fContext.fUInt_Type || dst == *fContext.fUShort_Type) {
1324 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1325 op = SpvOpConvertFToS;
1326 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1327 op = SpvOpBitcast;
1328 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1329 if (c.fArguments.size() == 1) {
1330 return vec;
1331 }
1332 } else {
1333 ASSERT(false);
1334 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001335 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001336 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1337 SpvId swizzle = this->nextId();
1338 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1339 out);
1340 if (op != SpvOpUndef) {
1341 SpvId cast = this->nextId();
1342 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1343 arguments.push_back(cast);
1344 } else {
1345 arguments.push_back(swizzle);
1346 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001347 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001348 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001349 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1350 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001351 }
1352 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001353 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1354 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1355 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001356 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001357 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001358 this->writeWord(arguments[0], out);
1359 }
1360 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001361 ASSERT(arguments.size() > 1);
1362 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001363 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001364 this->writeWord(result, out);
1365 for (SpvId id : arguments) {
1366 this->writeWord(id, out);
1367 }
1368 }
1369 return result;
1370}
1371
Ethan Nicholasbd553222017-07-18 15:54:59 -04001372SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
1373 ASSERT(c.fType.kind() == Type::kArray_Kind);
1374 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1375 // an instruction
1376 std::vector<SpvId> arguments;
1377 for (size_t i = 0; i < c.fArguments.size(); i++) {
1378 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1379 }
1380 SpvId result = this->nextId();
1381 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1382 this->writeWord(this->getType(c.fType), out);
1383 this->writeWord(result, out);
1384 for (SpvId id : arguments) {
1385 this->writeWord(id, out);
1386 }
1387 return result;
1388}
1389
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001390SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001391 if (c.fArguments.size() == 1 &&
1392 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1393 return this->writeExpression(*c.fArguments[0], out);
1394 }
1395 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001396 return this->writeFloatConstructor(c, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001397 } else if (c.fType == *fContext.fInt_Type || c.fType == *fContext.fShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001398 return this->writeIntConstructor(c, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001399 } else if (c.fType == *fContext.fUInt_Type || c.fType == *fContext.fUShort_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001400 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001401 }
ethannicholasd598f792016-07-25 10:08:54 -07001402 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001403 case Type::kVector_Kind:
1404 return this->writeVectorConstructor(c, out);
1405 case Type::kMatrix_Kind:
1406 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001407 case Type::kArray_Kind:
1408 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001409 default:
1410 ABORT("unsupported constructor: %s", c.description().c_str());
1411 }
1412}
1413
1414SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1415 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001416 ASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001417 return SpvStorageClassInput;
1418 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001419 ASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001420 return SpvStorageClassOutput;
1421 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001422 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001423 return SpvStorageClassPushConstant;
1424 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001425 return SpvStorageClassUniform;
1426 } else {
1427 return SpvStorageClassFunction;
1428 }
1429}
1430
ethannicholasf789b382016-08-03 12:43:36 -07001431SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001432 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001433 case Expression::kVariableReference_Kind: {
1434 const Variable& var = ((VariableReference&) expr).fVariable;
1435 if (var.fStorage != Variable::kGlobal_Storage) {
1436 return SpvStorageClassFunction;
1437 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001438 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1439 if (result == SpvStorageClassFunction) {
1440 result = SpvStorageClassPrivate;
1441 }
1442 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001443 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001444 case Expression::kFieldAccess_Kind:
1445 return get_storage_class(*((FieldAccess&) expr).fBase);
1446 case Expression::kIndex_Kind:
1447 return get_storage_class(*((IndexExpression&) expr).fBase);
1448 default:
1449 return SpvStorageClassFunction;
1450 }
1451}
1452
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001453std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 std::vector<SpvId> chain;
1455 switch (expr.fKind) {
1456 case Expression::kIndex_Kind: {
1457 IndexExpression& indexExpr = (IndexExpression&) expr;
1458 chain = this->getAccessChain(*indexExpr.fBase, out);
1459 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1460 break;
1461 }
1462 case Expression::kFieldAccess_Kind: {
1463 FieldAccess& fieldExpr = (FieldAccess&) expr;
1464 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001465 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 chain.push_back(this->writeIntLiteral(index));
1467 break;
1468 }
1469 default:
1470 chain.push_back(this->getLValue(expr, out)->getPointer());
1471 }
1472 return chain;
1473}
1474
1475class PointerLValue : public SPIRVCodeGenerator::LValue {
1476public:
Greg Daniel64773e62016-11-22 09:44:03 -05001477 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 : fGen(gen)
1479 , fPointer(pointer)
1480 , fType(type) {}
1481
1482 virtual SpvId getPointer() override {
1483 return fPointer;
1484 }
1485
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001486 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 SpvId result = fGen.nextId();
1488 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1489 return result;
1490 }
1491
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001492 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001493 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1494 }
1495
1496private:
1497 SPIRVCodeGenerator& fGen;
1498 const SpvId fPointer;
1499 const SpvId fType;
1500};
1501
1502class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1503public:
Greg Daniel64773e62016-11-22 09:44:03 -05001504 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 const Type& baseType, const Type& swizzleType)
1506 : fGen(gen)
1507 , fVecPointer(vecPointer)
1508 , fComponents(components)
1509 , fBaseType(baseType)
1510 , fSwizzleType(swizzleType) {}
1511
1512 virtual SpvId getPointer() override {
1513 return 0;
1514 }
1515
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001516 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 SpvId base = fGen.nextId();
1518 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1519 SpvId result = fGen.nextId();
1520 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1521 fGen.writeWord(fGen.getType(fSwizzleType), out);
1522 fGen.writeWord(result, out);
1523 fGen.writeWord(base, out);
1524 fGen.writeWord(base, out);
1525 for (int component : fComponents) {
1526 fGen.writeWord(component, out);
1527 }
1528 return result;
1529 }
1530
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001531 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001532 // use OpVectorShuffle to mix and match the vector components. We effectively create
1533 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001534 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001535 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001536 // float3L = ...;
1537 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001539 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1541 // (3, 1, 4).
1542 SpvId base = fGen.nextId();
1543 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1544 SpvId shuffle = fGen.nextId();
1545 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1546 fGen.writeWord(fGen.getType(fBaseType), out);
1547 fGen.writeWord(shuffle, out);
1548 fGen.writeWord(base, out);
1549 fGen.writeWord(value, out);
1550 for (int i = 0; i < fBaseType.columns(); i++) {
1551 // current offset into the virtual vector, defaults to pulling the unmodified
1552 // value from the left side
1553 int offset = i;
1554 // check to see if we are writing this component
1555 for (size_t j = 0; j < fComponents.size(); j++) {
1556 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001557 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001558 // the correct component of the right side instead of preserving the
1559 // value from the left
1560 offset = (int) (j + fBaseType.columns());
1561 break;
1562 }
1563 }
1564 fGen.writeWord(offset, out);
1565 }
1566 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1567 }
1568
1569private:
1570 SPIRVCodeGenerator& fGen;
1571 const SpvId fVecPointer;
1572 const std::vector<int>& fComponents;
1573 const Type& fBaseType;
1574 const Type& fSwizzleType;
1575};
1576
Greg Daniel64773e62016-11-22 09:44:03 -05001577std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001578 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001579 switch (expr.fKind) {
1580 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001581 const Variable& var = ((VariableReference&) expr).fVariable;
1582 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 ASSERT(entry != fVariableMap.end());
1584 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001585 *this,
1586 entry->second,
1587 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 }
1589 case Expression::kIndex_Kind: // fall through
1590 case Expression::kFieldAccess_Kind: {
1591 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1592 SpvId member = this->nextId();
1593 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001594 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 this->writeWord(member, out);
1596 for (SpvId idx : chain) {
1597 this->writeWord(idx, out);
1598 }
1599 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001600 *this,
1601 member,
1602 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001604 case Expression::kSwizzle_Kind: {
1605 Swizzle& swizzle = (Swizzle&) expr;
1606 size_t count = swizzle.fComponents.size();
1607 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1608 ASSERT(base);
1609 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001610 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001611 SpvId member = this->nextId();
1612 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001613 this->getPointerType(swizzle.fType,
1614 get_storage_class(*swizzle.fBase)),
1615 member,
1616 base,
1617 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001618 out);
1619 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1620 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001621 member,
ethannicholasd598f792016-07-25 10:08:54 -07001622 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 } else {
1624 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001625 *this,
1626 base,
1627 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001628 swizzle.fBase->fType,
1629 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001630 }
1631 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001632 case Expression::kTernary_Kind: {
1633 TernaryExpression& t = (TernaryExpression&) expr;
1634 SpvId test = this->writeExpression(*t.fTest, out);
1635 SpvId end = this->nextId();
1636 SpvId ifTrueLabel = this->nextId();
1637 SpvId ifFalseLabel = this->nextId();
1638 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1639 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1640 this->writeLabel(ifTrueLabel, out);
1641 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
1642 ASSERT(ifTrue);
1643 this->writeInstruction(SpvOpBranch, end, out);
1644 ifTrueLabel = fCurrentBlock;
1645 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
1646 ASSERT(ifFalse);
1647 ifFalseLabel = fCurrentBlock;
1648 this->writeInstruction(SpvOpBranch, end, out);
1649 SpvId result = this->nextId();
1650 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1651 ifTrueLabel, ifFalse, ifFalseLabel, out);
1652 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1653 *this,
1654 result,
1655 this->getType(expr.fType)));
1656 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 default:
1658 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001659 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001660 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1661 // caught by IRGenerator
1662 SpvId result = this->nextId();
1663 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001664 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1665 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001666 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1667 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1668 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001669 result,
ethannicholasd598f792016-07-25 10:08:54 -07001670 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001671 }
1672}
1673
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001674SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001675 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001676 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001677 ASSERT(entry != fVariableMap.end());
1678 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001679 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001680 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1681 fProgram.fSettings.fFlipY) {
1682 // need to remap to a top-left coordinate system
1683 if (fRTHeightStructId == (SpvId) -1) {
1684 // height variable hasn't been written yet
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001685 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001686 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
1687 std::vector<Type::Field> fields;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001688 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1689 StringFragment name("sksl_synthetic_uniforms");
1690 Type intfStruct(-1, name, fields);
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001691 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1692 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
1693 StringFragment());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001694 Variable* intfVar = new Variable(-1,
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001695 Modifiers(layout, Modifiers::kUniform_Flag),
1696 name,
1697 intfStruct,
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001698 Variable::kGlobal_Storage);
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001699 fSynthetics.takeOwnership(intfVar);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001700 InterfaceBlock intf(-1, intfVar, name, String(""),
Ethan Nicholas50afc172017-02-16 14:49:57 -05001701 std::vector<std::unique_ptr<Expression>>(), st);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001702 fRTHeightStructId = this->writeInterfaceBlock(intf);
1703 fRTHeightFieldIndex = 0;
1704 }
1705 ASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001706 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001707 SpvId xId = this->nextId();
1708 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1709 result, 0, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001710 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001711 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001712 SpvId heightPtr = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001713 this->writeOpCode(SpvOpAccessChain, 5, out);
1714 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001715 this->writeWord(heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001716 this->writeWord(fRTHeightStructId, out);
1717 this->writeWord(fieldIndexId, out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001718 SpvId heightRead = this->nextId();
1719 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1720 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001721 SpvId rawYId = this->nextId();
1722 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1723 result, 1, out);
1724 SpvId flippedYId = this->nextId();
1725 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1726 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001727 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001728 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001729 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001730 SpvId oneId = writeFloatLiteral(one);
1731 SpvId flipped = this->nextId();
1732 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001733 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001734 this->writeWord(flipped, out);
1735 this->writeWord(xId, out);
1736 this->writeWord(flippedYId, out);
1737 this->writeWord(zeroId, out);
1738 this->writeWord(oneId, out);
1739 return flipped;
1740 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001741 return result;
1742}
1743
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001744SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001745 return getLValue(expr, out)->load(out);
1746}
1747
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001748SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 return getLValue(f, out)->load(out);
1750}
1751
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001752SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 SpvId base = this->writeExpression(*swizzle.fBase, out);
1754 SpvId result = this->nextId();
1755 size_t count = swizzle.fComponents.size();
1756 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001757 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1758 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 } else {
1760 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001761 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 this->writeWord(result, out);
1763 this->writeWord(base, out);
1764 this->writeWord(base, out);
1765 for (int component : swizzle.fComponents) {
1766 this->writeWord(component, out);
1767 }
1768 }
1769 return result;
1770}
1771
Greg Daniel64773e62016-11-22 09:44:03 -05001772SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1773 const Type& operandType, SpvId lhs,
1774 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001775 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001777 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001778 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001779 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001780 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001781 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001782 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001783 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1785 } else {
1786 ABORT("invalid operandType: %s", operandType.description().c_str());
1787 }
1788 return result;
1789}
1790
1791bool is_assignment(Token::Kind op) {
1792 switch (op) {
1793 case Token::EQ: // fall through
1794 case Token::PLUSEQ: // fall through
1795 case Token::MINUSEQ: // fall through
1796 case Token::STAREQ: // fall through
1797 case Token::SLASHEQ: // fall through
1798 case Token::PERCENTEQ: // fall through
1799 case Token::SHLEQ: // fall through
1800 case Token::SHREQ: // fall through
1801 case Token::BITWISEOREQ: // fall through
1802 case Token::BITWISEXOREQ: // fall through
1803 case Token::BITWISEANDEQ: // fall through
1804 case Token::LOGICALOREQ: // fall through
1805 case Token::LOGICALXOREQ: // fall through
1806 case Token::LOGICALANDEQ:
1807 return true;
1808 default:
1809 return false;
1810 }
1811}
1812
Ethan Nicholas48e24052018-03-14 13:51:39 -04001813SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1814 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001815 if (operandType.kind() == Type::kVector_Kind) {
1816 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001817 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001818 return result;
1819 }
1820 return id;
1821}
1822
Ethan Nicholas68990be2017-07-13 09:36:52 -04001823SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1824 SpvOp_ floatOperator, SpvOp_ intOperator,
1825 OutputStream& out) {
1826 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
1827 ASSERT(operandType.kind() == Type::kMatrix_Kind);
1828 SpvId rowType = this->getType(operandType.componentType().toCompound(fContext,
1829 operandType.columns(),
1830 1));
1831 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
1832 operandType.columns(),
1833 1));
1834 SpvId boolType = this->getType(*fContext.fBool_Type);
1835 SpvId result = 0;
1836 for (int i = 0; i < operandType.rows(); i++) {
1837 SpvId rowL = this->nextId();
1838 this->writeInstruction(SpvOpCompositeExtract, rowType, rowL, lhs, 0, out);
1839 SpvId rowR = this->nextId();
1840 this->writeInstruction(SpvOpCompositeExtract, rowType, rowR, rhs, 0, out);
1841 SpvId compare = this->nextId();
1842 this->writeInstruction(compareOp, bvecType, compare, rowL, rowR, out);
1843 SpvId all = this->nextId();
1844 this->writeInstruction(SpvOpAll, boolType, all, compare, out);
1845 if (result != 0) {
1846 SpvId next = this->nextId();
1847 this->writeInstruction(SpvOpLogicalAnd, boolType, next, result, all, out);
1848 result = next;
1849 }
1850 else {
1851 result = all;
1852 }
1853 }
1854 return result;
1855}
1856
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001857SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 // handle cases where we don't necessarily evaluate both LHS and RHS
1859 switch (b.fOperator) {
1860 case Token::EQ: {
1861 SpvId rhs = this->writeExpression(*b.fRight, out);
1862 this->getLValue(*b.fLeft, out)->store(rhs, out);
1863 return rhs;
1864 }
1865 case Token::LOGICALAND:
1866 return this->writeLogicalAnd(b, out);
1867 case Token::LOGICALOR:
1868 return this->writeLogicalOr(b, out);
1869 default:
1870 break;
1871 }
1872
1873 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001874 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001875 std::unique_ptr<LValue> lvalue;
1876 SpvId lhs;
1877 if (is_assignment(b.fOperator)) {
1878 lvalue = this->getLValue(*b.fLeft, out);
1879 lhs = lvalue->load(out);
1880 } else {
1881 lvalue = nullptr;
1882 lhs = this->writeExpression(*b.fLeft, out);
1883 }
1884 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04001885 if (b.fOperator == Token::COMMA) {
1886 return rhs;
1887 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001888 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04001889 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07001890 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001891 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
1892 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001893 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05001894 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001895 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001896 // promote number to vector
1897 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001898 const Type& vecType = b.fLeft->fType;
1899 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1900 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001901 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001902 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001903 this->writeWord(rhs, out);
1904 }
1905 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001906 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05001907 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001908 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001909 // promote number to vector
1910 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001911 const Type& vecType = b.fRight->fType;
1912 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1913 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001915 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 this->writeWord(lhs, out);
1917 }
1918 lhs = vec;
1919 ASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001920 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07001921 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001923 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001925 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001926 op = SpvOpMatrixTimesVector;
1927 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001928 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001929 op = SpvOpMatrixTimesScalar;
1930 }
1931 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001932 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001933 if (b.fOperator == Token::STAREQ) {
1934 lvalue->store(result, out);
1935 } else {
1936 ASSERT(b.fOperator == Token::STAR);
1937 }
1938 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001939 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001940 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001941 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05001942 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001943 lhs, rhs, out);
1944 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001945 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05001946 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001947 lhs, out);
1948 }
1949 if (b.fOperator == Token::STAREQ) {
1950 lvalue->store(result, out);
1951 } else {
1952 ASSERT(b.fOperator == Token::STAR);
1953 }
1954 return result;
1955 } else {
1956 ABORT("unsupported binary expression: %s", b.description().c_str());
1957 }
1958 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001959 tmp = this->getActualType(b.fLeft->fType);
1960 operandType = &tmp;
1961 ASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001962 }
1963 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001964 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04001965 if (operandType->kind() == Type::kMatrix_Kind) {
1966 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
1967 SpvOpIEqual, out);
1968 }
ethannicholasd598f792016-07-25 10:08:54 -07001969 ASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001970 const Type* tmpType;
1971 if (operandType->kind() == Type::kVector_Kind) {
1972 tmpType = &fContext.fBool_Type->toCompound(fContext,
1973 operandType->columns(),
1974 operandType->rows());
1975 } else {
1976 tmpType = &resultType;
1977 }
1978 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05001979 SpvOpFOrdEqual, SpvOpIEqual,
1980 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04001981 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001982 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001983 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04001984 if (operandType->kind() == Type::kMatrix_Kind) {
1985 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
1986 SpvOpINotEqual, out);
1987 }
ethannicholasd598f792016-07-25 10:08:54 -07001988 ASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001989 const Type* tmpType;
1990 if (operandType->kind() == Type::kVector_Kind) {
1991 tmpType = &fContext.fBool_Type->toCompound(fContext,
1992 operandType->columns(),
1993 operandType->rows());
1994 } else {
1995 tmpType = &resultType;
1996 }
1997 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05001998 SpvOpFOrdNotEqual, SpvOpINotEqual,
1999 SpvOpINotEqual, SpvOpLogicalNotEqual,
2000 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002001 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002002 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07002003 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002004 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2005 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 SpvOpUGreaterThan, SpvOpUndef, out);
2007 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07002008 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002009 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2011 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002012 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002013 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2014 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002015 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2016 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002017 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002018 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2019 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 SpvOpULessThanEqual, SpvOpUndef, out);
2021 case Token::PLUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002022 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002023 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2024 case Token::MINUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002025 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002026 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2027 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002028 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002029 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 // matrix multiply
2031 SpvId result = this->nextId();
2032 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2033 lhs, rhs, out);
2034 return result;
2035 }
Greg Daniel64773e62016-11-22 09:44:03 -05002036 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002037 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2038 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002039 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002041 case Token::PERCENT:
2042 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2043 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002044 case Token::SHL:
2045 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2046 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2047 SpvOpUndef, out);
2048 case Token::SHR:
2049 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2050 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2051 SpvOpUndef, out);
2052 case Token::BITWISEAND:
2053 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2054 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2055 case Token::BITWISEOR:
2056 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2057 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2058 case Token::BITWISEXOR:
2059 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2060 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002061 case Token::PLUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002062 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002063 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2064 ASSERT(lvalue);
2065 lvalue->store(result, out);
2066 return result;
2067 }
2068 case Token::MINUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002069 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002070 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2071 ASSERT(lvalue);
2072 lvalue->store(result, out);
2073 return result;
2074 }
2075 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002076 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002077 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002078 // matrix multiply
2079 SpvId result = this->nextId();
2080 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2081 lhs, rhs, out);
2082 ASSERT(lvalue);
2083 lvalue->store(result, out);
2084 return result;
2085 }
Greg Daniel64773e62016-11-22 09:44:03 -05002086 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2088 ASSERT(lvalue);
2089 lvalue->store(result, out);
2090 return result;
2091 }
2092 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002093 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2095 ASSERT(lvalue);
2096 lvalue->store(result, out);
2097 return result;
2098 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002099 case Token::PERCENTEQ: {
2100 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2101 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
2102 ASSERT(lvalue);
2103 lvalue->store(result, out);
2104 return result;
2105 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002106 case Token::SHLEQ: {
2107 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2108 SpvOpUndef, SpvOpShiftLeftLogical,
2109 SpvOpShiftLeftLogical, SpvOpUndef, out);
2110 ASSERT(lvalue);
2111 lvalue->store(result, out);
2112 return result;
2113 }
2114 case Token::SHREQ: {
2115 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2116 SpvOpUndef, SpvOpShiftRightArithmetic,
2117 SpvOpShiftRightLogical, SpvOpUndef, out);
2118 ASSERT(lvalue);
2119 lvalue->store(result, out);
2120 return result;
2121 }
2122 case Token::BITWISEANDEQ: {
2123 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2124 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2125 SpvOpUndef, out);
2126 ASSERT(lvalue);
2127 lvalue->store(result, out);
2128 return result;
2129 }
2130 case Token::BITWISEOREQ: {
2131 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2132 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2133 SpvOpUndef, out);
2134 ASSERT(lvalue);
2135 lvalue->store(result, out);
2136 return result;
2137 }
2138 case Token::BITWISEXOREQ: {
2139 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2140 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2141 SpvOpUndef, out);
2142 ASSERT(lvalue);
2143 lvalue->store(result, out);
2144 return result;
2145 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002146 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 ABORT("unsupported binary expression: %s", b.description().c_str());
2148 }
2149}
2150
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002151SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 ASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002153 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002154 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2155 SpvId lhs = this->writeExpression(*a.fLeft, out);
2156 SpvId rhsLabel = this->nextId();
2157 SpvId end = this->nextId();
2158 SpvId lhsBlock = fCurrentBlock;
2159 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2160 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2161 this->writeLabel(rhsLabel, out);
2162 SpvId rhs = this->writeExpression(*a.fRight, out);
2163 SpvId rhsBlock = fCurrentBlock;
2164 this->writeInstruction(SpvOpBranch, end, out);
2165 this->writeLabel(end, out);
2166 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002167 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002168 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 return result;
2170}
2171
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002172SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 ASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002174 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002175 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2176 SpvId lhs = this->writeExpression(*o.fLeft, out);
2177 SpvId rhsLabel = this->nextId();
2178 SpvId end = this->nextId();
2179 SpvId lhsBlock = fCurrentBlock;
2180 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2181 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2182 this->writeLabel(rhsLabel, out);
2183 SpvId rhs = this->writeExpression(*o.fRight, out);
2184 SpvId rhsBlock = fCurrentBlock;
2185 this->writeInstruction(SpvOpBranch, end, out);
2186 this->writeLabel(end, out);
2187 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002188 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002189 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 return result;
2191}
2192
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002193SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002194 SpvId test = this->writeExpression(*t.fTest, out);
2195 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2196 // both true and false are constants, can just use OpSelect
2197 SpvId result = this->nextId();
2198 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2199 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002200 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 out);
2202 return result;
2203 }
Greg Daniel64773e62016-11-22 09:44:03 -05002204 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 // Adreno. Switched to storing the result in a temp variable as glslang does.
2206 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002207 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002208 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 SpvId trueLabel = this->nextId();
2210 SpvId falseLabel = this->nextId();
2211 SpvId end = this->nextId();
2212 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2213 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2214 this->writeLabel(trueLabel, out);
2215 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2216 this->writeInstruction(SpvOpBranch, end, out);
2217 this->writeLabel(falseLabel, out);
2218 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2219 this->writeInstruction(SpvOpBranch, end, out);
2220 this->writeLabel(end, out);
2221 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002222 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002223 return result;
2224}
2225
ethannicholasd598f792016-07-25 10:08:54 -07002226std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002227 if (type.isInteger()) {
2228 return std::unique_ptr<Expression>(new IntLiteral(context, -1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002229 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002230 else if (type.isFloat()) {
2231 return std::unique_ptr<Expression>(new FloatLiteral(context, -1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002233 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002234 }
2235}
2236
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002237SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002238 if (p.fOperator == Token::MINUS) {
2239 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002240 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002242 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002243 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002244 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2246 } else {
2247 ABORT("unsupported prefix expression %s", p.description().c_str());
2248 };
2249 return result;
2250 }
2251 switch (p.fOperator) {
2252 case Token::PLUS:
2253 return this->writeExpression(*p.fOperand, out);
2254 case Token::PLUSPLUS: {
2255 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002256 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002257 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2258 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 out);
2260 lv->store(result, out);
2261 return result;
2262 }
2263 case Token::MINUSMINUS: {
2264 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002265 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002266 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2267 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 out);
2269 lv->store(result, out);
2270 return result;
2271 }
ethannicholas5961bc92016-10-12 06:39:56 -07002272 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002273 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002275 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 this->writeExpression(*p.fOperand, out), out);
2277 return result;
2278 }
ethannicholas5961bc92016-10-12 06:39:56 -07002279 case Token::BITWISENOT: {
2280 SpvId result = this->nextId();
2281 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2282 this->writeExpression(*p.fOperand, out), out);
2283 return result;
2284 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002285 default:
2286 ABORT("unsupported prefix expression: %s", p.description().c_str());
2287 }
2288}
2289
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002290SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2292 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002293 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002294 switch (p.fOperator) {
2295 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002296 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2298 lv->store(temp, out);
2299 return result;
2300 }
2301 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002302 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002303 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2304 lv->store(temp, out);
2305 return result;
2306 }
2307 default:
2308 ABORT("unsupported postfix expression %s", p.description().c_str());
2309 }
2310}
2311
ethannicholasf789b382016-08-03 12:43:36 -07002312SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002313 if (b.fValue) {
2314 if (fBoolTrue == 0) {
2315 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002316 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002317 fConstantBuffer);
2318 }
2319 return fBoolTrue;
2320 } else {
2321 if (fBoolFalse == 0) {
2322 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002323 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002324 fConstantBuffer);
2325 }
2326 return fBoolFalse;
2327 }
2328}
2329
ethannicholasf789b382016-08-03 12:43:36 -07002330SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002331 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002332 auto entry = fIntConstants.find(i.fValue);
2333 if (entry == fIntConstants.end()) {
2334 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002335 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002336 fConstantBuffer);
2337 fIntConstants[i.fValue] = result;
2338 return result;
2339 }
2340 return entry->second;
2341 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002342 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 auto entry = fUIntConstants.find(i.fValue);
2344 if (entry == fUIntConstants.end()) {
2345 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002346 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002347 fConstantBuffer);
2348 fUIntConstants[i.fValue] = result;
2349 return result;
2350 }
2351 return entry->second;
2352 }
2353}
2354
ethannicholasf789b382016-08-03 12:43:36 -07002355SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002356 if (f.fType == *fContext.fFloat_Type || f.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002357 float value = (float) f.fValue;
2358 auto entry = fFloatConstants.find(value);
2359 if (entry == fFloatConstants.end()) {
2360 SpvId result = this->nextId();
2361 uint32_t bits;
2362 ASSERT(sizeof(bits) == sizeof(value));
2363 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002364 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 fConstantBuffer);
2366 fFloatConstants[value] = result;
2367 return result;
2368 }
2369 return entry->second;
2370 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002371 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002372 auto entry = fDoubleConstants.find(f.fValue);
2373 if (entry == fDoubleConstants.end()) {
2374 SpvId result = this->nextId();
2375 uint64_t bits;
2376 ASSERT(sizeof(bits) == sizeof(f.fValue));
2377 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002378 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2380 fDoubleConstants[f.fValue] = result;
2381 return result;
2382 }
2383 return entry->second;
2384 }
2385}
2386
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002387SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002388 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002389 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002390 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002391 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002392 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002393 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002394 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002395 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002396 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002397 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2398 }
2399 return result;
2400}
2401
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002402SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2403 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2405 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002406 if (f.fDeclaration.fName == "main") {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002407 write_stringstream(fGlobalInitializersBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002408 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002409 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002410 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002411 write_stringstream(fVariableBuffer, out);
2412 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002414 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2415 this->writeInstruction(SpvOpReturn, out);
2416 } else {
2417 this->writeInstruction(SpvOpUnreachable, out);
2418 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 }
2420 this->writeInstruction(SpvOpFunctionEnd, out);
2421 return result;
2422}
2423
2424void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2425 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002426 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002427 fDecorationBuffer);
2428 }
2429 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002430 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 fDecorationBuffer);
2432 }
2433 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002434 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002435 fDecorationBuffer);
2436 }
2437 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002438 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 fDecorationBuffer);
2440 }
Greg Daniel64773e62016-11-22 09:44:03 -05002441 if (layout.fInputAttachmentIndex >= 0) {
2442 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2443 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002444 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002445 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002446 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04002447 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002448 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 fDecorationBuffer);
2450 }
2451}
2452
2453void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2454 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002455 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002456 layout.fLocation, fDecorationBuffer);
2457 }
2458 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002459 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002460 layout.fBinding, fDecorationBuffer);
2461 }
2462 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002463 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002464 layout.fIndex, fDecorationBuffer);
2465 }
2466 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002467 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002468 layout.fSet, fDecorationBuffer);
2469 }
Greg Daniel64773e62016-11-22 09:44:03 -05002470 if (layout.fInputAttachmentIndex >= 0) {
2471 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2472 layout.fInputAttachmentIndex, fDecorationBuffer);
2473 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002474 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002475 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 layout.fBuiltin, fDecorationBuffer);
2477 }
2478}
2479
ethannicholasf789b382016-08-03 12:43:36 -07002480SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002481 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002482 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2483 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002484 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2485 MemoryLayout(MemoryLayout::k430_Standard) :
2486 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002488 const Type* type = &intf.fVariable.fType;
2489 if (fProgram.fInputs.fRTHeight) {
2490 ASSERT(fRTHeightStructId == (SpvId) -1);
2491 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
2492 std::vector<Type::Field> fields = type->fields();
2493 fRTHeightStructId = result;
2494 fRTHeightFieldIndex = fields.size();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002495 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2496 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002497 }
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002498 SpvId typeId = this->getType(*type, memoryLayout);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002499 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2500 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
2501 } else {
2502 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2503 }
ethannicholasd598f792016-07-25 10:08:54 -07002504 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002505 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002506 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002507 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002508 Layout layout = intf.fVariable.fModifiers.fLayout;
2509 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2510 layout.fSet = 0;
2511 }
2512 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002513 fVariableMap[&intf.fVariable] = result;
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002514 if (fProgram.fInputs.fRTHeight) {
2515 delete type;
2516 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 return result;
2518}
2519
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002520void SPIRVCodeGenerator::writePrecisionModifier(const Modifiers& modifiers, SpvId id) {
2521 if ((modifiers.fFlags & Modifiers::kLowp_Flag) |
2522 (modifiers.fFlags & Modifiers::kMediump_Flag)) {
2523 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2524 }
2525}
2526
ethannicholas5961bc92016-10-12 06:39:56 -07002527#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002528void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002529 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002530 for (size_t i = 0; i < decl.fVars.size(); i++) {
2531 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2532 continue;
2533 }
2534 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2535 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002536 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2537 // in the OpenGL backend.
2538 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2539 Modifiers::kWriteOnly_Flag |
2540 Modifiers::kCoherent_Flag |
2541 Modifiers::kVolatile_Flag |
2542 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002543 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2544 continue;
2545 }
2546 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2547 kind != Program::kFragment_Kind) {
Brian Salomondc092132018-04-04 10:14:16 -04002548 ASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002549 continue;
2550 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002551 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002552 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2553 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002554 Modifiers::kUniform_Flag |
2555 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002556 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2557 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002558 continue;
2559 }
2560 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002561 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002563 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002564 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002565 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2566 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 storageClass = SpvStorageClassUniformConstant;
2568 } else {
2569 storageClass = SpvStorageClassUniform;
2570 }
2571 } else {
2572 storageClass = SpvStorageClassPrivate;
2573 }
2574 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002575 fVariableMap[var] = id;
2576 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002577 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002578 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002579 this->writePrecisionModifier(var->fModifiers, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002580 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002581 ASSERT(!fCurrentBlock);
2582 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002583 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002584 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002585 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002586 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002587 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002588 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2589 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2590 }
2591 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2592 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2593 fDecorationBuffer);
2594 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002595 }
2596}
2597
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002598void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002599 for (const auto& stmt : decl.fVars) {
2600 ASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
2601 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2602 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002603 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2604 // in the OpenGL backend.
2605 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2606 Modifiers::kWriteOnly_Flag |
2607 Modifiers::kCoherent_Flag |
2608 Modifiers::kVolatile_Flag |
2609 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002611 fVariableMap[var] = id;
2612 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002613 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002614 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002615 if (varDecl.fValue) {
2616 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 this->writeInstruction(SpvOpStore, id, value, out);
2618 }
2619 }
2620}
2621
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002622void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002623 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002624 case Statement::kNop_Kind:
2625 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002626 case Statement::kBlock_Kind:
2627 this->writeBlock((Block&) s, out);
2628 break;
2629 case Statement::kExpression_Kind:
2630 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2631 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002632 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002633 this->writeReturnStatement((ReturnStatement&) s, out);
2634 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002635 case Statement::kVarDeclarations_Kind:
2636 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 break;
2638 case Statement::kIf_Kind:
2639 this->writeIfStatement((IfStatement&) s, out);
2640 break;
2641 case Statement::kFor_Kind:
2642 this->writeForStatement((ForStatement&) s, out);
2643 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002644 case Statement::kWhile_Kind:
2645 this->writeWhileStatement((WhileStatement&) s, out);
2646 break;
2647 case Statement::kDo_Kind:
2648 this->writeDoStatement((DoStatement&) s, out);
2649 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002650 case Statement::kSwitch_Kind:
2651 this->writeSwitchStatement((SwitchStatement&) s, out);
2652 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002653 case Statement::kBreak_Kind:
2654 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2655 break;
2656 case Statement::kContinue_Kind:
2657 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2658 break;
2659 case Statement::kDiscard_Kind:
2660 this->writeInstruction(SpvOpKill, out);
2661 break;
2662 default:
2663 ABORT("unsupported statement: %s", s.description().c_str());
2664 }
2665}
2666
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002667void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002668 for (size_t i = 0; i < b.fStatements.size(); i++) {
2669 this->writeStatement(*b.fStatements[i], out);
2670 }
2671}
2672
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002673void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002674 SpvId test = this->writeExpression(*stmt.fTest, out);
2675 SpvId ifTrue = this->nextId();
2676 SpvId ifFalse = this->nextId();
2677 if (stmt.fIfFalse) {
2678 SpvId end = this->nextId();
2679 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2680 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2681 this->writeLabel(ifTrue, out);
2682 this->writeStatement(*stmt.fIfTrue, out);
2683 if (fCurrentBlock) {
2684 this->writeInstruction(SpvOpBranch, end, out);
2685 }
2686 this->writeLabel(ifFalse, out);
2687 this->writeStatement(*stmt.fIfFalse, out);
2688 if (fCurrentBlock) {
2689 this->writeInstruction(SpvOpBranch, end, out);
2690 }
2691 this->writeLabel(end, out);
2692 } else {
2693 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2694 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2695 this->writeLabel(ifTrue, out);
2696 this->writeStatement(*stmt.fIfTrue, out);
2697 if (fCurrentBlock) {
2698 this->writeInstruction(SpvOpBranch, ifFalse, out);
2699 }
2700 this->writeLabel(ifFalse, out);
2701 }
2702}
2703
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002704void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002705 if (f.fInitializer) {
2706 this->writeStatement(*f.fInitializer, out);
2707 }
2708 SpvId header = this->nextId();
2709 SpvId start = this->nextId();
2710 SpvId body = this->nextId();
2711 SpvId next = this->nextId();
2712 fContinueTarget.push(next);
2713 SpvId end = this->nextId();
2714 fBreakTarget.push(end);
2715 this->writeInstruction(SpvOpBranch, header, out);
2716 this->writeLabel(header, out);
2717 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002718 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002719 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002720 if (f.fTest) {
2721 SpvId test = this->writeExpression(*f.fTest, out);
2722 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2723 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002724 this->writeLabel(body, out);
2725 this->writeStatement(*f.fStatement, out);
2726 if (fCurrentBlock) {
2727 this->writeInstruction(SpvOpBranch, next, out);
2728 }
2729 this->writeLabel(next, out);
2730 if (f.fNext) {
2731 this->writeExpression(*f.fNext, out);
2732 }
2733 this->writeInstruction(SpvOpBranch, header, out);
2734 this->writeLabel(end, out);
2735 fBreakTarget.pop();
2736 fContinueTarget.pop();
2737}
2738
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002739void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002740 // We believe the while loop code below will work, but Skia doesn't actually use them and
2741 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2742 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2743 // message, simply remove the error call below to see whether our while loop support actually
2744 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002745 fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002746 "see SkSLSPIRVCodeGenerator.cpp for details");
2747
2748 SpvId header = this->nextId();
2749 SpvId start = this->nextId();
2750 SpvId body = this->nextId();
2751 fContinueTarget.push(start);
2752 SpvId end = this->nextId();
2753 fBreakTarget.push(end);
2754 this->writeInstruction(SpvOpBranch, header, out);
2755 this->writeLabel(header, out);
2756 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2757 this->writeInstruction(SpvOpBranch, start, out);
2758 this->writeLabel(start, out);
2759 SpvId test = this->writeExpression(*w.fTest, out);
2760 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2761 this->writeLabel(body, out);
2762 this->writeStatement(*w.fStatement, out);
2763 if (fCurrentBlock) {
2764 this->writeInstruction(SpvOpBranch, start, out);
2765 }
2766 this->writeLabel(end, out);
2767 fBreakTarget.pop();
2768 fContinueTarget.pop();
2769}
2770
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002771void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002772 // We believe the do loop code below will work, but Skia doesn't actually use them and
2773 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2774 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2775 // message, simply remove the error call below to see whether our do loop support actually
2776 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002777 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002778 "SkSLSPIRVCodeGenerator.cpp for details");
2779
2780 SpvId header = this->nextId();
2781 SpvId start = this->nextId();
2782 SpvId next = this->nextId();
2783 fContinueTarget.push(next);
2784 SpvId end = this->nextId();
2785 fBreakTarget.push(end);
2786 this->writeInstruction(SpvOpBranch, header, out);
2787 this->writeLabel(header, out);
2788 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2789 this->writeInstruction(SpvOpBranch, start, out);
2790 this->writeLabel(start, out);
2791 this->writeStatement(*d.fStatement, out);
2792 if (fCurrentBlock) {
2793 this->writeInstruction(SpvOpBranch, next, out);
2794 }
2795 this->writeLabel(next, out);
2796 SpvId test = this->writeExpression(*d.fTest, out);
2797 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2798 this->writeLabel(end, out);
2799 fBreakTarget.pop();
2800 fContinueTarget.pop();
2801}
2802
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002803void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2804 SpvId value = this->writeExpression(*s.fValue, out);
2805 std::vector<SpvId> labels;
2806 SpvId end = this->nextId();
2807 SpvId defaultLabel = end;
2808 fBreakTarget.push(end);
2809 int size = 3;
2810 for (const auto& c : s.fCases) {
2811 SpvId label = this->nextId();
2812 labels.push_back(label);
2813 if (c->fValue) {
2814 size += 2;
2815 } else {
2816 defaultLabel = label;
2817 }
2818 }
2819 labels.push_back(end);
2820 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2821 this->writeOpCode(SpvOpSwitch, size, out);
2822 this->writeWord(value, out);
2823 this->writeWord(defaultLabel, out);
2824 for (size_t i = 0; i < s.fCases.size(); ++i) {
2825 if (!s.fCases[i]->fValue) {
2826 continue;
2827 }
2828 ASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
2829 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
2830 this->writeWord(labels[i], out);
2831 }
2832 for (size_t i = 0; i < s.fCases.size(); ++i) {
2833 this->writeLabel(labels[i], out);
2834 for (const auto& stmt : s.fCases[i]->fStatements) {
2835 this->writeStatement(*stmt, out);
2836 }
2837 if (fCurrentBlock) {
2838 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
2839 }
2840 }
2841 this->writeLabel(end, out);
2842 fBreakTarget.pop();
2843}
2844
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002845void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002846 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05002847 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07002848 out);
2849 } else {
2850 this->writeInstruction(SpvOpReturn, out);
2851 }
2852}
2853
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002854void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
2855 ASSERT(fProgram.fKind == Program::kGeometry_Kind);
2856 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002857 for (const auto& e : fProgram) {
2858 if (e.fKind == ProgramElement::kModifiers_Kind) {
2859 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002860 if (m.fFlags & Modifiers::kIn_Flag) {
2861 if (m.fLayout.fInvocations != -1) {
2862 invocations = m.fLayout.fInvocations;
2863 }
2864 SpvId input;
2865 switch (m.fLayout.fPrimitive) {
2866 case Layout::kPoints_Primitive:
2867 input = SpvExecutionModeInputPoints;
2868 break;
2869 case Layout::kLines_Primitive:
2870 input = SpvExecutionModeInputLines;
2871 break;
2872 case Layout::kLinesAdjacency_Primitive:
2873 input = SpvExecutionModeInputLinesAdjacency;
2874 break;
2875 case Layout::kTriangles_Primitive:
2876 input = SpvExecutionModeTriangles;
2877 break;
2878 case Layout::kTrianglesAdjacency_Primitive:
2879 input = SpvExecutionModeInputTrianglesAdjacency;
2880 break;
2881 default:
2882 input = 0;
2883 break;
2884 }
2885 if (input) {
2886 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
2887 }
2888 } else if (m.fFlags & Modifiers::kOut_Flag) {
2889 SpvId output;
2890 switch (m.fLayout.fPrimitive) {
2891 case Layout::kPoints_Primitive:
2892 output = SpvExecutionModeOutputPoints;
2893 break;
2894 case Layout::kLineStrip_Primitive:
2895 output = SpvExecutionModeOutputLineStrip;
2896 break;
2897 case Layout::kTriangleStrip_Primitive:
2898 output = SpvExecutionModeOutputTriangleStrip;
2899 break;
2900 default:
2901 output = 0;
2902 break;
2903 }
2904 if (output) {
2905 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
2906 }
2907 if (m.fLayout.fMaxVertices != -1) {
2908 this->writeInstruction(SpvOpExecutionMode, entryPoint,
2909 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
2910 out);
2911 }
2912 }
2913 }
2914 }
2915 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
2916 invocations, out);
2917}
2918
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002919void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002920 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002921 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05002922 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002923 // assign IDs to functions, determine sk_in size
2924 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002925 for (const auto& e : program) {
2926 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002927 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002928 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002929 fFunctionMap[&f.fDeclaration] = this->nextId();
2930 break;
2931 }
2932 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002933 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002934 if (m.fFlags & Modifiers::kIn_Flag) {
2935 switch (m.fLayout.fPrimitive) {
2936 case Layout::kPoints_Primitive: // break
2937 case Layout::kLines_Primitive:
2938 skInSize = 1;
2939 break;
2940 case Layout::kLinesAdjacency_Primitive: // break
2941 skInSize = 2;
2942 break;
2943 case Layout::kTriangles_Primitive: // break
2944 case Layout::kTrianglesAdjacency_Primitive:
2945 skInSize = 3;
2946 break;
2947 default:
2948 break;
2949 }
2950 }
2951 break;
2952 }
2953 default:
2954 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002955 }
2956 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002957 for (const auto& e : program) {
2958 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
2959 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002960 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
2961 ASSERT(skInSize != -1);
2962 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
2963 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002964 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04002965 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2966 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
2967 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05002968 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002969 }
2970 }
2971 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002972 for (const auto& e : program) {
2973 if (e.fKind == ProgramElement::kVar_Kind) {
2974 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002975 }
2976 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002977 for (const auto& e : program) {
2978 if (e.fKind == ProgramElement::kFunction_Kind) {
2979 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002980 }
2981 }
ethannicholasd598f792016-07-25 10:08:54 -07002982 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002983 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002984 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002985 main = entry.first;
2986 }
2987 }
2988 ASSERT(main);
2989 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002990 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05002991 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04002992 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2993 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) &&
2994 var->fModifiers.fLayout.fBuiltin != SK_IN_BUILTIN &&
2995 var->fModifiers.fLayout.fBuiltin != SK_OUT_BUILTIN) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05002996 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07002997 }
2998 }
2999 this->writeCapabilities(out);
3000 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3001 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003002 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003003 (int32_t) interfaceVars.size(), out);
3004 switch (program.fKind) {
3005 case Program::kVertex_Kind:
3006 this->writeWord(SpvExecutionModelVertex, out);
3007 break;
3008 case Program::kFragment_Kind:
3009 this->writeWord(SpvExecutionModelFragment, out);
3010 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003011 case Program::kGeometry_Kind:
3012 this->writeWord(SpvExecutionModelGeometry, out);
3013 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003014 default:
3015 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003016 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003017 SpvId entryPoint = fFunctionMap[main];
3018 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003019 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003020 for (int var : interfaceVars) {
3021 this->writeWord(var, out);
3022 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003023 if (program.fKind == Program::kGeometry_Kind) {
3024 this->writeGeometryShaderExecutionMode(entryPoint, out);
3025 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003026 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003027 this->writeInstruction(SpvOpExecutionMode,
3028 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003029 SpvExecutionModeOriginUpperLeft,
3030 out);
3031 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003032 for (const auto& e : program) {
3033 if (e.fKind == ProgramElement::kExtension_Kind) {
3034 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003035 }
3036 }
Greg Daniel64773e62016-11-22 09:44:03 -05003037
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003038 write_stringstream(fExtraGlobalsBuffer, out);
3039 write_stringstream(fNameBuffer, out);
3040 write_stringstream(fDecorationBuffer, out);
3041 write_stringstream(fConstantBuffer, out);
3042 write_stringstream(fExternalFunctionsBuffer, out);
3043 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003044}
3045
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003046bool SPIRVCodeGenerator::generateCode() {
3047 ASSERT(!fErrors.errorCount());
3048 this->writeWord(SpvMagicNumber, *fOut);
3049 this->writeWord(SpvVersion, *fOut);
3050 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003051 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003052 this->writeInstructions(fProgram, buffer);
3053 this->writeWord(fIdCount, *fOut);
3054 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003055 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003056 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003057}
3058
3059}