SpirvBuilder.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119
  1. //===--- SpirvBuilder.cpp - SPIR-V Builder Implementation --------*- C++ -*-==//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "clang/SPIRV/SpirvBuilder.h"
  10. #include "CapabilityVisitor.h"
  11. #include "EmitVisitor.h"
  12. #include "LiteralTypeVisitor.h"
  13. #include "LowerTypeVisitor.h"
  14. #include "NonUniformVisitor.h"
  15. #include "PreciseVisitor.h"
  16. #include "RelaxedPrecisionVisitor.h"
  17. #include "RemoveBufferBlockVisitor.h"
  18. #include "clang/SPIRV/AstTypeProbe.h"
  19. namespace clang {
  20. namespace spirv {
  21. SpirvBuilder::SpirvBuilder(ASTContext &ac, SpirvContext &ctx,
  22. const SpirvCodeGenOptions &opt)
  23. : astContext(ac), context(ctx), mod(nullptr), function(nullptr),
  24. spirvOptions(opt), builtinVars(), stringLiterals() {
  25. mod = new (context) SpirvModule;
  26. }
  27. SpirvFunction *SpirvBuilder::beginFunction(QualType returnType,
  28. llvm::ArrayRef<QualType> paramTypes,
  29. SourceLocation loc,
  30. llvm::StringRef funcName,
  31. bool isPrecise,
  32. SpirvFunction *func) {
  33. assert(!function && "found nested function");
  34. if (func) {
  35. function = func;
  36. function->setAstReturnType(returnType);
  37. function->setAstParamTypes(paramTypes);
  38. function->setSourceLocation(loc);
  39. function->setFunctionName(funcName);
  40. function->setPrecise(isPrecise);
  41. } else {
  42. function = new (context)
  43. SpirvFunction(returnType, paramTypes, loc, funcName, isPrecise);
  44. }
  45. return function;
  46. }
  47. SpirvFunctionParameter *SpirvBuilder::addFnParam(QualType ptrType,
  48. bool isPrecise,
  49. SourceLocation loc,
  50. llvm::StringRef name) {
  51. assert(function && "found detached parameter");
  52. auto *param = new (context) SpirvFunctionParameter(ptrType, isPrecise, loc);
  53. param->setStorageClass(spv::StorageClass::Function);
  54. param->setDebugName(name);
  55. function->addParameter(param);
  56. return param;
  57. }
  58. SpirvVariable *SpirvBuilder::addFnVar(QualType valueType, SourceLocation loc,
  59. llvm::StringRef name, bool isPrecise,
  60. SpirvInstruction *init) {
  61. assert(function && "found detached local variable");
  62. auto *var = new (context) SpirvVariable(
  63. valueType, loc, spv::StorageClass::Function, isPrecise, init);
  64. var->setDebugName(name);
  65. function->addVariable(var);
  66. return var;
  67. }
  68. void SpirvBuilder::endFunction() {
  69. assert(function && "no active function");
  70. // Move all basic blocks into the current function.
  71. // TODO: we should adjust the order the basic blocks according to
  72. // SPIR-V validation rules.
  73. for (auto *bb : basicBlocks) {
  74. function->addBasicBlock(bb);
  75. }
  76. basicBlocks.clear();
  77. mod->addFunction(function);
  78. function = nullptr;
  79. insertPoint = nullptr;
  80. }
  81. SpirvBasicBlock *SpirvBuilder::createBasicBlock(llvm::StringRef name) {
  82. assert(function && "found detached basic block");
  83. auto *bb = new (context) SpirvBasicBlock(name);
  84. basicBlocks.push_back(bb);
  85. return bb;
  86. }
  87. void SpirvBuilder::addSuccessor(SpirvBasicBlock *successorBB) {
  88. assert(insertPoint && "null insert point");
  89. insertPoint->addSuccessor(successorBB);
  90. }
  91. void SpirvBuilder::setMergeTarget(SpirvBasicBlock *mergeLabel) {
  92. assert(insertPoint && "null insert point");
  93. insertPoint->setMergeTarget(mergeLabel);
  94. }
  95. void SpirvBuilder::setContinueTarget(SpirvBasicBlock *continueLabel) {
  96. assert(insertPoint && "null insert point");
  97. insertPoint->setContinueTarget(continueLabel);
  98. }
  99. SpirvCompositeConstruct *SpirvBuilder::createCompositeConstruct(
  100. QualType resultType, llvm::ArrayRef<SpirvInstruction *> constituents,
  101. SourceLocation loc) {
  102. assert(insertPoint && "null insert point");
  103. auto *instruction =
  104. new (context) SpirvCompositeConstruct(resultType, loc, constituents);
  105. insertPoint->addInstruction(instruction);
  106. if (!constituents.empty()) {
  107. instruction->setLayoutRule(constituents[0]->getLayoutRule());
  108. }
  109. return instruction;
  110. }
  111. SpirvCompositeExtract *SpirvBuilder::createCompositeExtract(
  112. QualType resultType, SpirvInstruction *composite,
  113. llvm::ArrayRef<uint32_t> indexes, SourceLocation loc) {
  114. assert(insertPoint && "null insert point");
  115. auto *instruction =
  116. new (context) SpirvCompositeExtract(resultType, loc, composite, indexes);
  117. instruction->setRValue();
  118. insertPoint->addInstruction(instruction);
  119. return instruction;
  120. }
  121. SpirvCompositeInsert *SpirvBuilder::createCompositeInsert(
  122. QualType resultType, SpirvInstruction *composite,
  123. llvm::ArrayRef<uint32_t> indices, SpirvInstruction *object,
  124. SourceLocation loc) {
  125. assert(insertPoint && "null insert point");
  126. auto *instruction = new (context)
  127. SpirvCompositeInsert(resultType, loc, composite, object, indices);
  128. insertPoint->addInstruction(instruction);
  129. return instruction;
  130. }
  131. SpirvVectorShuffle *SpirvBuilder::createVectorShuffle(
  132. QualType resultType, SpirvInstruction *vector1, SpirvInstruction *vector2,
  133. llvm::ArrayRef<uint32_t> selectors, SourceLocation loc) {
  134. assert(insertPoint && "null insert point");
  135. auto *instruction = new (context)
  136. SpirvVectorShuffle(resultType, loc, vector1, vector2, selectors);
  137. instruction->setRValue();
  138. insertPoint->addInstruction(instruction);
  139. return instruction;
  140. }
  141. SpirvLoad *SpirvBuilder::createLoad(QualType resultType,
  142. SpirvInstruction *pointer,
  143. SourceLocation loc) {
  144. assert(insertPoint && "null insert point");
  145. auto *instruction = new (context) SpirvLoad(resultType, loc, pointer);
  146. instruction->setStorageClass(pointer->getStorageClass());
  147. instruction->setLayoutRule(pointer->getLayoutRule());
  148. instruction->setRValue(true);
  149. if (pointer->containsAliasComponent() &&
  150. isAKindOfStructuredOrByteBuffer(resultType)) {
  151. instruction->setStorageClass(spv::StorageClass::Uniform);
  152. // Now it is a pointer to the global resource, which is lvalue.
  153. instruction->setRValue(false);
  154. // Set to false to indicate that we've performed dereference over the
  155. // pointer-to-pointer and now should fallback to the normal path
  156. instruction->setContainsAliasComponent(false);
  157. }
  158. insertPoint->addInstruction(instruction);
  159. return instruction;
  160. }
  161. SpirvCopyObject *SpirvBuilder::createCopyObject(QualType resultType,
  162. SpirvInstruction *pointer,
  163. SourceLocation loc) {
  164. assert(insertPoint && "null insert point");
  165. auto *instruction = new (context) SpirvCopyObject(resultType, loc, pointer);
  166. instruction->setStorageClass(pointer->getStorageClass());
  167. instruction->setLayoutRule(pointer->getLayoutRule());
  168. // The result of OpCopyObject is always an rvalue.
  169. instruction->setRValue(true);
  170. insertPoint->addInstruction(instruction);
  171. return instruction;
  172. }
  173. SpirvLoad *SpirvBuilder::createLoad(const SpirvType *resultType,
  174. SpirvInstruction *pointer,
  175. SourceLocation loc) {
  176. assert(insertPoint && "null insert point");
  177. auto *instruction = new (context) SpirvLoad(/*QualType*/ {}, loc, pointer);
  178. instruction->setResultType(resultType);
  179. instruction->setStorageClass(pointer->getStorageClass());
  180. // Special case for legalization. We could have point-to-pointer types.
  181. // For example:
  182. //
  183. // %var = OpVariable %_ptr_Private__ptr_Uniform_type_X Private
  184. // %1 = OpLoad %_ptr_Uniform_type_X %var
  185. //
  186. // Loading from %var should result in Uniform storage class, not Private.
  187. if (const auto *ptrType = dyn_cast<SpirvPointerType>(resultType)) {
  188. instruction->setStorageClass(ptrType->getStorageClass());
  189. }
  190. instruction->setLayoutRule(pointer->getLayoutRule());
  191. instruction->setRValue(true);
  192. insertPoint->addInstruction(instruction);
  193. return instruction;
  194. }
  195. void SpirvBuilder::createStore(SpirvInstruction *address,
  196. SpirvInstruction *value, SourceLocation loc) {
  197. assert(insertPoint && "null insert point");
  198. auto *instruction = new (context) SpirvStore(loc, address, value);
  199. insertPoint->addInstruction(instruction);
  200. }
  201. SpirvFunctionCall *
  202. SpirvBuilder::createFunctionCall(QualType returnType, SpirvFunction *func,
  203. llvm::ArrayRef<SpirvInstruction *> params,
  204. SourceLocation loc) {
  205. assert(insertPoint && "null insert point");
  206. auto *instruction =
  207. new (context) SpirvFunctionCall(returnType, loc, func, params);
  208. instruction->setRValue(func->isRValue());
  209. instruction->setContainsAliasComponent(func->constainsAliasComponent());
  210. if (func->constainsAliasComponent() &&
  211. isAKindOfStructuredOrByteBuffer(returnType)) {
  212. instruction->setStorageClass(spv::StorageClass::Uniform);
  213. // Now it is a pointer to the global resource, which is lvalue.
  214. instruction->setRValue(false);
  215. // Set to false to indicate that we've performed dereference over the
  216. // pointer-to-pointer and now should fallback to the normal path
  217. instruction->setContainsAliasComponent(false);
  218. }
  219. insertPoint->addInstruction(instruction);
  220. return instruction;
  221. }
  222. SpirvAccessChain *
  223. SpirvBuilder::createAccessChain(QualType resultType, SpirvInstruction *base,
  224. llvm::ArrayRef<SpirvInstruction *> indexes,
  225. SourceLocation loc) {
  226. assert(insertPoint && "null insert point");
  227. auto *instruction =
  228. new (context) SpirvAccessChain(resultType, loc, base, indexes);
  229. instruction->setStorageClass(base->getStorageClass());
  230. instruction->setLayoutRule(base->getLayoutRule());
  231. instruction->setContainsAliasComponent(base->containsAliasComponent());
  232. // If doing an access chain into a structured or byte address buffer, make
  233. // sure the layout rule is sBufferLayoutRule.
  234. if (base->hasAstResultType() &&
  235. isAKindOfStructuredOrByteBuffer(base->getAstResultType()))
  236. instruction->setLayoutRule(spirvOptions.sBufferLayoutRule);
  237. insertPoint->addInstruction(instruction);
  238. return instruction;
  239. }
  240. SpirvUnaryOp *SpirvBuilder::createUnaryOp(spv::Op op, QualType resultType,
  241. SpirvInstruction *operand,
  242. SourceLocation loc) {
  243. assert(insertPoint && "null insert point");
  244. auto *instruction = new (context) SpirvUnaryOp(op, resultType, loc, operand);
  245. insertPoint->addInstruction(instruction);
  246. return instruction;
  247. }
  248. SpirvBinaryOp *SpirvBuilder::createBinaryOp(spv::Op op, QualType resultType,
  249. SpirvInstruction *lhs,
  250. SpirvInstruction *rhs,
  251. SourceLocation loc) {
  252. assert(insertPoint && "null insert point");
  253. auto *instruction =
  254. new (context) SpirvBinaryOp(op, resultType, loc, lhs, rhs);
  255. insertPoint->addInstruction(instruction);
  256. return instruction;
  257. }
  258. SpirvSpecConstantBinaryOp *SpirvBuilder::createSpecConstantBinaryOp(
  259. spv::Op op, QualType resultType, SpirvInstruction *lhs,
  260. SpirvInstruction *rhs, SourceLocation loc) {
  261. assert(insertPoint && "null insert point");
  262. auto *instruction =
  263. new (context) SpirvSpecConstantBinaryOp(op, resultType, loc, lhs, rhs);
  264. insertPoint->addInstruction(instruction);
  265. return instruction;
  266. }
  267. SpirvNonUniformElect *SpirvBuilder::createGroupNonUniformElect(
  268. spv::Op op, QualType resultType, spv::Scope execScope, SourceLocation loc) {
  269. assert(insertPoint && "null insert point");
  270. auto *instruction =
  271. new (context) SpirvNonUniformElect(resultType, loc, execScope);
  272. insertPoint->addInstruction(instruction);
  273. return instruction;
  274. }
  275. SpirvNonUniformUnaryOp *SpirvBuilder::createGroupNonUniformUnaryOp(
  276. SourceLocation loc, spv::Op op, QualType resultType, spv::Scope execScope,
  277. SpirvInstruction *operand, llvm::Optional<spv::GroupOperation> groupOp) {
  278. assert(insertPoint && "null insert point");
  279. auto *instruction = new (context)
  280. SpirvNonUniformUnaryOp(op, resultType, loc, execScope, groupOp, operand);
  281. insertPoint->addInstruction(instruction);
  282. return instruction;
  283. }
  284. SpirvNonUniformBinaryOp *SpirvBuilder::createGroupNonUniformBinaryOp(
  285. spv::Op op, QualType resultType, spv::Scope execScope,
  286. SpirvInstruction *operand1, SpirvInstruction *operand2,
  287. SourceLocation loc) {
  288. assert(insertPoint && "null insert point");
  289. auto *instruction = new (context) SpirvNonUniformBinaryOp(
  290. op, resultType, loc, execScope, operand1, operand2);
  291. insertPoint->addInstruction(instruction);
  292. return instruction;
  293. }
  294. SpirvAtomic *SpirvBuilder::createAtomicOp(
  295. spv::Op opcode, QualType resultType, SpirvInstruction *originalValuePtr,
  296. spv::Scope scope, spv::MemorySemanticsMask memorySemantics,
  297. SpirvInstruction *valueToOp, SourceLocation loc) {
  298. assert(insertPoint && "null insert point");
  299. auto *instruction =
  300. new (context) SpirvAtomic(opcode, resultType, loc, originalValuePtr,
  301. scope, memorySemantics, valueToOp);
  302. insertPoint->addInstruction(instruction);
  303. return instruction;
  304. }
  305. SpirvAtomic *SpirvBuilder::createAtomicCompareExchange(
  306. QualType resultType, SpirvInstruction *originalValuePtr, spv::Scope scope,
  307. spv::MemorySemanticsMask equalMemorySemantics,
  308. spv::MemorySemanticsMask unequalMemorySemantics,
  309. SpirvInstruction *valueToOp, SpirvInstruction *comparator,
  310. SourceLocation loc) {
  311. assert(insertPoint && "null insert point");
  312. auto *instruction = new (context)
  313. SpirvAtomic(spv::Op::OpAtomicCompareExchange, resultType, loc,
  314. originalValuePtr, scope, equalMemorySemantics,
  315. unequalMemorySemantics, valueToOp, comparator);
  316. insertPoint->addInstruction(instruction);
  317. return instruction;
  318. }
  319. SpirvSampledImage *SpirvBuilder::createSampledImage(QualType imageType,
  320. SpirvInstruction *image,
  321. SpirvInstruction *sampler,
  322. SourceLocation loc) {
  323. assert(insertPoint && "null insert point");
  324. auto *sampledImage =
  325. new (context) SpirvSampledImage(imageType, loc, image, sampler);
  326. insertPoint->addInstruction(sampledImage);
  327. return sampledImage;
  328. }
  329. SpirvImageTexelPointer *SpirvBuilder::createImageTexelPointer(
  330. QualType resultType, SpirvInstruction *image, SpirvInstruction *coordinate,
  331. SpirvInstruction *sample, SourceLocation loc) {
  332. assert(insertPoint && "null insert point");
  333. auto *instruction = new (context)
  334. SpirvImageTexelPointer(resultType, loc, image, coordinate, sample);
  335. insertPoint->addInstruction(instruction);
  336. return instruction;
  337. }
  338. spv::ImageOperandsMask SpirvBuilder::composeImageOperandsMask(
  339. SpirvInstruction *bias, SpirvInstruction *lod,
  340. const std::pair<SpirvInstruction *, SpirvInstruction *> &grad,
  341. SpirvInstruction *constOffset, SpirvInstruction *varOffset,
  342. SpirvInstruction *constOffsets, SpirvInstruction *sample,
  343. SpirvInstruction *minLod) {
  344. using spv::ImageOperandsMask;
  345. // SPIR-V Image Operands from least significant bit to most significant bit
  346. // Bias, Lod, Grad, ConstOffset, Offset, ConstOffsets, Sample, MinLod
  347. auto mask = ImageOperandsMask::MaskNone;
  348. if (bias) {
  349. mask = mask | ImageOperandsMask::Bias;
  350. }
  351. if (lod) {
  352. mask = mask | ImageOperandsMask::Lod;
  353. }
  354. if (grad.first && grad.second) {
  355. mask = mask | ImageOperandsMask::Grad;
  356. }
  357. if (constOffset) {
  358. mask = mask | ImageOperandsMask::ConstOffset;
  359. }
  360. if (varOffset) {
  361. mask = mask | ImageOperandsMask::Offset;
  362. }
  363. if (constOffsets) {
  364. mask = mask | ImageOperandsMask::ConstOffsets;
  365. }
  366. if (sample) {
  367. mask = mask | ImageOperandsMask::Sample;
  368. }
  369. if (minLod) {
  370. mask = mask | ImageOperandsMask::MinLod;
  371. }
  372. return mask;
  373. }
  374. SpirvInstruction *SpirvBuilder::createImageSample(
  375. QualType texelType, QualType imageType, SpirvInstruction *image,
  376. SpirvInstruction *sampler, SpirvInstruction *coordinate,
  377. SpirvInstruction *compareVal, SpirvInstruction *bias, SpirvInstruction *lod,
  378. std::pair<SpirvInstruction *, SpirvInstruction *> grad,
  379. SpirvInstruction *constOffset, SpirvInstruction *varOffset,
  380. SpirvInstruction *constOffsets, SpirvInstruction *sample,
  381. SpirvInstruction *minLod, SpirvInstruction *residencyCode,
  382. SourceLocation loc) {
  383. assert(insertPoint && "null insert point");
  384. // The Lod and Grad image operands requires explicit-lod instructions.
  385. // Otherwise we use implicit-lod instructions.
  386. const bool isExplicit = lod || (grad.first && grad.second);
  387. const bool isSparse = (residencyCode != nullptr);
  388. spv::Op op = spv::Op::Max;
  389. if (compareVal) {
  390. op = isExplicit ? (isSparse ? spv::Op::OpImageSparseSampleDrefExplicitLod
  391. : spv::Op::OpImageSampleDrefExplicitLod)
  392. : (isSparse ? spv::Op::OpImageSparseSampleDrefImplicitLod
  393. : spv::Op::OpImageSampleDrefImplicitLod);
  394. } else {
  395. op = isExplicit ? (isSparse ? spv::Op::OpImageSparseSampleExplicitLod
  396. : spv::Op::OpImageSampleExplicitLod)
  397. : (isSparse ? spv::Op::OpImageSparseSampleImplicitLod
  398. : spv::Op::OpImageSampleImplicitLod);
  399. }
  400. // minLod is only valid with Implicit instructions and Grad instructions.
  401. // This means that we cannot have Lod and minLod together because Lod requires
  402. // explicit insturctions. So either lod or minLod or both must be zero.
  403. assert(lod == nullptr || minLod == nullptr);
  404. // An OpSampledImage is required to do the image sampling.
  405. auto *sampledImage = createSampledImage(imageType, image, sampler, loc);
  406. const auto mask = composeImageOperandsMask(
  407. bias, lod, grad, constOffset, varOffset, constOffsets, sample, minLod);
  408. auto *imageSampleInst = new (context)
  409. SpirvImageOp(op, texelType, loc, sampledImage, coordinate, mask,
  410. compareVal, bias, lod, grad.first, grad.second, constOffset,
  411. varOffset, constOffsets, sample, minLod);
  412. insertPoint->addInstruction(imageSampleInst);
  413. if (isSparse) {
  414. // Write the Residency Code
  415. const auto status = createCompositeExtract(astContext.UnsignedIntTy,
  416. imageSampleInst, {0}, loc);
  417. createStore(residencyCode, status, loc);
  418. // Extract the real result from the struct
  419. return createCompositeExtract(texelType, imageSampleInst, {1}, loc);
  420. }
  421. return imageSampleInst;
  422. }
  423. SpirvInstruction *SpirvBuilder::createImageFetchOrRead(
  424. bool doImageFetch, QualType texelType, QualType imageType,
  425. SpirvInstruction *image, SpirvInstruction *coordinate,
  426. SpirvInstruction *lod, SpirvInstruction *constOffset,
  427. SpirvInstruction *varOffset, SpirvInstruction *constOffsets,
  428. SpirvInstruction *sample, SpirvInstruction *residencyCode,
  429. SourceLocation loc) {
  430. assert(insertPoint && "null insert point");
  431. const auto mask = composeImageOperandsMask(
  432. /*bias*/ nullptr, lod, std::make_pair(nullptr, nullptr), constOffset,
  433. varOffset, constOffsets, sample, /*minLod*/ nullptr);
  434. const bool isSparse = (residencyCode != nullptr);
  435. spv::Op op =
  436. doImageFetch
  437. ? (isSparse ? spv::Op::OpImageSparseFetch : spv::Op::OpImageFetch)
  438. : (isSparse ? spv::Op::OpImageSparseRead : spv::Op::OpImageRead);
  439. auto *fetchOrReadInst = new (context) SpirvImageOp(
  440. op, texelType, loc, image, coordinate, mask,
  441. /*dref*/ nullptr, /*bias*/ nullptr, lod, /*gradDx*/ nullptr,
  442. /*gradDy*/ nullptr, constOffset, varOffset, constOffsets, sample);
  443. insertPoint->addInstruction(fetchOrReadInst);
  444. if (isSparse) {
  445. // Write the Residency Code
  446. const auto status = createCompositeExtract(astContext.UnsignedIntTy,
  447. fetchOrReadInst, {0}, loc);
  448. createStore(residencyCode, status, loc);
  449. // Extract the real result from the struct
  450. return createCompositeExtract(texelType, fetchOrReadInst, {1}, loc);
  451. }
  452. return fetchOrReadInst;
  453. }
  454. void SpirvBuilder::createImageWrite(QualType imageType, SpirvInstruction *image,
  455. SpirvInstruction *coord,
  456. SpirvInstruction *texel,
  457. SourceLocation loc) {
  458. assert(insertPoint && "null insert point");
  459. auto *writeInst = new (context) SpirvImageOp(
  460. spv::Op::OpImageWrite, imageType, loc, image, coord,
  461. spv::ImageOperandsMask::MaskNone,
  462. /*dref*/ nullptr, /*bias*/ nullptr, /*lod*/ nullptr, /*gradDx*/ nullptr,
  463. /*gradDy*/ nullptr, /*constOffset*/ nullptr, /*varOffset*/ nullptr,
  464. /*constOffsets*/ nullptr, /*sample*/ nullptr, /*minLod*/ nullptr,
  465. /*component*/ nullptr, texel);
  466. insertPoint->addInstruction(writeInst);
  467. }
  468. SpirvInstruction *SpirvBuilder::createImageGather(
  469. QualType texelType, QualType imageType, SpirvInstruction *image,
  470. SpirvInstruction *sampler, SpirvInstruction *coordinate,
  471. SpirvInstruction *component, SpirvInstruction *compareVal,
  472. SpirvInstruction *constOffset, SpirvInstruction *varOffset,
  473. SpirvInstruction *constOffsets, SpirvInstruction *sample,
  474. SpirvInstruction *residencyCode, SourceLocation loc) {
  475. assert(insertPoint && "null insert point");
  476. // An OpSampledImage is required to do the image sampling.
  477. auto *sampledImage = createSampledImage(imageType, image, sampler, loc);
  478. // TODO: Update ImageGather to accept minLod if necessary.
  479. const auto mask = composeImageOperandsMask(
  480. /*bias*/ nullptr, /*lod*/ nullptr, std::make_pair(nullptr, nullptr),
  481. constOffset, varOffset, constOffsets, sample, /*minLod*/ nullptr);
  482. spv::Op op = compareVal ? (residencyCode ? spv::Op::OpImageSparseDrefGather
  483. : spv::Op::OpImageDrefGather)
  484. : (residencyCode ? spv::Op::OpImageSparseGather
  485. : spv::Op::OpImageGather);
  486. // Note: OpImageSparseDrefGather and OpImageDrefGather do not take the
  487. // component parameter.
  488. if (compareVal)
  489. component = nullptr;
  490. auto *imageInstruction = new (context) SpirvImageOp(
  491. op, texelType, loc, sampledImage, coordinate, mask, compareVal,
  492. /*bias*/ nullptr, /*lod*/ nullptr, /*gradDx*/ nullptr,
  493. /*gradDy*/ nullptr, constOffset, varOffset, constOffsets, sample,
  494. /*minLod*/ nullptr, component);
  495. insertPoint->addInstruction(imageInstruction);
  496. if (residencyCode) {
  497. // Write the Residency Code
  498. const auto status = createCompositeExtract(astContext.UnsignedIntTy,
  499. imageInstruction, {0}, loc);
  500. createStore(residencyCode, status, loc);
  501. // Extract the real result from the struct
  502. return createCompositeExtract(texelType, imageInstruction, {1}, loc);
  503. }
  504. return imageInstruction;
  505. }
  506. SpirvImageSparseTexelsResident *
  507. SpirvBuilder::createImageSparseTexelsResident(SpirvInstruction *residentCode,
  508. SourceLocation loc) {
  509. assert(insertPoint && "null insert point");
  510. auto *inst = new (context)
  511. SpirvImageSparseTexelsResident(astContext.BoolTy, loc, residentCode);
  512. insertPoint->addInstruction(inst);
  513. return inst;
  514. }
  515. SpirvImageQuery *SpirvBuilder::createImageQuery(spv::Op opcode,
  516. QualType resultType,
  517. SourceLocation loc,
  518. SpirvInstruction *image,
  519. SpirvInstruction *lod) {
  520. assert(insertPoint && "null insert point");
  521. SpirvInstruction *lodParam = nullptr;
  522. SpirvInstruction *coordinateParam = nullptr;
  523. if (opcode == spv::Op::OpImageQuerySizeLod)
  524. lodParam = lod;
  525. if (opcode == spv::Op::OpImageQueryLod)
  526. coordinateParam = lod;
  527. auto *inst = new (context) SpirvImageQuery(opcode, resultType, loc, image,
  528. lodParam, coordinateParam);
  529. insertPoint->addInstruction(inst);
  530. return inst;
  531. }
  532. SpirvSelect *SpirvBuilder::createSelect(QualType resultType,
  533. SpirvInstruction *condition,
  534. SpirvInstruction *trueValue,
  535. SpirvInstruction *falseValue,
  536. SourceLocation loc) {
  537. assert(insertPoint && "null insert point");
  538. auto *inst = new (context)
  539. SpirvSelect(resultType, loc, condition, trueValue, falseValue);
  540. insertPoint->addInstruction(inst);
  541. return inst;
  542. }
  543. void SpirvBuilder::createSwitch(
  544. SpirvBasicBlock *mergeLabel, SpirvInstruction *selector,
  545. SpirvBasicBlock *defaultLabel,
  546. llvm::ArrayRef<std::pair<uint32_t, SpirvBasicBlock *>> target,
  547. SourceLocation loc) {
  548. assert(insertPoint && "null insert point");
  549. // Create the OpSelectioMerege.
  550. auto *selectionMerge = new (context)
  551. SpirvSelectionMerge(loc, mergeLabel, spv::SelectionControlMask::MaskNone);
  552. insertPoint->addInstruction(selectionMerge);
  553. // Create the OpSwitch.
  554. auto *switchInst =
  555. new (context) SpirvSwitch(loc, selector, defaultLabel, target);
  556. insertPoint->addInstruction(switchInst);
  557. }
  558. void SpirvBuilder::createKill(SourceLocation loc) {
  559. assert(insertPoint && "null insert point");
  560. auto *kill = new (context) SpirvKill(loc);
  561. insertPoint->addInstruction(kill);
  562. }
  563. void SpirvBuilder::createBranch(SpirvBasicBlock *targetLabel,
  564. SourceLocation loc, SpirvBasicBlock *mergeBB,
  565. SpirvBasicBlock *continueBB,
  566. spv::LoopControlMask loopControl) {
  567. assert(insertPoint && "null insert point");
  568. if (mergeBB && continueBB) {
  569. auto *loopMerge =
  570. new (context) SpirvLoopMerge(loc, mergeBB, continueBB, loopControl);
  571. insertPoint->addInstruction(loopMerge);
  572. }
  573. auto *branch = new (context) SpirvBranch(loc, targetLabel);
  574. insertPoint->addInstruction(branch);
  575. }
  576. void SpirvBuilder::createConditionalBranch(
  577. SpirvInstruction *condition, SpirvBasicBlock *trueLabel,
  578. SpirvBasicBlock *falseLabel, SourceLocation loc,
  579. SpirvBasicBlock *mergeLabel, SpirvBasicBlock *continueLabel,
  580. spv::SelectionControlMask selectionControl,
  581. spv::LoopControlMask loopControl) {
  582. assert(insertPoint && "null insert point");
  583. if (mergeLabel) {
  584. if (continueLabel) {
  585. auto *loopMerge = new (context)
  586. SpirvLoopMerge(loc, mergeLabel, continueLabel, loopControl);
  587. insertPoint->addInstruction(loopMerge);
  588. } else {
  589. auto *selectionMerge =
  590. new (context) SpirvSelectionMerge(loc, mergeLabel, selectionControl);
  591. insertPoint->addInstruction(selectionMerge);
  592. }
  593. }
  594. auto *branchConditional = new (context)
  595. SpirvBranchConditional(loc, condition, trueLabel, falseLabel);
  596. insertPoint->addInstruction(branchConditional);
  597. }
  598. void SpirvBuilder::createReturn(SourceLocation loc) {
  599. assert(insertPoint && "null insert point");
  600. insertPoint->addInstruction(new (context) SpirvReturn(loc));
  601. }
  602. void SpirvBuilder::createReturnValue(SpirvInstruction *value,
  603. SourceLocation loc) {
  604. assert(insertPoint && "null insert point");
  605. insertPoint->addInstruction(new (context) SpirvReturn(loc, value));
  606. }
  607. SpirvInstruction *
  608. SpirvBuilder::createGLSLExtInst(QualType resultType, GLSLstd450 inst,
  609. llvm::ArrayRef<SpirvInstruction *> operands,
  610. SourceLocation loc) {
  611. assert(insertPoint && "null insert point");
  612. auto *extInst = new (context) SpirvExtInst(
  613. resultType, loc, getExtInstSet("GLSL.std.450"), inst, operands);
  614. insertPoint->addInstruction(extInst);
  615. return extInst;
  616. }
  617. SpirvInstruction *
  618. SpirvBuilder::createGLSLExtInst(const SpirvType *resultType, GLSLstd450 inst,
  619. llvm::ArrayRef<SpirvInstruction *> operands,
  620. SourceLocation loc) {
  621. assert(insertPoint && "null insert point");
  622. auto *extInst = new (context) SpirvExtInst(
  623. /*QualType*/ {}, loc, getExtInstSet("GLSL.std.450"), inst, operands);
  624. extInst->setResultType(resultType);
  625. insertPoint->addInstruction(extInst);
  626. return extInst;
  627. }
  628. SpirvInstruction *SpirvBuilder::createNonSemanticDebugPrintfExtInst(
  629. QualType resultType, NonSemanticDebugPrintfInstructions instId,
  630. llvm::ArrayRef<SpirvInstruction *> operands, SourceLocation loc) {
  631. assert(insertPoint && "null insert point");
  632. auto *extInst = new (context)
  633. SpirvExtInst(resultType, loc, getExtInstSet("NonSemantic.DebugPrintf"),
  634. instId, operands);
  635. insertPoint->addInstruction(extInst);
  636. return extInst;
  637. }
  638. void SpirvBuilder::createBarrier(spv::Scope memoryScope,
  639. spv::MemorySemanticsMask memorySemantics,
  640. llvm::Optional<spv::Scope> exec,
  641. SourceLocation loc) {
  642. assert(insertPoint && "null insert point");
  643. SpirvBarrier *barrier =
  644. new (context) SpirvBarrier(loc, memoryScope, memorySemantics, exec);
  645. insertPoint->addInstruction(barrier);
  646. }
  647. SpirvBitFieldInsert *SpirvBuilder::createBitFieldInsert(
  648. QualType resultType, SpirvInstruction *base, SpirvInstruction *insert,
  649. SpirvInstruction *offset, SpirvInstruction *count, SourceLocation loc) {
  650. assert(insertPoint && "null insert point");
  651. auto *inst = new (context)
  652. SpirvBitFieldInsert(resultType, loc, base, insert, offset, count);
  653. insertPoint->addInstruction(inst);
  654. return inst;
  655. }
  656. SpirvBitFieldExtract *SpirvBuilder::createBitFieldExtract(
  657. QualType resultType, SpirvInstruction *base, SpirvInstruction *offset,
  658. SpirvInstruction *count, bool isSigned, SourceLocation loc) {
  659. assert(insertPoint && "null insert point");
  660. auto *inst = new (context)
  661. SpirvBitFieldExtract(resultType, loc, base, offset, count, isSigned);
  662. insertPoint->addInstruction(inst);
  663. return inst;
  664. }
  665. void SpirvBuilder::createEmitVertex(SourceLocation loc) {
  666. assert(insertPoint && "null insert point");
  667. auto *inst = new (context) SpirvEmitVertex(loc);
  668. insertPoint->addInstruction(inst);
  669. }
  670. void SpirvBuilder::createEndPrimitive(SourceLocation loc) {
  671. assert(insertPoint && "null insert point");
  672. auto *inst = new (context) SpirvEndPrimitive(loc);
  673. insertPoint->addInstruction(inst);
  674. }
  675. SpirvArrayLength *SpirvBuilder::createArrayLength(QualType resultType,
  676. SourceLocation loc,
  677. SpirvInstruction *structure,
  678. uint32_t arrayMember) {
  679. assert(insertPoint && "null insert point");
  680. auto *inst =
  681. new (context) SpirvArrayLength(resultType, loc, structure, arrayMember);
  682. insertPoint->addInstruction(inst);
  683. return inst;
  684. }
  685. SpirvInstruction *
  686. SpirvBuilder::createRayTracingOpsNV(spv::Op opcode, QualType resultType,
  687. ArrayRef<SpirvInstruction *> operands,
  688. SourceLocation loc) {
  689. assert(insertPoint && "null insert point");
  690. auto *inst =
  691. new (context) SpirvRayTracingOpNV(resultType, opcode, operands, loc);
  692. insertPoint->addInstruction(inst);
  693. return inst;
  694. }
  695. SpirvInstruction *
  696. SpirvBuilder::createDemoteToHelperInvocationEXT(SourceLocation loc) {
  697. assert(insertPoint && "null insert point");
  698. auto *inst = new (context) SpirvDemoteToHelperInvocationEXT(loc);
  699. insertPoint->addInstruction(inst);
  700. return inst;
  701. }
  702. SpirvInstruction *
  703. SpirvBuilder::createRayQueryOpsKHR(spv::Op opcode, QualType resultType,
  704. ArrayRef<SpirvInstruction *> operands,
  705. bool cullFlags, SourceLocation loc) {
  706. assert(insertPoint && "null insert point");
  707. auto *inst = new (context)
  708. SpirvRayQueryOpKHR(resultType, opcode, operands, cullFlags, loc);
  709. insertPoint->addInstruction(inst);
  710. return inst;
  711. }
  712. void SpirvBuilder::addModuleProcessed(llvm::StringRef process) {
  713. mod->addModuleProcessed(new (context) SpirvModuleProcessed({}, process));
  714. }
  715. SpirvExtInstImport *SpirvBuilder::getExtInstSet(llvm::StringRef extName) {
  716. SpirvExtInstImport *set = mod->getExtInstSet(extName);
  717. if (!set) {
  718. // The extended instruction set is likely required for several different
  719. // reasons. We can't pinpoint the source location for one specific function.
  720. set = new (context) SpirvExtInstImport(/*SourceLocation*/ {}, extName);
  721. mod->addExtInstSet(set);
  722. }
  723. return set;
  724. }
  725. SpirvVariable *SpirvBuilder::addStageIOVar(QualType type,
  726. spv::StorageClass storageClass,
  727. std::string name, bool isPrecise,
  728. SourceLocation loc) {
  729. // Note: We store the underlying type in the variable, *not* the pointer type.
  730. auto *var = new (context) SpirvVariable(type, loc, storageClass, isPrecise);
  731. var->setDebugName(name);
  732. mod->addVariable(var);
  733. return var;
  734. }
  735. SpirvVariable *SpirvBuilder::addStageBuiltinVar(QualType type,
  736. spv::StorageClass storageClass,
  737. spv::BuiltIn builtin,
  738. bool isPrecise,
  739. SourceLocation loc) {
  740. // If the built-in variable has already been added (via a built-in alias),
  741. // return the existing variable.
  742. auto found = std::find_if(
  743. builtinVars.begin(), builtinVars.end(),
  744. [storageClass, builtin](const BuiltInVarInfo &varInfo) {
  745. return varInfo.sc == storageClass && varInfo.builtIn == builtin;
  746. });
  747. if (found != builtinVars.end()) {
  748. return found->variable;
  749. }
  750. // Note: We store the underlying type in the variable, *not* the pointer type.
  751. auto *var = new (context) SpirvVariable(type, loc, storageClass, isPrecise);
  752. mod->addVariable(var);
  753. // Decorate with the specified Builtin
  754. auto *decor = new (context) SpirvDecoration(
  755. loc, var, spv::Decoration::BuiltIn, {static_cast<uint32_t>(builtin)});
  756. mod->addDecoration(decor);
  757. // Add variable to cache.
  758. builtinVars.emplace_back(storageClass, builtin, var);
  759. return var;
  760. }
  761. SpirvVariable *
  762. SpirvBuilder::addModuleVar(QualType type, spv::StorageClass storageClass,
  763. bool isPrecise, llvm::StringRef name,
  764. llvm::Optional<SpirvInstruction *> init,
  765. SourceLocation loc) {
  766. assert(storageClass != spv::StorageClass::Function);
  767. // Note: We store the underlying type in the variable, *not* the pointer type.
  768. auto *var =
  769. new (context) SpirvVariable(type, loc, storageClass, isPrecise,
  770. init.hasValue() ? init.getValue() : nullptr);
  771. var->setDebugName(name);
  772. mod->addVariable(var);
  773. return var;
  774. }
  775. SpirvVariable *SpirvBuilder::addModuleVar(
  776. const SpirvType *type, spv::StorageClass storageClass, bool isPrecise,
  777. llvm::StringRef name, llvm::Optional<SpirvInstruction *> init,
  778. SourceLocation loc) {
  779. assert(storageClass != spv::StorageClass::Function);
  780. // Note: We store the underlying type in the variable, *not* the pointer type.
  781. auto *var =
  782. new (context) SpirvVariable(/*QualType*/ {}, loc, storageClass, isPrecise,
  783. init.hasValue() ? init.getValue() : nullptr);
  784. var->setResultType(type);
  785. var->setDebugName(name);
  786. mod->addVariable(var);
  787. return var;
  788. }
  789. void SpirvBuilder::decorateLocation(SpirvInstruction *target,
  790. uint32_t location) {
  791. auto *decor =
  792. new (context) SpirvDecoration(target->getSourceLocation(), target,
  793. spv::Decoration::Location, {location});
  794. mod->addDecoration(decor);
  795. }
  796. void SpirvBuilder::decorateIndex(SpirvInstruction *target, uint32_t index,
  797. SourceLocation srcLoc) {
  798. auto *decor = new (context)
  799. SpirvDecoration(srcLoc, target, spv::Decoration::Index, {index});
  800. mod->addDecoration(decor);
  801. }
  802. void SpirvBuilder::decorateDSetBinding(SpirvVariable *target,
  803. uint32_t setNumber,
  804. uint32_t bindingNumber) {
  805. const SourceLocation srcLoc = target->getSourceLocation();
  806. auto *dset = new (context) SpirvDecoration(
  807. srcLoc, target, spv::Decoration::DescriptorSet, {setNumber});
  808. mod->addDecoration(dset);
  809. auto *binding = new (context) SpirvDecoration(
  810. srcLoc, target, spv::Decoration::Binding, {bindingNumber});
  811. target->setDescriptorSetNo(setNumber);
  812. target->setBindingNo(bindingNumber);
  813. mod->addDecoration(binding);
  814. }
  815. void SpirvBuilder::decorateSpecId(SpirvInstruction *target, uint32_t specId,
  816. SourceLocation srcLoc) {
  817. auto *decor = new (context)
  818. SpirvDecoration(srcLoc, target, spv::Decoration::SpecId, {specId});
  819. mod->addDecoration(decor);
  820. }
  821. void SpirvBuilder::decorateInputAttachmentIndex(SpirvInstruction *target,
  822. uint32_t indexNumber,
  823. SourceLocation srcLoc) {
  824. auto *decor = new (context) SpirvDecoration(
  825. srcLoc, target, spv::Decoration::InputAttachmentIndex, {indexNumber});
  826. mod->addDecoration(decor);
  827. }
  828. void SpirvBuilder::decorateCounterBuffer(SpirvInstruction *mainBuffer,
  829. SpirvInstruction *counterBuffer,
  830. SourceLocation srcLoc) {
  831. if (spirvOptions.enableReflect) {
  832. auto *decor = new (context) SpirvDecoration(
  833. srcLoc, mainBuffer, spv::Decoration::HlslCounterBufferGOOGLE,
  834. {counterBuffer});
  835. mod->addDecoration(decor);
  836. }
  837. }
  838. void SpirvBuilder::decorateHlslSemantic(SpirvInstruction *target,
  839. llvm::StringRef semantic,
  840. llvm::Optional<uint32_t> memberIdx) {
  841. if (spirvOptions.enableReflect) {
  842. auto *decor = new (context) SpirvDecoration(
  843. target->getSourceLocation(), target,
  844. spv::Decoration::HlslSemanticGOOGLE, semantic, memberIdx);
  845. mod->addDecoration(decor);
  846. }
  847. }
  848. void SpirvBuilder::decorateCentroid(SpirvInstruction *target,
  849. SourceLocation srcLoc) {
  850. auto *decor =
  851. new (context) SpirvDecoration(srcLoc, target, spv::Decoration::Centroid);
  852. mod->addDecoration(decor);
  853. }
  854. void SpirvBuilder::decorateFlat(SpirvInstruction *target,
  855. SourceLocation srcLoc) {
  856. auto *decor =
  857. new (context) SpirvDecoration(srcLoc, target, spv::Decoration::Flat);
  858. mod->addDecoration(decor);
  859. }
  860. void SpirvBuilder::decorateNoPerspective(SpirvInstruction *target,
  861. SourceLocation srcLoc) {
  862. auto *decor = new (context)
  863. SpirvDecoration(srcLoc, target, spv::Decoration::NoPerspective);
  864. mod->addDecoration(decor);
  865. }
  866. void SpirvBuilder::decorateSample(SpirvInstruction *target,
  867. SourceLocation srcLoc) {
  868. auto *decor =
  869. new (context) SpirvDecoration(srcLoc, target, spv::Decoration::Sample);
  870. mod->addDecoration(decor);
  871. }
  872. void SpirvBuilder::decoratePatch(SpirvInstruction *target,
  873. SourceLocation srcLoc) {
  874. auto *decor =
  875. new (context) SpirvDecoration(srcLoc, target, spv::Decoration::Patch);
  876. mod->addDecoration(decor);
  877. }
  878. void SpirvBuilder::decorateNoContraction(SpirvInstruction *target,
  879. SourceLocation srcLoc) {
  880. auto *decor = new (context)
  881. SpirvDecoration(srcLoc, target, spv::Decoration::NoContraction);
  882. mod->addDecoration(decor);
  883. }
  884. void SpirvBuilder::decoratePerPrimitiveNV(SpirvInstruction *target,
  885. SourceLocation srcLoc) {
  886. auto *decor = new (context)
  887. SpirvDecoration(srcLoc, target, spv::Decoration::PerPrimitiveNV);
  888. mod->addDecoration(decor);
  889. }
  890. void SpirvBuilder::decoratePerTaskNV(SpirvInstruction *target, uint32_t offset,
  891. SourceLocation srcLoc) {
  892. auto *decor =
  893. new (context) SpirvDecoration(srcLoc, target, spv::Decoration::PerTaskNV);
  894. mod->addDecoration(decor);
  895. decor = new (context)
  896. SpirvDecoration(srcLoc, target, spv::Decoration::Offset, {offset});
  897. mod->addDecoration(decor);
  898. }
  899. SpirvConstant *SpirvBuilder::getConstantInt(QualType type, llvm::APInt value,
  900. bool specConst) {
  901. // We do not reuse existing constant integers. Just create a new one.
  902. auto *intConst = new (context) SpirvConstantInteger(type, value, specConst);
  903. mod->addConstant(intConst);
  904. return intConst;
  905. }
  906. SpirvConstant *SpirvBuilder::getConstantFloat(QualType type,
  907. llvm::APFloat value,
  908. bool specConst) {
  909. // We do not reuse existing constant floats. Just create a new one.
  910. auto *floatConst = new (context) SpirvConstantFloat(type, value, specConst);
  911. mod->addConstant(floatConst);
  912. return floatConst;
  913. }
  914. SpirvConstant *SpirvBuilder::getConstantBool(bool value, bool specConst) {
  915. // We do not care about making unique constants at this point.
  916. auto *boolConst =
  917. new (context) SpirvConstantBoolean(astContext.BoolTy, value, specConst);
  918. mod->addConstant(boolConst);
  919. return boolConst;
  920. }
  921. SpirvConstant *
  922. SpirvBuilder::getConstantComposite(QualType compositeType,
  923. llvm::ArrayRef<SpirvConstant *> constituents,
  924. bool specConst) {
  925. // We do not care about making unique constants at this point.
  926. auto *compositeConst = new (context)
  927. SpirvConstantComposite(compositeType, constituents, specConst);
  928. mod->addConstant(compositeConst);
  929. return compositeConst;
  930. }
  931. SpirvConstant *SpirvBuilder::getConstantNull(QualType type) {
  932. // We do not care about making unique constants at this point.
  933. auto *nullConst = new (context) SpirvConstantNull(type);
  934. mod->addConstant(nullConst);
  935. return nullConst;
  936. }
  937. SpirvString *SpirvBuilder::getString(llvm::StringRef str) {
  938. // Reuse an existing instruction if possible.
  939. auto iter = stringLiterals.find(str.str());
  940. if (iter != stringLiterals.end())
  941. return iter->second;
  942. // Create a SpirvString instruction
  943. auto *instr = new (context) SpirvString(/* SourceLocation */ {}, str);
  944. instr->setRValue();
  945. stringLiterals[str.str()] = instr;
  946. mod->addString(instr);
  947. return instr;
  948. }
  949. std::vector<uint32_t> SpirvBuilder::takeModule() {
  950. // Run necessary visitor passes first
  951. LiteralTypeVisitor literalTypeVisitor(astContext, context, spirvOptions);
  952. LowerTypeVisitor lowerTypeVisitor(astContext, context, spirvOptions);
  953. CapabilityVisitor capabilityVisitor(astContext, context, spirvOptions, *this);
  954. RelaxedPrecisionVisitor relaxedPrecisionVisitor(context, spirvOptions);
  955. PreciseVisitor preciseVisitor(context, spirvOptions);
  956. NonUniformVisitor nonUniformVisitor(context, spirvOptions);
  957. RemoveBufferBlockVisitor removeBufferBlockVisitor(context, spirvOptions);
  958. EmitVisitor emitVisitor(astContext, context, spirvOptions);
  959. mod->invokeVisitor(&literalTypeVisitor, true);
  960. // Propagate NonUniform decorations
  961. mod->invokeVisitor(&nonUniformVisitor);
  962. // Lower types
  963. mod->invokeVisitor(&lowerTypeVisitor);
  964. // Add necessary capabilities and extensions
  965. mod->invokeVisitor(&capabilityVisitor);
  966. // Propagate RelaxedPrecision decorations
  967. mod->invokeVisitor(&relaxedPrecisionVisitor);
  968. // Propagate NoContraction decorations
  969. mod->invokeVisitor(&preciseVisitor, true);
  970. // Remove BufferBlock decoration if necessary (this decoration is deprecated
  971. // after SPIR-V 1.3).
  972. mod->invokeVisitor(&removeBufferBlockVisitor);
  973. // Emit SPIR-V
  974. mod->invokeVisitor(&emitVisitor);
  975. return emitVisitor.takeBinary();
  976. }
  977. } // end namespace spirv
  978. } // end namespace clang