blob: e1488e8c2a3b730d2c10a5ac4b2f67dc52369952 [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 Nicholasbe850ad2018-04-27 10:36:31 -04001250 if (c.fArguments[i]->fType.columns() == 1) {
1251 currentColumn.push_back(arguments[i]);
1252 } else {
1253 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
1254 for (int j = 0; j < c.fArguments[j]->fType.columns(); ++j) {
1255 SpvId swizzle = this->nextId();
1256 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1257 arguments[i], j, out);
1258 currentColumn.push_back(swizzle);
1259 }
1260 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001261 currentCount += c.fArguments[i]->fType.columns();
1262 if (currentCount == rows) {
1263 currentCount = 0;
1264 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn.size(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001265 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1266 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001267 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001268 SpvId columnId = this->nextId();
1269 this->writeWord(columnId, out);
1270 columnIds.push_back(columnId);
1271 for (SpvId id : currentColumn) {
1272 this->writeWord(id, out);
1273 }
1274 currentColumn.clear();
ethannicholasb3058bd2016-07-01 08:22:01 -07001275 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001276 ASSERT(currentCount < rows);
ethannicholasb3058bd2016-07-01 08:22:01 -07001277 }
1278 }
1279 ASSERT(columnIds.size() == (size_t) columns);
1280 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001281 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001282 this->writeWord(result, out);
1283 for (SpvId id : columnIds) {
1284 this->writeWord(id, out);
1285 }
1286 }
1287 return result;
1288}
1289
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001290SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001291 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001292 if (c.isConstant()) {
1293 return this->writeConstantVector(c);
1294 }
1295 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1296 // an instruction
1297 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001298 for (size_t i = 0; i < c.fArguments.size(); i++) {
1299 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1300 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1301 // extract the components and convert them in that case manually. On top of that,
1302 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1303 // doesn't handle vector arguments at all, so we always extract vector components and
1304 // pass them into OpCreateComposite individually.
1305 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1306 SpvOp_ op = SpvOpUndef;
1307 const Type& src = c.fArguments[i]->fType.componentType();
1308 const Type& dst = c.fType.componentType();
1309 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1310 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1311 if (c.fArguments.size() == 1) {
1312 return vec;
1313 }
1314 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1315 op = SpvOpConvertSToF;
1316 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1317 op = SpvOpConvertUToF;
1318 } else {
1319 ASSERT(false);
1320 }
1321 } else if (dst == *fContext.fInt_Type || dst == *fContext.fShort_Type) {
1322 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1323 op = SpvOpConvertFToS;
1324 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1325 if (c.fArguments.size() == 1) {
1326 return vec;
1327 }
1328 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1329 op = SpvOpBitcast;
1330 } else {
1331 ASSERT(false);
1332 }
1333 } else if (dst == *fContext.fUInt_Type || dst == *fContext.fUShort_Type) {
1334 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1335 op = SpvOpConvertFToS;
1336 } else if (src == *fContext.fInt_Type || src == *fContext.fShort_Type) {
1337 op = SpvOpBitcast;
1338 } else if (src == *fContext.fUInt_Type || src == *fContext.fUShort_Type) {
1339 if (c.fArguments.size() == 1) {
1340 return vec;
1341 }
1342 } else {
1343 ASSERT(false);
1344 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001345 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001346 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1347 SpvId swizzle = this->nextId();
1348 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1349 out);
1350 if (op != SpvOpUndef) {
1351 SpvId cast = this->nextId();
1352 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1353 arguments.push_back(cast);
1354 } else {
1355 arguments.push_back(swizzle);
1356 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001357 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001358 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001359 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1360 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001361 }
1362 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001363 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1364 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1365 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001366 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001367 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001368 this->writeWord(arguments[0], out);
1369 }
1370 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001371 ASSERT(arguments.size() > 1);
1372 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001373 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001374 this->writeWord(result, out);
1375 for (SpvId id : arguments) {
1376 this->writeWord(id, out);
1377 }
1378 }
1379 return result;
1380}
1381
Ethan Nicholasbd553222017-07-18 15:54:59 -04001382SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
1383 ASSERT(c.fType.kind() == Type::kArray_Kind);
1384 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1385 // an instruction
1386 std::vector<SpvId> arguments;
1387 for (size_t i = 0; i < c.fArguments.size(); i++) {
1388 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1389 }
1390 SpvId result = this->nextId();
1391 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1392 this->writeWord(this->getType(c.fType), out);
1393 this->writeWord(result, out);
1394 for (SpvId id : arguments) {
1395 this->writeWord(id, out);
1396 }
1397 return result;
1398}
1399
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001400SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001401 if (c.fArguments.size() == 1 &&
1402 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1403 return this->writeExpression(*c.fArguments[0], out);
1404 }
1405 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001406 return this->writeFloatConstructor(c, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001407 } else if (c.fType == *fContext.fInt_Type || c.fType == *fContext.fShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001408 return this->writeIntConstructor(c, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001409 } else if (c.fType == *fContext.fUInt_Type || c.fType == *fContext.fUShort_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001410 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 }
ethannicholasd598f792016-07-25 10:08:54 -07001412 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 case Type::kVector_Kind:
1414 return this->writeVectorConstructor(c, out);
1415 case Type::kMatrix_Kind:
1416 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001417 case Type::kArray_Kind:
1418 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 default:
1420 ABORT("unsupported constructor: %s", c.description().c_str());
1421 }
1422}
1423
1424SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1425 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001426 ASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001427 return SpvStorageClassInput;
1428 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001429 ASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001430 return SpvStorageClassOutput;
1431 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001432 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001433 return SpvStorageClassPushConstant;
1434 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001435 return SpvStorageClassUniform;
1436 } else {
1437 return SpvStorageClassFunction;
1438 }
1439}
1440
ethannicholasf789b382016-08-03 12:43:36 -07001441SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001442 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001443 case Expression::kVariableReference_Kind: {
1444 const Variable& var = ((VariableReference&) expr).fVariable;
1445 if (var.fStorage != Variable::kGlobal_Storage) {
1446 return SpvStorageClassFunction;
1447 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001448 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1449 if (result == SpvStorageClassFunction) {
1450 result = SpvStorageClassPrivate;
1451 }
1452 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001453 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 case Expression::kFieldAccess_Kind:
1455 return get_storage_class(*((FieldAccess&) expr).fBase);
1456 case Expression::kIndex_Kind:
1457 return get_storage_class(*((IndexExpression&) expr).fBase);
1458 default:
1459 return SpvStorageClassFunction;
1460 }
1461}
1462
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001463std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001464 std::vector<SpvId> chain;
1465 switch (expr.fKind) {
1466 case Expression::kIndex_Kind: {
1467 IndexExpression& indexExpr = (IndexExpression&) expr;
1468 chain = this->getAccessChain(*indexExpr.fBase, out);
1469 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1470 break;
1471 }
1472 case Expression::kFieldAccess_Kind: {
1473 FieldAccess& fieldExpr = (FieldAccess&) expr;
1474 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001475 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001476 chain.push_back(this->writeIntLiteral(index));
1477 break;
1478 }
1479 default:
1480 chain.push_back(this->getLValue(expr, out)->getPointer());
1481 }
1482 return chain;
1483}
1484
1485class PointerLValue : public SPIRVCodeGenerator::LValue {
1486public:
Greg Daniel64773e62016-11-22 09:44:03 -05001487 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001488 : fGen(gen)
1489 , fPointer(pointer)
1490 , fType(type) {}
1491
1492 virtual SpvId getPointer() override {
1493 return fPointer;
1494 }
1495
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001496 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001497 SpvId result = fGen.nextId();
1498 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1499 return result;
1500 }
1501
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001502 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001503 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1504 }
1505
1506private:
1507 SPIRVCodeGenerator& fGen;
1508 const SpvId fPointer;
1509 const SpvId fType;
1510};
1511
1512class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1513public:
Greg Daniel64773e62016-11-22 09:44:03 -05001514 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001515 const Type& baseType, const Type& swizzleType)
1516 : fGen(gen)
1517 , fVecPointer(vecPointer)
1518 , fComponents(components)
1519 , fBaseType(baseType)
1520 , fSwizzleType(swizzleType) {}
1521
1522 virtual SpvId getPointer() override {
1523 return 0;
1524 }
1525
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001526 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 SpvId base = fGen.nextId();
1528 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1529 SpvId result = fGen.nextId();
1530 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1531 fGen.writeWord(fGen.getType(fSwizzleType), out);
1532 fGen.writeWord(result, out);
1533 fGen.writeWord(base, out);
1534 fGen.writeWord(base, out);
1535 for (int component : fComponents) {
1536 fGen.writeWord(component, out);
1537 }
1538 return result;
1539 }
1540
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001541 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 // use OpVectorShuffle to mix and match the vector components. We effectively create
1543 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001544 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001545 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001546 // float3L = ...;
1547 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001548 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001549 // 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 -07001550 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1551 // (3, 1, 4).
1552 SpvId base = fGen.nextId();
1553 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1554 SpvId shuffle = fGen.nextId();
1555 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1556 fGen.writeWord(fGen.getType(fBaseType), out);
1557 fGen.writeWord(shuffle, out);
1558 fGen.writeWord(base, out);
1559 fGen.writeWord(value, out);
1560 for (int i = 0; i < fBaseType.columns(); i++) {
1561 // current offset into the virtual vector, defaults to pulling the unmodified
1562 // value from the left side
1563 int offset = i;
1564 // check to see if we are writing this component
1565 for (size_t j = 0; j < fComponents.size(); j++) {
1566 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001567 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 // the correct component of the right side instead of preserving the
1569 // value from the left
1570 offset = (int) (j + fBaseType.columns());
1571 break;
1572 }
1573 }
1574 fGen.writeWord(offset, out);
1575 }
1576 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1577 }
1578
1579private:
1580 SPIRVCodeGenerator& fGen;
1581 const SpvId fVecPointer;
1582 const std::vector<int>& fComponents;
1583 const Type& fBaseType;
1584 const Type& fSwizzleType;
1585};
1586
Greg Daniel64773e62016-11-22 09:44:03 -05001587std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001588 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001589 switch (expr.fKind) {
1590 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001591 const Variable& var = ((VariableReference&) expr).fVariable;
1592 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001593 ASSERT(entry != fVariableMap.end());
1594 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001595 *this,
1596 entry->second,
1597 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001598 }
1599 case Expression::kIndex_Kind: // fall through
1600 case Expression::kFieldAccess_Kind: {
1601 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1602 SpvId member = this->nextId();
1603 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001604 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001605 this->writeWord(member, out);
1606 for (SpvId idx : chain) {
1607 this->writeWord(idx, out);
1608 }
1609 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001610 *this,
1611 member,
1612 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001614 case Expression::kSwizzle_Kind: {
1615 Swizzle& swizzle = (Swizzle&) expr;
1616 size_t count = swizzle.fComponents.size();
1617 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1618 ASSERT(base);
1619 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001620 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001621 SpvId member = this->nextId();
1622 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001623 this->getPointerType(swizzle.fType,
1624 get_storage_class(*swizzle.fBase)),
1625 member,
1626 base,
1627 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001628 out);
1629 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1630 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001631 member,
ethannicholasd598f792016-07-25 10:08:54 -07001632 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001633 } else {
1634 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001635 *this,
1636 base,
1637 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001638 swizzle.fBase->fType,
1639 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001640 }
1641 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001642 case Expression::kTernary_Kind: {
1643 TernaryExpression& t = (TernaryExpression&) expr;
1644 SpvId test = this->writeExpression(*t.fTest, out);
1645 SpvId end = this->nextId();
1646 SpvId ifTrueLabel = this->nextId();
1647 SpvId ifFalseLabel = this->nextId();
1648 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1649 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1650 this->writeLabel(ifTrueLabel, out);
1651 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
1652 ASSERT(ifTrue);
1653 this->writeInstruction(SpvOpBranch, end, out);
1654 ifTrueLabel = fCurrentBlock;
1655 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
1656 ASSERT(ifFalse);
1657 ifFalseLabel = fCurrentBlock;
1658 this->writeInstruction(SpvOpBranch, end, out);
1659 SpvId result = this->nextId();
1660 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1661 ifTrueLabel, ifFalse, ifFalseLabel, out);
1662 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1663 *this,
1664 result,
1665 this->getType(expr.fType)));
1666 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 default:
1668 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001669 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001670 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1671 // caught by IRGenerator
1672 SpvId result = this->nextId();
1673 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001674 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1675 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1677 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1678 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001679 result,
ethannicholasd598f792016-07-25 10:08:54 -07001680 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001681 }
1682}
1683
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001684SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001685 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001686 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 ASSERT(entry != fVariableMap.end());
1688 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001689 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001690 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1691 fProgram.fSettings.fFlipY) {
1692 // need to remap to a top-left coordinate system
1693 if (fRTHeightStructId == (SpvId) -1) {
1694 // height variable hasn't been written yet
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001695 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001696 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
1697 std::vector<Type::Field> fields;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001698 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1699 StringFragment name("sksl_synthetic_uniforms");
1700 Type intfStruct(-1, name, fields);
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001701 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1702 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
1703 StringFragment());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001704 Variable* intfVar = new Variable(-1,
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001705 Modifiers(layout, Modifiers::kUniform_Flag),
1706 name,
1707 intfStruct,
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001708 Variable::kGlobal_Storage);
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001709 fSynthetics.takeOwnership(intfVar);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001710 InterfaceBlock intf(-1, intfVar, name, String(""),
Ethan Nicholas50afc172017-02-16 14:49:57 -05001711 std::vector<std::unique_ptr<Expression>>(), st);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001712 fRTHeightStructId = this->writeInterfaceBlock(intf);
1713 fRTHeightFieldIndex = 0;
1714 }
1715 ASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001716 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001717 SpvId xId = this->nextId();
1718 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1719 result, 0, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001720 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001721 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001722 SpvId heightPtr = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001723 this->writeOpCode(SpvOpAccessChain, 5, out);
1724 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001725 this->writeWord(heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001726 this->writeWord(fRTHeightStructId, out);
1727 this->writeWord(fieldIndexId, out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001728 SpvId heightRead = this->nextId();
1729 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1730 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001731 SpvId rawYId = this->nextId();
1732 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1733 result, 1, out);
1734 SpvId flippedYId = this->nextId();
1735 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1736 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001737 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001738 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001739 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001740 SpvId oneId = writeFloatLiteral(one);
1741 SpvId flipped = this->nextId();
1742 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001743 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001744 this->writeWord(flipped, out);
1745 this->writeWord(xId, out);
1746 this->writeWord(flippedYId, out);
1747 this->writeWord(zeroId, out);
1748 this->writeWord(oneId, out);
1749 return flipped;
1750 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001751 return result;
1752}
1753
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001754SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001755 return getLValue(expr, out)->load(out);
1756}
1757
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001758SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 return getLValue(f, out)->load(out);
1760}
1761
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001762SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001763 SpvId base = this->writeExpression(*swizzle.fBase, out);
1764 SpvId result = this->nextId();
1765 size_t count = swizzle.fComponents.size();
1766 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001767 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1768 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001769 } else {
1770 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001771 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001772 this->writeWord(result, out);
1773 this->writeWord(base, out);
1774 this->writeWord(base, out);
1775 for (int component : swizzle.fComponents) {
1776 this->writeWord(component, out);
1777 }
1778 }
1779 return result;
1780}
1781
Greg Daniel64773e62016-11-22 09:44:03 -05001782SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1783 const Type& operandType, SpvId lhs,
1784 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001785 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001787 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001788 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001789 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001791 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001793 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1795 } else {
1796 ABORT("invalid operandType: %s", operandType.description().c_str());
1797 }
1798 return result;
1799}
1800
1801bool is_assignment(Token::Kind op) {
1802 switch (op) {
1803 case Token::EQ: // fall through
1804 case Token::PLUSEQ: // fall through
1805 case Token::MINUSEQ: // fall through
1806 case Token::STAREQ: // fall through
1807 case Token::SLASHEQ: // fall through
1808 case Token::PERCENTEQ: // fall through
1809 case Token::SHLEQ: // fall through
1810 case Token::SHREQ: // fall through
1811 case Token::BITWISEOREQ: // fall through
1812 case Token::BITWISEXOREQ: // fall through
1813 case Token::BITWISEANDEQ: // fall through
1814 case Token::LOGICALOREQ: // fall through
1815 case Token::LOGICALXOREQ: // fall through
1816 case Token::LOGICALANDEQ:
1817 return true;
1818 default:
1819 return false;
1820 }
1821}
1822
Ethan Nicholas48e24052018-03-14 13:51:39 -04001823SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1824 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001825 if (operandType.kind() == Type::kVector_Kind) {
1826 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001827 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001828 return result;
1829 }
1830 return id;
1831}
1832
Ethan Nicholas68990be2017-07-13 09:36:52 -04001833SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1834 SpvOp_ floatOperator, SpvOp_ intOperator,
1835 OutputStream& out) {
1836 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
1837 ASSERT(operandType.kind() == Type::kMatrix_Kind);
1838 SpvId rowType = this->getType(operandType.componentType().toCompound(fContext,
1839 operandType.columns(),
1840 1));
1841 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
1842 operandType.columns(),
1843 1));
1844 SpvId boolType = this->getType(*fContext.fBool_Type);
1845 SpvId result = 0;
1846 for (int i = 0; i < operandType.rows(); i++) {
1847 SpvId rowL = this->nextId();
1848 this->writeInstruction(SpvOpCompositeExtract, rowType, rowL, lhs, 0, out);
1849 SpvId rowR = this->nextId();
1850 this->writeInstruction(SpvOpCompositeExtract, rowType, rowR, rhs, 0, out);
1851 SpvId compare = this->nextId();
1852 this->writeInstruction(compareOp, bvecType, compare, rowL, rowR, out);
1853 SpvId all = this->nextId();
1854 this->writeInstruction(SpvOpAll, boolType, all, compare, out);
1855 if (result != 0) {
1856 SpvId next = this->nextId();
1857 this->writeInstruction(SpvOpLogicalAnd, boolType, next, result, all, out);
1858 result = next;
1859 }
1860 else {
1861 result = all;
1862 }
1863 }
1864 return result;
1865}
1866
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001867SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001868 // handle cases where we don't necessarily evaluate both LHS and RHS
1869 switch (b.fOperator) {
1870 case Token::EQ: {
1871 SpvId rhs = this->writeExpression(*b.fRight, out);
1872 this->getLValue(*b.fLeft, out)->store(rhs, out);
1873 return rhs;
1874 }
1875 case Token::LOGICALAND:
1876 return this->writeLogicalAnd(b, out);
1877 case Token::LOGICALOR:
1878 return this->writeLogicalOr(b, out);
1879 default:
1880 break;
1881 }
1882
1883 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001884 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001885 std::unique_ptr<LValue> lvalue;
1886 SpvId lhs;
1887 if (is_assignment(b.fOperator)) {
1888 lvalue = this->getLValue(*b.fLeft, out);
1889 lhs = lvalue->load(out);
1890 } else {
1891 lvalue = nullptr;
1892 lhs = this->writeExpression(*b.fLeft, out);
1893 }
1894 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04001895 if (b.fOperator == Token::COMMA) {
1896 return rhs;
1897 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001898 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04001899 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07001900 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001901 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
1902 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001903 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05001904 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001905 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 // promote number to vector
1907 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001908 const Type& vecType = b.fLeft->fType;
1909 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1910 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001912 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 this->writeWord(rhs, out);
1914 }
1915 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001916 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05001917 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001918 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001919 // promote number to vector
1920 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001921 const Type& vecType = b.fRight->fType;
1922 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1923 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001925 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001926 this->writeWord(lhs, out);
1927 }
1928 lhs = vec;
1929 ASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001930 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07001931 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001933 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001934 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001935 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001936 op = SpvOpMatrixTimesVector;
1937 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001938 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001939 op = SpvOpMatrixTimesScalar;
1940 }
1941 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001942 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001943 if (b.fOperator == Token::STAREQ) {
1944 lvalue->store(result, out);
1945 } else {
1946 ASSERT(b.fOperator == Token::STAR);
1947 }
1948 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001949 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001950 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001951 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05001952 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001953 lhs, rhs, out);
1954 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001955 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05001956 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 lhs, out);
1958 }
1959 if (b.fOperator == Token::STAREQ) {
1960 lvalue->store(result, out);
1961 } else {
1962 ASSERT(b.fOperator == Token::STAR);
1963 }
1964 return result;
1965 } else {
1966 ABORT("unsupported binary expression: %s", b.description().c_str());
1967 }
1968 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001969 tmp = this->getActualType(b.fLeft->fType);
1970 operandType = &tmp;
1971 ASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 }
1973 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001974 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04001975 if (operandType->kind() == Type::kMatrix_Kind) {
1976 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
1977 SpvOpIEqual, out);
1978 }
ethannicholasd598f792016-07-25 10:08:54 -07001979 ASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001980 const Type* tmpType;
1981 if (operandType->kind() == Type::kVector_Kind) {
1982 tmpType = &fContext.fBool_Type->toCompound(fContext,
1983 operandType->columns(),
1984 operandType->rows());
1985 } else {
1986 tmpType = &resultType;
1987 }
1988 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05001989 SpvOpFOrdEqual, SpvOpIEqual,
1990 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04001991 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001992 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04001994 if (operandType->kind() == Type::kMatrix_Kind) {
1995 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
1996 SpvOpINotEqual, out);
1997 }
ethannicholasd598f792016-07-25 10:08:54 -07001998 ASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001999 const Type* tmpType;
2000 if (operandType->kind() == Type::kVector_Kind) {
2001 tmpType = &fContext.fBool_Type->toCompound(fContext,
2002 operandType->columns(),
2003 operandType->rows());
2004 } else {
2005 tmpType = &resultType;
2006 }
2007 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002008 SpvOpFOrdNotEqual, SpvOpINotEqual,
2009 SpvOpINotEqual, SpvOpLogicalNotEqual,
2010 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002011 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002012 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07002013 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002014 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2015 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 SpvOpUGreaterThan, SpvOpUndef, out);
2017 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07002018 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002019 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2021 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002022 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002023 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2024 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002025 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2026 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002027 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002028 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2029 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 SpvOpULessThanEqual, SpvOpUndef, out);
2031 case Token::PLUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002032 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2034 case Token::MINUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002035 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2037 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002038 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002039 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 // matrix multiply
2041 SpvId result = this->nextId();
2042 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2043 lhs, rhs, out);
2044 return result;
2045 }
Greg Daniel64773e62016-11-22 09:44:03 -05002046 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002047 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2048 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002049 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002051 case Token::PERCENT:
2052 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2053 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002054 case Token::SHL:
2055 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2056 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2057 SpvOpUndef, out);
2058 case Token::SHR:
2059 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2060 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2061 SpvOpUndef, out);
2062 case Token::BITWISEAND:
2063 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2064 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2065 case Token::BITWISEOR:
2066 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2067 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2068 case Token::BITWISEXOR:
2069 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2070 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 case Token::PLUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002072 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002073 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2074 ASSERT(lvalue);
2075 lvalue->store(result, out);
2076 return result;
2077 }
2078 case Token::MINUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002079 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002080 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2081 ASSERT(lvalue);
2082 lvalue->store(result, out);
2083 return result;
2084 }
2085 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002086 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002087 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002088 // matrix multiply
2089 SpvId result = this->nextId();
2090 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2091 lhs, rhs, out);
2092 ASSERT(lvalue);
2093 lvalue->store(result, out);
2094 return result;
2095 }
Greg Daniel64773e62016-11-22 09:44:03 -05002096 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002097 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2098 ASSERT(lvalue);
2099 lvalue->store(result, out);
2100 return result;
2101 }
2102 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002103 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2105 ASSERT(lvalue);
2106 lvalue->store(result, out);
2107 return result;
2108 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002109 case Token::PERCENTEQ: {
2110 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2111 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
2112 ASSERT(lvalue);
2113 lvalue->store(result, out);
2114 return result;
2115 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002116 case Token::SHLEQ: {
2117 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2118 SpvOpUndef, SpvOpShiftLeftLogical,
2119 SpvOpShiftLeftLogical, SpvOpUndef, out);
2120 ASSERT(lvalue);
2121 lvalue->store(result, out);
2122 return result;
2123 }
2124 case Token::SHREQ: {
2125 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2126 SpvOpUndef, SpvOpShiftRightArithmetic,
2127 SpvOpShiftRightLogical, SpvOpUndef, out);
2128 ASSERT(lvalue);
2129 lvalue->store(result, out);
2130 return result;
2131 }
2132 case Token::BITWISEANDEQ: {
2133 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2134 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2135 SpvOpUndef, out);
2136 ASSERT(lvalue);
2137 lvalue->store(result, out);
2138 return result;
2139 }
2140 case Token::BITWISEOREQ: {
2141 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2142 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2143 SpvOpUndef, out);
2144 ASSERT(lvalue);
2145 lvalue->store(result, out);
2146 return result;
2147 }
2148 case Token::BITWISEXOREQ: {
2149 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2150 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2151 SpvOpUndef, out);
2152 ASSERT(lvalue);
2153 lvalue->store(result, out);
2154 return result;
2155 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002156 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 ABORT("unsupported binary expression: %s", b.description().c_str());
2158 }
2159}
2160
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002161SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 ASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002163 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2165 SpvId lhs = this->writeExpression(*a.fLeft, out);
2166 SpvId rhsLabel = this->nextId();
2167 SpvId end = this->nextId();
2168 SpvId lhsBlock = fCurrentBlock;
2169 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2170 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2171 this->writeLabel(rhsLabel, out);
2172 SpvId rhs = this->writeExpression(*a.fRight, out);
2173 SpvId rhsBlock = fCurrentBlock;
2174 this->writeInstruction(SpvOpBranch, end, out);
2175 this->writeLabel(end, out);
2176 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002177 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002178 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 return result;
2180}
2181
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002182SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 ASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002184 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2186 SpvId lhs = this->writeExpression(*o.fLeft, out);
2187 SpvId rhsLabel = this->nextId();
2188 SpvId end = this->nextId();
2189 SpvId lhsBlock = fCurrentBlock;
2190 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2191 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2192 this->writeLabel(rhsLabel, out);
2193 SpvId rhs = this->writeExpression(*o.fRight, out);
2194 SpvId rhsBlock = fCurrentBlock;
2195 this->writeInstruction(SpvOpBranch, end, out);
2196 this->writeLabel(end, out);
2197 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002198 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002199 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002200 return result;
2201}
2202
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002203SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 SpvId test = this->writeExpression(*t.fTest, out);
2205 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2206 // both true and false are constants, can just use OpSelect
2207 SpvId result = this->nextId();
2208 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2209 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002210 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 out);
2212 return result;
2213 }
Greg Daniel64773e62016-11-22 09:44:03 -05002214 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 // Adreno. Switched to storing the result in a temp variable as glslang does.
2216 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002217 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002218 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 SpvId trueLabel = this->nextId();
2220 SpvId falseLabel = this->nextId();
2221 SpvId end = this->nextId();
2222 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2223 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2224 this->writeLabel(trueLabel, out);
2225 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2226 this->writeInstruction(SpvOpBranch, end, out);
2227 this->writeLabel(falseLabel, out);
2228 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2229 this->writeInstruction(SpvOpBranch, end, out);
2230 this->writeLabel(end, out);
2231 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002232 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002233 return result;
2234}
2235
ethannicholasd598f792016-07-25 10:08:54 -07002236std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002237 if (type.isInteger()) {
2238 return std::unique_ptr<Expression>(new IntLiteral(context, -1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002239 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002240 else if (type.isFloat()) {
2241 return std::unique_ptr<Expression>(new FloatLiteral(context, -1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002242 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002243 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 }
2245}
2246
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002247SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002248 if (p.fOperator == Token::MINUS) {
2249 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002250 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002251 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002252 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002253 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002254 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2256 } else {
2257 ABORT("unsupported prefix expression %s", p.description().c_str());
2258 };
2259 return result;
2260 }
2261 switch (p.fOperator) {
2262 case Token::PLUS:
2263 return this->writeExpression(*p.fOperand, out);
2264 case Token::PLUSPLUS: {
2265 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002266 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002267 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2268 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002269 out);
2270 lv->store(result, out);
2271 return result;
2272 }
2273 case Token::MINUSMINUS: {
2274 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002275 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002276 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2277 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 out);
2279 lv->store(result, out);
2280 return result;
2281 }
ethannicholas5961bc92016-10-12 06:39:56 -07002282 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002283 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002284 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002285 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002286 this->writeExpression(*p.fOperand, out), out);
2287 return result;
2288 }
ethannicholas5961bc92016-10-12 06:39:56 -07002289 case Token::BITWISENOT: {
2290 SpvId result = this->nextId();
2291 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2292 this->writeExpression(*p.fOperand, out), out);
2293 return result;
2294 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 default:
2296 ABORT("unsupported prefix expression: %s", p.description().c_str());
2297 }
2298}
2299
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002300SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2302 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002303 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002304 switch (p.fOperator) {
2305 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002306 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2308 lv->store(temp, out);
2309 return result;
2310 }
2311 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002312 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002313 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2314 lv->store(temp, out);
2315 return result;
2316 }
2317 default:
2318 ABORT("unsupported postfix expression %s", p.description().c_str());
2319 }
2320}
2321
ethannicholasf789b382016-08-03 12:43:36 -07002322SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002323 if (b.fValue) {
2324 if (fBoolTrue == 0) {
2325 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002326 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002327 fConstantBuffer);
2328 }
2329 return fBoolTrue;
2330 } else {
2331 if (fBoolFalse == 0) {
2332 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002333 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002334 fConstantBuffer);
2335 }
2336 return fBoolFalse;
2337 }
2338}
2339
ethannicholasf789b382016-08-03 12:43:36 -07002340SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002341 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002342 auto entry = fIntConstants.find(i.fValue);
2343 if (entry == fIntConstants.end()) {
2344 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002345 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002346 fConstantBuffer);
2347 fIntConstants[i.fValue] = result;
2348 return result;
2349 }
2350 return entry->second;
2351 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002352 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002353 auto entry = fUIntConstants.find(i.fValue);
2354 if (entry == fUIntConstants.end()) {
2355 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002356 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002357 fConstantBuffer);
2358 fUIntConstants[i.fValue] = result;
2359 return result;
2360 }
2361 return entry->second;
2362 }
2363}
2364
ethannicholasf789b382016-08-03 12:43:36 -07002365SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002366 if (f.fType == *fContext.fFloat_Type || f.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002367 float value = (float) f.fValue;
2368 auto entry = fFloatConstants.find(value);
2369 if (entry == fFloatConstants.end()) {
2370 SpvId result = this->nextId();
2371 uint32_t bits;
2372 ASSERT(sizeof(bits) == sizeof(value));
2373 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002374 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002375 fConstantBuffer);
2376 fFloatConstants[value] = result;
2377 return result;
2378 }
2379 return entry->second;
2380 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002381 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002382 auto entry = fDoubleConstants.find(f.fValue);
2383 if (entry == fDoubleConstants.end()) {
2384 SpvId result = this->nextId();
2385 uint64_t bits;
2386 ASSERT(sizeof(bits) == sizeof(f.fValue));
2387 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002388 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2390 fDoubleConstants[f.fValue] = result;
2391 return result;
2392 }
2393 return entry->second;
2394 }
2395}
2396
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002397SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002398 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002399 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002400 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002401 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002402 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002403 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002404 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002405 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002406 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002407 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2408 }
2409 return result;
2410}
2411
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002412SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2413 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2415 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002416 if (f.fDeclaration.fName == "main") {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002417 write_stringstream(fGlobalInitializersBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002419 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002420 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002421 write_stringstream(fVariableBuffer, out);
2422 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002424 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2425 this->writeInstruction(SpvOpReturn, out);
2426 } else {
2427 this->writeInstruction(SpvOpUnreachable, out);
2428 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 }
2430 this->writeInstruction(SpvOpFunctionEnd, out);
2431 return result;
2432}
2433
2434void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2435 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002436 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002437 fDecorationBuffer);
2438 }
2439 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002440 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002441 fDecorationBuffer);
2442 }
2443 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002444 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002445 fDecorationBuffer);
2446 }
2447 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002448 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 fDecorationBuffer);
2450 }
Greg Daniel64773e62016-11-22 09:44:03 -05002451 if (layout.fInputAttachmentIndex >= 0) {
2452 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2453 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002454 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002455 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002456 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04002457 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002458 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002459 fDecorationBuffer);
2460 }
2461}
2462
2463void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2464 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002465 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 layout.fLocation, fDecorationBuffer);
2467 }
2468 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002469 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002470 layout.fBinding, fDecorationBuffer);
2471 }
2472 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002473 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002474 layout.fIndex, fDecorationBuffer);
2475 }
2476 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002477 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002478 layout.fSet, fDecorationBuffer);
2479 }
Greg Daniel64773e62016-11-22 09:44:03 -05002480 if (layout.fInputAttachmentIndex >= 0) {
2481 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2482 layout.fInputAttachmentIndex, fDecorationBuffer);
2483 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002484 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002485 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 layout.fBuiltin, fDecorationBuffer);
2487 }
2488}
2489
ethannicholasf789b382016-08-03 12:43:36 -07002490SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002491 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002492 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2493 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002494 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2495 MemoryLayout(MemoryLayout::k430_Standard) :
2496 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002498 const Type* type = &intf.fVariable.fType;
2499 if (fProgram.fInputs.fRTHeight) {
2500 ASSERT(fRTHeightStructId == (SpvId) -1);
2501 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
2502 std::vector<Type::Field> fields = type->fields();
2503 fRTHeightStructId = result;
2504 fRTHeightFieldIndex = fields.size();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002505 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2506 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002507 }
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002508 SpvId typeId = this->getType(*type, memoryLayout);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002509 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2510 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
2511 } else {
2512 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2513 }
ethannicholasd598f792016-07-25 10:08:54 -07002514 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002516 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002518 Layout layout = intf.fVariable.fModifiers.fLayout;
2519 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2520 layout.fSet = 0;
2521 }
2522 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002523 fVariableMap[&intf.fVariable] = result;
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002524 if (fProgram.fInputs.fRTHeight) {
2525 delete type;
2526 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002527 return result;
2528}
2529
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002530void SPIRVCodeGenerator::writePrecisionModifier(const Modifiers& modifiers, SpvId id) {
2531 if ((modifiers.fFlags & Modifiers::kLowp_Flag) |
2532 (modifiers.fFlags & Modifiers::kMediump_Flag)) {
2533 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2534 }
2535}
2536
ethannicholas5961bc92016-10-12 06:39:56 -07002537#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002538void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002539 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002540 for (size_t i = 0; i < decl.fVars.size(); i++) {
2541 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2542 continue;
2543 }
2544 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2545 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002546 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2547 // in the OpenGL backend.
2548 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2549 Modifiers::kWriteOnly_Flag |
2550 Modifiers::kCoherent_Flag |
2551 Modifiers::kVolatile_Flag |
2552 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002553 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2554 continue;
2555 }
2556 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2557 kind != Program::kFragment_Kind) {
Brian Salomondc092132018-04-04 10:14:16 -04002558 ASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002559 continue;
2560 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002561 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002562 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2563 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002564 Modifiers::kUniform_Flag |
2565 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002566 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2567 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002568 continue;
2569 }
2570 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002571 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002573 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002575 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2576 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002577 storageClass = SpvStorageClassUniformConstant;
2578 } else {
2579 storageClass = SpvStorageClassUniform;
2580 }
2581 } else {
2582 storageClass = SpvStorageClassPrivate;
2583 }
2584 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002585 fVariableMap[var] = id;
2586 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002587 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002588 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002589 this->writePrecisionModifier(var->fModifiers, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002590 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002591 ASSERT(!fCurrentBlock);
2592 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002593 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002594 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002595 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002596 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002597 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002598 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2599 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2600 }
2601 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2602 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2603 fDecorationBuffer);
2604 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002605 }
2606}
2607
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002608void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002609 for (const auto& stmt : decl.fVars) {
2610 ASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
2611 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2612 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002613 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2614 // in the OpenGL backend.
2615 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2616 Modifiers::kWriteOnly_Flag |
2617 Modifiers::kCoherent_Flag |
2618 Modifiers::kVolatile_Flag |
2619 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002620 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002621 fVariableMap[var] = id;
2622 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002623 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002624 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002625 if (varDecl.fValue) {
2626 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002627 this->writeInstruction(SpvOpStore, id, value, out);
2628 }
2629 }
2630}
2631
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002632void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002633 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002634 case Statement::kNop_Kind:
2635 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002636 case Statement::kBlock_Kind:
2637 this->writeBlock((Block&) s, out);
2638 break;
2639 case Statement::kExpression_Kind:
2640 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2641 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002642 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002643 this->writeReturnStatement((ReturnStatement&) s, out);
2644 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002645 case Statement::kVarDeclarations_Kind:
2646 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002647 break;
2648 case Statement::kIf_Kind:
2649 this->writeIfStatement((IfStatement&) s, out);
2650 break;
2651 case Statement::kFor_Kind:
2652 this->writeForStatement((ForStatement&) s, out);
2653 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002654 case Statement::kWhile_Kind:
2655 this->writeWhileStatement((WhileStatement&) s, out);
2656 break;
2657 case Statement::kDo_Kind:
2658 this->writeDoStatement((DoStatement&) s, out);
2659 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002660 case Statement::kSwitch_Kind:
2661 this->writeSwitchStatement((SwitchStatement&) s, out);
2662 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002663 case Statement::kBreak_Kind:
2664 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2665 break;
2666 case Statement::kContinue_Kind:
2667 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2668 break;
2669 case Statement::kDiscard_Kind:
2670 this->writeInstruction(SpvOpKill, out);
2671 break;
2672 default:
2673 ABORT("unsupported statement: %s", s.description().c_str());
2674 }
2675}
2676
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002677void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002678 for (size_t i = 0; i < b.fStatements.size(); i++) {
2679 this->writeStatement(*b.fStatements[i], out);
2680 }
2681}
2682
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002683void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002684 SpvId test = this->writeExpression(*stmt.fTest, out);
2685 SpvId ifTrue = this->nextId();
2686 SpvId ifFalse = this->nextId();
2687 if (stmt.fIfFalse) {
2688 SpvId end = this->nextId();
2689 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2690 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2691 this->writeLabel(ifTrue, out);
2692 this->writeStatement(*stmt.fIfTrue, out);
2693 if (fCurrentBlock) {
2694 this->writeInstruction(SpvOpBranch, end, out);
2695 }
2696 this->writeLabel(ifFalse, out);
2697 this->writeStatement(*stmt.fIfFalse, out);
2698 if (fCurrentBlock) {
2699 this->writeInstruction(SpvOpBranch, end, out);
2700 }
2701 this->writeLabel(end, out);
2702 } else {
2703 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2704 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2705 this->writeLabel(ifTrue, out);
2706 this->writeStatement(*stmt.fIfTrue, out);
2707 if (fCurrentBlock) {
2708 this->writeInstruction(SpvOpBranch, ifFalse, out);
2709 }
2710 this->writeLabel(ifFalse, out);
2711 }
2712}
2713
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002714void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002715 if (f.fInitializer) {
2716 this->writeStatement(*f.fInitializer, out);
2717 }
2718 SpvId header = this->nextId();
2719 SpvId start = this->nextId();
2720 SpvId body = this->nextId();
2721 SpvId next = this->nextId();
2722 fContinueTarget.push(next);
2723 SpvId end = this->nextId();
2724 fBreakTarget.push(end);
2725 this->writeInstruction(SpvOpBranch, header, out);
2726 this->writeLabel(header, out);
2727 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002728 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002729 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002730 if (f.fTest) {
2731 SpvId test = this->writeExpression(*f.fTest, out);
2732 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2733 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002734 this->writeLabel(body, out);
2735 this->writeStatement(*f.fStatement, out);
2736 if (fCurrentBlock) {
2737 this->writeInstruction(SpvOpBranch, next, out);
2738 }
2739 this->writeLabel(next, out);
2740 if (f.fNext) {
2741 this->writeExpression(*f.fNext, out);
2742 }
2743 this->writeInstruction(SpvOpBranch, header, out);
2744 this->writeLabel(end, out);
2745 fBreakTarget.pop();
2746 fContinueTarget.pop();
2747}
2748
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002749void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002750 // We believe the while loop code below will work, but Skia doesn't actually use them and
2751 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2752 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2753 // message, simply remove the error call below to see whether our while loop support actually
2754 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002755 fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002756 "see SkSLSPIRVCodeGenerator.cpp for details");
2757
2758 SpvId header = this->nextId();
2759 SpvId start = this->nextId();
2760 SpvId body = this->nextId();
2761 fContinueTarget.push(start);
2762 SpvId end = this->nextId();
2763 fBreakTarget.push(end);
2764 this->writeInstruction(SpvOpBranch, header, out);
2765 this->writeLabel(header, out);
2766 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2767 this->writeInstruction(SpvOpBranch, start, out);
2768 this->writeLabel(start, out);
2769 SpvId test = this->writeExpression(*w.fTest, out);
2770 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2771 this->writeLabel(body, out);
2772 this->writeStatement(*w.fStatement, out);
2773 if (fCurrentBlock) {
2774 this->writeInstruction(SpvOpBranch, start, out);
2775 }
2776 this->writeLabel(end, out);
2777 fBreakTarget.pop();
2778 fContinueTarget.pop();
2779}
2780
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002781void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002782 // We believe the do loop code below will work, but Skia doesn't actually use them and
2783 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2784 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2785 // message, simply remove the error call below to see whether our do loop support actually
2786 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002787 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002788 "SkSLSPIRVCodeGenerator.cpp for details");
2789
2790 SpvId header = this->nextId();
2791 SpvId start = this->nextId();
2792 SpvId next = this->nextId();
2793 fContinueTarget.push(next);
2794 SpvId end = this->nextId();
2795 fBreakTarget.push(end);
2796 this->writeInstruction(SpvOpBranch, header, out);
2797 this->writeLabel(header, out);
2798 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2799 this->writeInstruction(SpvOpBranch, start, out);
2800 this->writeLabel(start, out);
2801 this->writeStatement(*d.fStatement, out);
2802 if (fCurrentBlock) {
2803 this->writeInstruction(SpvOpBranch, next, out);
2804 }
2805 this->writeLabel(next, out);
2806 SpvId test = this->writeExpression(*d.fTest, out);
2807 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2808 this->writeLabel(end, out);
2809 fBreakTarget.pop();
2810 fContinueTarget.pop();
2811}
2812
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002813void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2814 SpvId value = this->writeExpression(*s.fValue, out);
2815 std::vector<SpvId> labels;
2816 SpvId end = this->nextId();
2817 SpvId defaultLabel = end;
2818 fBreakTarget.push(end);
2819 int size = 3;
2820 for (const auto& c : s.fCases) {
2821 SpvId label = this->nextId();
2822 labels.push_back(label);
2823 if (c->fValue) {
2824 size += 2;
2825 } else {
2826 defaultLabel = label;
2827 }
2828 }
2829 labels.push_back(end);
2830 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2831 this->writeOpCode(SpvOpSwitch, size, out);
2832 this->writeWord(value, out);
2833 this->writeWord(defaultLabel, out);
2834 for (size_t i = 0; i < s.fCases.size(); ++i) {
2835 if (!s.fCases[i]->fValue) {
2836 continue;
2837 }
2838 ASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
2839 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
2840 this->writeWord(labels[i], out);
2841 }
2842 for (size_t i = 0; i < s.fCases.size(); ++i) {
2843 this->writeLabel(labels[i], out);
2844 for (const auto& stmt : s.fCases[i]->fStatements) {
2845 this->writeStatement(*stmt, out);
2846 }
2847 if (fCurrentBlock) {
2848 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
2849 }
2850 }
2851 this->writeLabel(end, out);
2852 fBreakTarget.pop();
2853}
2854
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002855void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002856 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05002857 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07002858 out);
2859 } else {
2860 this->writeInstruction(SpvOpReturn, out);
2861 }
2862}
2863
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002864void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
2865 ASSERT(fProgram.fKind == Program::kGeometry_Kind);
2866 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002867 for (const auto& e : fProgram) {
2868 if (e.fKind == ProgramElement::kModifiers_Kind) {
2869 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002870 if (m.fFlags & Modifiers::kIn_Flag) {
2871 if (m.fLayout.fInvocations != -1) {
2872 invocations = m.fLayout.fInvocations;
2873 }
2874 SpvId input;
2875 switch (m.fLayout.fPrimitive) {
2876 case Layout::kPoints_Primitive:
2877 input = SpvExecutionModeInputPoints;
2878 break;
2879 case Layout::kLines_Primitive:
2880 input = SpvExecutionModeInputLines;
2881 break;
2882 case Layout::kLinesAdjacency_Primitive:
2883 input = SpvExecutionModeInputLinesAdjacency;
2884 break;
2885 case Layout::kTriangles_Primitive:
2886 input = SpvExecutionModeTriangles;
2887 break;
2888 case Layout::kTrianglesAdjacency_Primitive:
2889 input = SpvExecutionModeInputTrianglesAdjacency;
2890 break;
2891 default:
2892 input = 0;
2893 break;
2894 }
2895 if (input) {
2896 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
2897 }
2898 } else if (m.fFlags & Modifiers::kOut_Flag) {
2899 SpvId output;
2900 switch (m.fLayout.fPrimitive) {
2901 case Layout::kPoints_Primitive:
2902 output = SpvExecutionModeOutputPoints;
2903 break;
2904 case Layout::kLineStrip_Primitive:
2905 output = SpvExecutionModeOutputLineStrip;
2906 break;
2907 case Layout::kTriangleStrip_Primitive:
2908 output = SpvExecutionModeOutputTriangleStrip;
2909 break;
2910 default:
2911 output = 0;
2912 break;
2913 }
2914 if (output) {
2915 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
2916 }
2917 if (m.fLayout.fMaxVertices != -1) {
2918 this->writeInstruction(SpvOpExecutionMode, entryPoint,
2919 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
2920 out);
2921 }
2922 }
2923 }
2924 }
2925 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
2926 invocations, out);
2927}
2928
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002929void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002930 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002931 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05002932 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002933 // assign IDs to functions, determine sk_in size
2934 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002935 for (const auto& e : program) {
2936 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002937 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002938 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002939 fFunctionMap[&f.fDeclaration] = this->nextId();
2940 break;
2941 }
2942 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002943 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002944 if (m.fFlags & Modifiers::kIn_Flag) {
2945 switch (m.fLayout.fPrimitive) {
2946 case Layout::kPoints_Primitive: // break
2947 case Layout::kLines_Primitive:
2948 skInSize = 1;
2949 break;
2950 case Layout::kLinesAdjacency_Primitive: // break
2951 skInSize = 2;
2952 break;
2953 case Layout::kTriangles_Primitive: // break
2954 case Layout::kTrianglesAdjacency_Primitive:
2955 skInSize = 3;
2956 break;
2957 default:
2958 break;
2959 }
2960 }
2961 break;
2962 }
2963 default:
2964 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002965 }
2966 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002967 for (const auto& e : program) {
2968 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
2969 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05002970 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
2971 ASSERT(skInSize != -1);
2972 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
2973 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002974 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04002975 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2976 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
2977 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05002978 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002979 }
2980 }
2981 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002982 for (const auto& e : program) {
2983 if (e.fKind == ProgramElement::kVar_Kind) {
2984 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002985 }
2986 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002987 for (const auto& e : program) {
2988 if (e.fKind == ProgramElement::kFunction_Kind) {
2989 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002990 }
2991 }
ethannicholasd598f792016-07-25 10:08:54 -07002992 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002993 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002994 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002995 main = entry.first;
2996 }
2997 }
2998 ASSERT(main);
2999 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003000 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003001 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003002 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
3003 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3004 var->fModifiers.fLayout.fBuiltin != SK_IN_BUILTIN &&
3005 var->fModifiers.fLayout.fBuiltin != SK_OUT_BUILTIN) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003006 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003007 }
3008 }
3009 this->writeCapabilities(out);
3010 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3011 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003012 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003013 (int32_t) interfaceVars.size(), out);
3014 switch (program.fKind) {
3015 case Program::kVertex_Kind:
3016 this->writeWord(SpvExecutionModelVertex, out);
3017 break;
3018 case Program::kFragment_Kind:
3019 this->writeWord(SpvExecutionModelFragment, out);
3020 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003021 case Program::kGeometry_Kind:
3022 this->writeWord(SpvExecutionModelGeometry, out);
3023 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003024 default:
3025 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003026 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003027 SpvId entryPoint = fFunctionMap[main];
3028 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003029 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003030 for (int var : interfaceVars) {
3031 this->writeWord(var, out);
3032 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003033 if (program.fKind == Program::kGeometry_Kind) {
3034 this->writeGeometryShaderExecutionMode(entryPoint, out);
3035 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003036 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003037 this->writeInstruction(SpvOpExecutionMode,
3038 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003039 SpvExecutionModeOriginUpperLeft,
3040 out);
3041 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003042 for (const auto& e : program) {
3043 if (e.fKind == ProgramElement::kExtension_Kind) {
3044 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003045 }
3046 }
Greg Daniel64773e62016-11-22 09:44:03 -05003047
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003048 write_stringstream(fExtraGlobalsBuffer, out);
3049 write_stringstream(fNameBuffer, out);
3050 write_stringstream(fDecorationBuffer, out);
3051 write_stringstream(fConstantBuffer, out);
3052 write_stringstream(fExternalFunctionsBuffer, out);
3053 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003054}
3055
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003056bool SPIRVCodeGenerator::generateCode() {
3057 ASSERT(!fErrors.errorCount());
3058 this->writeWord(SpvMagicNumber, *fOut);
3059 this->writeWord(SpvVersion, *fOut);
3060 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003061 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003062 this->writeInstructions(fProgram, buffer);
3063 this->writeWord(fIdCount, *fOut);
3064 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003065 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003066 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003067}
3068
3069}