23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/ADT/Sequence.h"
25 #include "llvm/ADT/SmallVector.h"
26 #include "llvm/ADT/StringExtras.h"
27 #include "llvm/ADT/bit.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/SaveAndRestore.h"
30 #include "llvm/Support/raw_ostream.h"
35 #define DEBUG_TYPE "spirv-deserialization"
44 isa_and_nonnull<spirv::FuncOp>(block->
getParentOp());
54 : binary(binary), context(context), unknownLoc(UnknownLoc::
get(context)),
55 module(createModuleOp()), opBuilder(module->getRegion()),
options(
options)
67 <<
"//+++---------- start deserialization ----------+++//\n";
70 if (
failed(processHeader()))
73 spirv::Opcode opcode = spirv::Opcode::OpNop;
75 auto binarySize = binary.size();
76 while (curOffset < binarySize) {
79 if (
failed(sliceInstruction(opcode, operands)))
82 if (
failed(processInstruction(opcode, operands)))
86 assert(curOffset == binarySize &&
87 "deserializer should never index beyond the binary end");
89 for (
auto &deferred : deferredInstructions) {
90 if (
failed(processInstruction(deferred.first, deferred.second,
false))) {
97 LLVM_DEBUG(logger.startLine()
98 <<
"//+++-------- completed deserialization --------+++//\n");
103 return std::move(module);
112 OperationState state(unknownLoc, spirv::ModuleOp::getOperationName());
113 spirv::ModuleOp::build(builder, state);
117 LogicalResult spirv::Deserializer::processHeader() {
120 "SPIR-V binary module must have a 5-word header");
123 return emitError(unknownLoc,
"incorrect magic number");
126 uint32_t majorVersion = (binary[1] << 8) >> 24;
127 uint32_t minorVersion = (binary[1] << 16) >> 24;
128 if (majorVersion == 1) {
129 switch (minorVersion) {
130 #define MIN_VERSION_CASE(v) \
132 version = spirv::Version::V_1_##v; \
142 #undef MIN_VERSION_CASE
144 return emitError(unknownLoc,
"unsupported SPIR-V minor version: ")
148 return emitError(unknownLoc,
"unsupported SPIR-V major version: ")
159 if (operands.size() != 1)
160 return emitError(unknownLoc,
"OpCapability must have one parameter");
162 auto cap = spirv::symbolizeCapability(operands[0]);
164 return emitError(unknownLoc,
"unknown capability: ") << operands[0];
166 capabilities.insert(*cap);
174 "OpExtension must have a literal string for the extension name");
177 unsigned wordIndex = 0;
179 if (wordIndex != words.size())
181 "unexpected trailing words in OpExtension instruction");
182 auto ext = spirv::symbolizeExtension(extName);
184 return emitError(unknownLoc,
"unknown extension: ") << extName;
186 extensions.insert(*ext);
192 if (words.size() < 2) {
194 "OpExtInstImport must have a result <id> and a literal "
195 "string for the extended instruction set name");
198 unsigned wordIndex = 1;
200 if (wordIndex != words.size()) {
202 "unexpected trailing words in OpExtInstImport");
207 void spirv::Deserializer::attachVCETriple() {
209 spirv::ModuleOp::getVCETripleAttrName(),
211 extensions.getArrayRef(), context));
216 if (operands.size() != 2)
217 return emitError(unknownLoc,
"OpMemoryModel must have two operands");
220 module->getAddressingModelAttrName(),
221 opBuilder.getAttr<spirv::AddressingModelAttr>(
222 static_cast<spirv::AddressingModel
>(operands.front())));
224 (*module)->setAttr(module->getMemoryModelAttrName(),
225 opBuilder.getAttr<spirv::MemoryModelAttr>(
226 static_cast<spirv::MemoryModel
>(operands.back())));
231 template <
typename AttrTy,
typename EnumAttrTy,
typename EnumTy>
235 StringAttr symbol, StringRef decorationName, StringRef cacheControlKind) {
236 if (words.size() != 4) {
237 return emitError(loc,
"OpDecoration with ")
238 << decorationName <<
"needs a cache control integer literal and a "
239 << cacheControlKind <<
" cache control literal";
241 unsigned cacheLevel = words[2];
242 auto cacheControlAttr =
static_cast<EnumTy
>(words[3]);
243 auto value = opBuilder.
getAttr<AttrTy>(cacheLevel, cacheControlAttr);
246 llvm::dyn_cast_or_null<ArrayAttr>(decorations[words[0]].
get(symbol)))
247 llvm::append_range(attrs, attrList);
248 attrs.push_back(value);
249 decorations[words[0]].set(symbol, opBuilder.
getArrayAttr(attrs));
257 if (words.size() < 2) {
259 unknownLoc,
"OpDecorate must have at least result <id> and Decoration");
261 auto decorationName =
262 stringifyDecoration(
static_cast<spirv::Decoration
>(words[1]));
263 if (decorationName.empty()) {
264 return emitError(unknownLoc,
"invalid Decoration code : ") << words[1];
266 auto symbol = getSymbolDecoration(decorationName);
267 switch (
static_cast<spirv::Decoration
>(words[1])) {
268 case spirv::Decoration::FPFastMathMode:
269 if (words.size() != 3) {
270 return emitError(unknownLoc,
"OpDecorate with ")
271 << decorationName <<
" needs a single integer literal";
273 decorations[words[0]].set(
275 static_cast<FPFastMathMode
>(words[2])));
277 case spirv::Decoration::FPRoundingMode:
278 if (words.size() != 3) {
279 return emitError(unknownLoc,
"OpDecorate with ")
280 << decorationName <<
" needs a single integer literal";
282 decorations[words[0]].set(
284 static_cast<FPRoundingMode
>(words[2])));
286 case spirv::Decoration::DescriptorSet:
287 case spirv::Decoration::Binding:
288 if (words.size() != 3) {
289 return emitError(unknownLoc,
"OpDecorate with ")
290 << decorationName <<
" needs a single integer literal";
292 decorations[words[0]].set(
293 symbol, opBuilder.getI32IntegerAttr(
static_cast<int32_t
>(words[2])));
295 case spirv::Decoration::BuiltIn:
296 if (words.size() != 3) {
297 return emitError(unknownLoc,
"OpDecorate with ")
298 << decorationName <<
" needs a single integer literal";
300 decorations[words[0]].set(
301 symbol, opBuilder.getStringAttr(
302 stringifyBuiltIn(
static_cast<spirv::BuiltIn
>(words[2]))));
304 case spirv::Decoration::ArrayStride:
305 if (words.size() != 3) {
306 return emitError(unknownLoc,
"OpDecorate with ")
307 << decorationName <<
" needs a single integer literal";
309 typeDecorations[words[0]] = words[2];
311 case spirv::Decoration::LinkageAttributes: {
312 if (words.size() < 4) {
313 return emitError(unknownLoc,
"OpDecorate with ")
315 <<
" needs at least 1 string and 1 integer literal";
323 unsigned wordIndex = 2;
325 auto linkageTypeAttr = opBuilder.getAttr<::mlir::spirv::LinkageTypeAttr>(
326 static_cast<::mlir::spirv::LinkageType
>(words[wordIndex++]));
327 auto linkageAttr = opBuilder.getAttr<::mlir::spirv::LinkageAttributesAttr>(
329 decorations[words[0]].set(symbol, llvm::dyn_cast<Attribute>(linkageAttr));
332 case spirv::Decoration::Aliased:
333 case spirv::Decoration::AliasedPointer:
334 case spirv::Decoration::Block:
335 case spirv::Decoration::BufferBlock:
336 case spirv::Decoration::Flat:
337 case spirv::Decoration::NonReadable:
338 case spirv::Decoration::NonWritable:
339 case spirv::Decoration::NoPerspective:
340 case spirv::Decoration::NoSignedWrap:
341 case spirv::Decoration::NoUnsignedWrap:
342 case spirv::Decoration::RelaxedPrecision:
343 case spirv::Decoration::Restrict:
344 case spirv::Decoration::RestrictPointer:
345 case spirv::Decoration::NoContraction:
346 case spirv::Decoration::Constant:
347 case spirv::Decoration::Invariant:
348 case spirv::Decoration::Patch:
349 if (words.size() != 2) {
350 return emitError(unknownLoc,
"OpDecoration with ")
351 << decorationName <<
"needs a single target <id>";
353 decorations[words[0]].set(symbol, opBuilder.getUnitAttr());
355 case spirv::Decoration::Location:
356 case spirv::Decoration::SpecId:
357 if (words.size() != 3) {
358 return emitError(unknownLoc,
"OpDecoration with ")
359 << decorationName <<
"needs a single integer literal";
361 decorations[words[0]].set(
362 symbol, opBuilder.getI32IntegerAttr(
static_cast<int32_t
>(words[2])));
364 case spirv::Decoration::CacheControlLoadINTEL: {
366 CacheControlLoadINTELAttr, LoadCacheControlAttr, LoadCacheControl>(
367 unknownLoc, opBuilder, decorations, words, symbol, decorationName,
373 case spirv::Decoration::CacheControlStoreINTEL: {
375 CacheControlStoreINTELAttr, StoreCacheControlAttr, StoreCacheControl>(
376 unknownLoc, opBuilder, decorations, words, symbol, decorationName,
383 return emitError(unknownLoc,
"unhandled Decoration : '") << decorationName;
391 if (words.size() < 3) {
393 "OpMemberDecorate must have at least 3 operands");
396 auto decoration =
static_cast<spirv::Decoration
>(words[2]);
397 if (decoration == spirv::Decoration::Offset && words.size() != 4) {
399 " missing offset specification in OpMemberDecorate with "
400 "Offset decoration");
403 if (words.size() > 3) {
404 decorationOperands = words.slice(3);
406 memberDecorationMap[words[0]][words[1]][decoration] = decorationOperands;
411 if (words.size() < 3) {
412 return emitError(unknownLoc,
"OpMemberName must have at least 3 operands");
414 unsigned wordIndex = 2;
416 if (wordIndex != words.size()) {
418 "unexpected trailing words in OpMemberName instruction");
420 memberNameMap[words[0]][words[1]] = name;
424 LogicalResult spirv::Deserializer::setFunctionArgAttrs(
426 if (!decorations.contains(argID)) {
431 spirv::DecorationAttr foundDecorationAttr;
433 for (
auto decoration :
434 {spirv::Decoration::Aliased, spirv::Decoration::Restrict,
435 spirv::Decoration::AliasedPointer,
436 spirv::Decoration::RestrictPointer}) {
438 if (decAttr.getName() !=
439 getSymbolDecoration(stringifyDecoration(decoration)))
442 if (foundDecorationAttr)
444 "more than one Aliased/Restrict decorations for "
445 "function argument with result <id> ")
452 if (decAttr.getName() == getSymbolDecoration(stringifyDecoration(
453 spirv::Decoration::RelaxedPrecision))) {
458 if (foundDecorationAttr)
459 return emitError(unknownLoc,
"already found a decoration for function "
460 "argument with result <id> ")
464 context, spirv::Decoration::RelaxedPrecision);
468 if (!foundDecorationAttr)
469 return emitError(unknownLoc,
"unimplemented decoration support for "
470 "function argument with result <id> ")
474 foundDecorationAttr);
482 return emitError(unknownLoc,
"found function inside function");
486 if (operands.size() != 4) {
487 return emitError(unknownLoc,
"OpFunction must have 4 parameters");
491 return emitError(unknownLoc,
"undefined result type from <id> ")
495 uint32_t fnID = operands[1];
496 if (funcMap.count(fnID)) {
497 return emitError(unknownLoc,
"duplicate function definition/declaration");
500 auto fnControl = spirv::symbolizeFunctionControl(operands[2]);
502 return emitError(unknownLoc,
"unknown Function Control: ") << operands[2];
506 if (!fnType || !isa<FunctionType>(fnType)) {
507 return emitError(unknownLoc,
"unknown function type from <id> ")
510 auto functionType = cast<FunctionType>(fnType);
512 if ((isVoidType(resultType) && functionType.getNumResults() != 0) ||
513 (functionType.getNumResults() == 1 &&
514 functionType.getResult(0) != resultType)) {
515 return emitError(unknownLoc,
"mismatch in function type ")
516 << functionType <<
" and return type " << resultType <<
" specified";
519 std::string fnName = getFunctionSymbol(fnID);
520 auto funcOp = spirv::FuncOp::create(opBuilder, unknownLoc, fnName,
521 functionType, fnControl.value());
523 if (decorations.count(fnID)) {
524 for (
auto attr : decorations[fnID].getAttrs()) {
525 funcOp->setAttr(attr.getName(), attr.getValue());
528 curFunction = funcMap[fnID] = funcOp;
529 auto *entryBlock = funcOp.addEntryBlock();
532 <<
"//===-------------------------------------------===//\n";
533 logger.startLine() <<
"[fn] name: " << fnName <<
"\n";
534 logger.startLine() <<
"[fn] type: " << fnType <<
"\n";
535 logger.startLine() <<
"[fn] ID: " << fnID <<
"\n";
536 logger.startLine() <<
"[fn] entry block: " << entryBlock <<
"\n";
541 argAttrs.resize(functionType.getNumInputs());
544 if (functionType.getNumInputs()) {
545 for (
size_t i = 0, e = functionType.getNumInputs(); i != e; ++i) {
546 auto argType = functionType.getInput(i);
547 spirv::Opcode opcode = spirv::Opcode::OpNop;
549 if (
failed(sliceInstruction(opcode, operands,
550 spirv::Opcode::OpFunctionParameter))) {
553 if (opcode != spirv::Opcode::OpFunctionParameter) {
556 "missing OpFunctionParameter instruction for argument ")
559 if (operands.size() != 2) {
562 "expected result type and result <id> for OpFunctionParameter");
564 auto argDefinedType =
getType(operands[0]);
565 if (!argDefinedType || argDefinedType != argType) {
567 "mismatch in argument type between function type "
569 << functionType <<
" and argument type definition "
570 << argDefinedType <<
" at argument " << i;
572 if (getValue(operands[1])) {
573 return emitError(unknownLoc,
"duplicate definition of result <id> ")
576 if (
failed(setFunctionArgAttrs(operands[1], argAttrs, i))) {
580 auto argValue = funcOp.getArgument(i);
581 valueMap[operands[1]] = argValue;
585 if (llvm::any_of(argAttrs, [](
Attribute attr) {
586 auto argAttr = cast<DictionaryAttr>(attr);
587 return !argAttr.empty();
594 auto linkageAttr = funcOp.getLinkageAttributes();
595 auto hasImportLinkage =
596 linkageAttr && (linkageAttr.value().getLinkageType().getValue() ==
597 spirv::LinkageType::Import);
598 if (hasImportLinkage)
605 spirv::Opcode opcode = spirv::Opcode::OpNop;
613 if (
failed(sliceInstruction(opcode, instOperands,
614 spirv::Opcode::OpFunctionEnd))) {
617 if (opcode == spirv::Opcode::OpFunctionEnd) {
618 return processFunctionEnd(instOperands);
620 if (opcode != spirv::Opcode::OpLabel) {
621 return emitError(unknownLoc,
"a basic block must start with OpLabel");
623 if (instOperands.size() != 1) {
624 return emitError(unknownLoc,
"OpLabel should only have result <id>");
626 blockMap[instOperands[0]] = entryBlock;
627 if (
failed(processLabel(instOperands))) {
633 while (succeeded(sliceInstruction(opcode, instOperands,
634 spirv::Opcode::OpFunctionEnd)) &&
635 opcode != spirv::Opcode::OpFunctionEnd) {
636 if (
failed(processInstruction(opcode, instOperands))) {
640 if (opcode != spirv::Opcode::OpFunctionEnd) {
644 return processFunctionEnd(instOperands);
650 if (!operands.empty()) {
651 return emitError(unknownLoc,
"unexpected operands for OpFunctionEnd");
657 if (
failed(wireUpBlockArgument()) ||
failed(structurizeControlFlow())) {
662 curFunction = std::nullopt;
667 <<
"//===-------------------------------------------===//\n";
674 if (operands.size() < 2) {
676 "missing graph defintion in OpGraphEntryPointARM");
679 unsigned wordIndex = 0;
680 uint32_t graphID = operands[wordIndex++];
681 if (!graphMap.contains(graphID)) {
683 "missing graph definition/declaration with id ")
687 spirv::GraphARMOp graphARM = graphMap[graphID];
689 graphARM.setSymName(name);
690 graphARM.setEntryPoint(
true);
693 for (int64_t size = operands.size(); wordIndex < size; ++wordIndex) {
694 if (spirv::GlobalVariableOp arg = getGlobalVariable(operands[wordIndex])) {
697 return emitError(unknownLoc,
"undefined result <id> ")
698 << operands[wordIndex] <<
" while decoding OpGraphEntryPoint";
704 opBuilder.setInsertionPoint(graphARM);
705 opBuilder.create<spirv::GraphEntryPointARMOp>(
707 opBuilder.getArrayAttr(interface));
715 return emitError(unknownLoc,
"found graph inside graph");
718 if (operands.size() < 2) {
719 return emitError(unknownLoc,
"OpGraphARM must have at least 2 parameters");
723 if (!type || !isa<GraphType>(type)) {
724 return emitError(unknownLoc,
"unknown graph type from <id> ")
727 auto graphType = cast<GraphType>(type);
728 if (graphType.getNumResults() <= 0) {
729 return emitError(unknownLoc,
"expected at least one result");
732 uint32_t graphID = operands[1];
733 if (graphMap.count(graphID)) {
734 return emitError(unknownLoc,
"duplicate graph definition/declaration");
737 std::string graphName = getGraphSymbol(graphID);
739 opBuilder.create<spirv::GraphARMOp>(unknownLoc, graphName, graphType);
740 curGraph = graphMap[graphID] = graphOp;
741 Block *entryBlock = graphOp.addEntryBlock();
744 <<
"//===-------------------------------------------===//\n";
745 logger.startLine() <<
"[graph] name: " << graphName <<
"\n";
746 logger.startLine() <<
"[graph] type: " << graphType <<
"\n";
747 logger.startLine() <<
"[graph] ID: " << graphID <<
"\n";
748 logger.startLine() <<
"[graph] entry block: " << entryBlock <<
"\n";
754 spirv::Opcode opcode;
756 if (
failed(sliceInstruction(opcode, operands,
757 spirv::Opcode::OpGraphInputARM))) {
760 if (operands.size() != 3) {
761 return emitError(unknownLoc,
"expected result type, result <id> and "
762 "input index for OpGraphInputARM");
766 if (!argDefinedType) {
767 return emitError(unknownLoc,
"unknown operand type <id> ") << operands[0];
770 if (argDefinedType != argType) {
772 "mismatch in argument type between graph type "
774 << graphType <<
" and argument type definition " << argDefinedType
775 <<
" at argument " << index;
777 if (getValue(operands[1])) {
778 return emitError(unknownLoc,
"duplicate definition of result <id> ")
782 IntegerAttr inputIndexAttr = getConstantInt(operands[2]);
783 if (!inputIndexAttr) {
785 "unable to read inputIndex value from constant op ")
788 BlockArgument argValue = graphOp.getArgument(inputIndexAttr.getInt());
789 valueMap[operands[1]] = argValue;
792 graphOutputs.resize(graphType.getNumResults());
798 blockMap[graphID] = entryBlock;
799 if (
failed(createGraphBlock(graphID))) {
805 spirv::Opcode opcode;
808 if (
failed(sliceInstruction(opcode, instOperands, std::nullopt))) {
812 if (
failed(processInstruction(opcode, instOperands))) {
815 }
while (opcode != spirv::Opcode::OpGraphEndARM);
822 if (operands.size() != 2) {
825 "expected value id and output index for OpGraphSetOutputARM");
828 uint32_t
id = operands[0];
829 Value value = getValue(
id);
831 return emitError(unknownLoc,
"could not find result <id> ") << id;
834 IntegerAttr outputIndexAttr = getConstantInt(operands[1]);
835 if (!outputIndexAttr) {
837 "unable to read outputIndex value from constant op ")
840 graphOutputs[outputIndexAttr.getInt()] = value;
847 opBuilder.create<spirv::GraphOutputsARMOp>(unknownLoc, graphOutputs);
850 if (!operands.empty()) {
851 return emitError(unknownLoc,
"unexpected operands for OpGraphEndARM");
855 curGraph = std::nullopt;
856 graphOutputs.clear();
861 <<
"//===-------------------------------------------===//\n";
866 std::optional<std::pair<Attribute, Type>>
867 spirv::Deserializer::getConstant(uint32_t
id) {
868 auto constIt = constantMap.find(
id);
869 if (constIt == constantMap.end())
871 return constIt->getSecond();
874 std::optional<std::pair<Attribute, Type>>
875 spirv::Deserializer::getConstantCompositeReplicate(uint32_t
id) {
876 if (
auto it = constantCompositeReplicateMap.find(
id);
877 it != constantCompositeReplicateMap.end())
882 std::optional<spirv::SpecConstOperationMaterializationInfo>
883 spirv::Deserializer::getSpecConstantOperation(uint32_t
id) {
884 auto constIt = specConstOperationMap.find(
id);
885 if (constIt == specConstOperationMap.end())
887 return constIt->getSecond();
890 std::string spirv::Deserializer::getFunctionSymbol(uint32_t
id) {
891 auto funcName = nameMap.lookup(
id).str();
892 if (funcName.empty()) {
893 funcName =
"spirv_fn_" + std::to_string(
id);
898 std::string spirv::Deserializer::getGraphSymbol(uint32_t
id) {
899 std::string graphName = nameMap.lookup(
id).str();
900 if (graphName.empty()) {
901 graphName =
"spirv_graph_" + std::to_string(
id);
906 std::string spirv::Deserializer::getSpecConstantSymbol(uint32_t
id) {
907 auto constName = nameMap.lookup(
id).str();
908 if (constName.empty()) {
909 constName =
"spirv_spec_const_" + std::to_string(
id);
914 spirv::SpecConstantOp
915 spirv::Deserializer::createSpecConstant(
Location loc, uint32_t resultID,
916 TypedAttr defaultValue) {
917 auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
918 auto op = spirv::SpecConstantOp::create(opBuilder, unknownLoc, symName,
920 if (decorations.count(resultID)) {
921 for (
auto attr : decorations[resultID].getAttrs())
922 op->setAttr(attr.getName(), attr.getValue());
924 specConstMap[resultID] = op;
928 std::optional<spirv::GraphConstantARMOpMaterializationInfo>
929 spirv::Deserializer::getGraphConstantARM(uint32_t
id) {
930 auto graphConstIt = graphConstantMap.find(
id);
931 if (graphConstIt == graphConstantMap.end())
933 return graphConstIt->getSecond();
938 unsigned wordIndex = 0;
939 if (operands.size() < 3) {
942 "OpVariable needs at least 3 operands, type, <id> and storage class");
946 auto type =
getType(operands[wordIndex]);
948 return emitError(unknownLoc,
"unknown result type <id> : ")
949 << operands[wordIndex];
951 auto ptrType = dyn_cast<spirv::PointerType>(type);
954 "expected a result type <id> to be a spirv.ptr, found : ")
960 auto variableID = operands[wordIndex];
961 auto variableName = nameMap.lookup(variableID).str();
962 if (variableName.empty()) {
963 variableName =
"spirv_var_" + std::to_string(variableID);
968 auto storageClass =
static_cast<spirv::StorageClass
>(operands[wordIndex]);
969 if (ptrType.getStorageClass() != storageClass) {
970 return emitError(unknownLoc,
"mismatch in storage class of pointer type ")
971 << type <<
" and that specified in OpVariable instruction : "
972 << stringifyStorageClass(storageClass);
979 if (wordIndex < operands.size()) {
982 if (
auto initOp = getGlobalVariable(operands[wordIndex]))
984 else if (
auto initOp = getSpecConstant(operands[wordIndex]))
986 else if (
auto initOp = getSpecConstantComposite(operands[wordIndex]))
989 return emitError(unknownLoc,
"unknown <id> ")
990 << operands[wordIndex] <<
"used as initializer";
995 if (wordIndex != operands.size()) {
997 "found more operands than expected when deserializing "
998 "OpVariable instruction, only ")
999 << wordIndex <<
" of " << operands.size() <<
" processed";
1001 auto loc = createFileLineColLoc(opBuilder);
1002 auto varOp = spirv::GlobalVariableOp::create(
1004 opBuilder.getStringAttr(variableName), initializer);
1007 if (decorations.count(variableID)) {
1008 for (
auto attr : decorations[variableID].getAttrs())
1009 varOp->setAttr(attr.getName(), attr.getValue());
1011 globalVariableMap[variableID] = varOp;
1015 IntegerAttr spirv::Deserializer::getConstantInt(uint32_t
id) {
1016 auto constInfo = getConstant(
id);
1020 return dyn_cast<IntegerAttr>(constInfo->first);
1024 if (operands.size() < 2) {
1025 return emitError(unknownLoc,
"OpName needs at least 2 operands");
1027 if (!nameMap.lookup(operands[0]).empty()) {
1028 return emitError(unknownLoc,
"duplicate name found for result <id> ")
1031 unsigned wordIndex = 1;
1033 if (wordIndex != operands.size()) {
1035 "unexpected trailing words in OpName instruction");
1037 nameMap[operands[0]] = name;
1045 LogicalResult spirv::Deserializer::processType(spirv::Opcode opcode,
1047 if (operands.empty()) {
1048 return emitError(unknownLoc,
"type instruction with opcode ")
1049 << spirv::stringifyOpcode(opcode) <<
" needs at least one <id>";
1054 if (typeMap.count(operands[0])) {
1055 return emitError(unknownLoc,
"duplicate definition for result <id> ")
1060 case spirv::Opcode::OpTypeVoid:
1061 if (operands.size() != 1)
1062 return emitError(unknownLoc,
"OpTypeVoid must have no parameters");
1063 typeMap[operands[0]] = opBuilder.getNoneType();
1065 case spirv::Opcode::OpTypeBool:
1066 if (operands.size() != 1)
1067 return emitError(unknownLoc,
"OpTypeBool must have no parameters");
1068 typeMap[operands[0]] = opBuilder.getI1Type();
1070 case spirv::Opcode::OpTypeInt: {
1071 if (operands.size() != 3)
1073 unknownLoc,
"OpTypeInt must have bitwidth and signedness parameters");
1083 : IntegerType::SignednessSemantics::Signless;
1086 case spirv::Opcode::OpTypeFloat: {
1087 if (operands.size() != 2 && operands.size() != 3)
1089 "OpTypeFloat expects either 2 operands (type, bitwidth) "
1090 "or 3 operands (type, bitwidth, encoding), but got ")
1092 uint32_t bitWidth = operands[1];
1097 floatTy = opBuilder.getF16Type();
1100 floatTy = opBuilder.getF32Type();
1103 floatTy = opBuilder.getF64Type();
1106 return emitError(unknownLoc,
"unsupported OpTypeFloat bitwidth: ")
1110 if (operands.size() == 3) {
1111 if (spirv::FPEncoding(operands[2]) != spirv::FPEncoding::BFloat16KHR)
1112 return emitError(unknownLoc,
"unsupported OpTypeFloat FP encoding: ")
1116 "invalid OpTypeFloat bitwidth for bfloat16 encoding: ")
1117 << bitWidth <<
" (expected 16)";
1118 floatTy = opBuilder.getBF16Type();
1121 typeMap[operands[0]] = floatTy;
1123 case spirv::Opcode::OpTypeVector: {
1124 if (operands.size() != 3) {
1127 "OpTypeVector must have element type and count parameters");
1131 return emitError(unknownLoc,
"OpTypeVector references undefined <id> ")
1136 case spirv::Opcode::OpTypePointer: {
1137 return processOpTypePointer(operands);
1139 case spirv::Opcode::OpTypeArray:
1140 return processArrayType(operands);
1141 case spirv::Opcode::OpTypeCooperativeMatrixKHR:
1142 return processCooperativeMatrixTypeKHR(operands);
1143 case spirv::Opcode::OpTypeFunction:
1144 return processFunctionType(operands);
1145 case spirv::Opcode::OpTypeImage:
1146 return processImageType(operands);
1147 case spirv::Opcode::OpTypeSampledImage:
1148 return processSampledImageType(operands);
1149 case spirv::Opcode::OpTypeRuntimeArray:
1150 return processRuntimeArrayType(operands);
1151 case spirv::Opcode::OpTypeStruct:
1152 return processStructType(operands);
1153 case spirv::Opcode::OpTypeMatrix:
1154 return processMatrixType(operands);
1155 case spirv::Opcode::OpTypeTensorARM:
1156 return processTensorARMType(operands);
1157 case spirv::Opcode::OpTypeGraphARM:
1158 return processGraphTypeARM(operands);
1160 return emitError(unknownLoc,
"unhandled type instruction");
1167 if (operands.size() != 3)
1168 return emitError(unknownLoc,
"OpTypePointer must have two parameters");
1170 auto pointeeType =
getType(operands[2]);
1172 return emitError(unknownLoc,
"unknown OpTypePointer pointee type <id> ")
1175 uint32_t typePointerID = operands[0];
1176 auto storageClass =
static_cast<spirv::StorageClass
>(operands[1]);
1179 for (
auto *deferredStructIt = std::begin(deferredStructTypesInfos);
1180 deferredStructIt != std::end(deferredStructTypesInfos);) {
1181 for (
auto *unresolvedMemberIt =
1182 std::begin(deferredStructIt->unresolvedMemberTypes);
1183 unresolvedMemberIt !=
1184 std::end(deferredStructIt->unresolvedMemberTypes);) {
1185 if (unresolvedMemberIt->first == typePointerID) {
1189 deferredStructIt->memberTypes[unresolvedMemberIt->second] =
1190 typeMap[typePointerID];
1191 unresolvedMemberIt =
1192 deferredStructIt->unresolvedMemberTypes.erase(unresolvedMemberIt);
1194 ++unresolvedMemberIt;
1198 if (deferredStructIt->unresolvedMemberTypes.empty()) {
1200 auto structType = deferredStructIt->deferredStructType;
1202 assert(structType &&
"expected a spirv::StructType");
1203 assert(structType.isIdentified() &&
"expected an indentified struct");
1205 if (
failed(structType.trySetBody(
1206 deferredStructIt->memberTypes, deferredStructIt->offsetInfo,
1207 deferredStructIt->memberDecorationsInfo,
1208 deferredStructIt->structDecorationsInfo)))
1211 deferredStructIt = deferredStructTypesInfos.erase(deferredStructIt);
1222 if (operands.size() != 3) {
1224 "OpTypeArray must have element type and count parameters");
1229 return emitError(unknownLoc,
"OpTypeArray references undefined <id> ")
1235 auto countInfo = getConstant(operands[2]);
1237 return emitError(unknownLoc,
"OpTypeArray count <id> ")
1238 << operands[2] <<
"can only come from normal constant right now";
1241 if (
auto intVal = dyn_cast<IntegerAttr>(countInfo->first)) {
1242 count = intVal.getValue().getZExtValue();
1244 return emitError(unknownLoc,
"OpTypeArray count must come from a "
1245 "scalar integer constant instruction");
1249 elementTy, count, typeDecorations.lookup(operands[0]));
1255 assert(!operands.empty() &&
"No operands for processing function type");
1256 if (operands.size() == 1) {
1257 return emitError(unknownLoc,
"missing return type for OpTypeFunction");
1259 auto returnType =
getType(operands[1]);
1261 return emitError(unknownLoc,
"unknown return type in OpTypeFunction");
1264 for (
size_t i = 2, e = operands.size(); i < e; ++i) {
1265 auto ty =
getType(operands[i]);
1267 return emitError(unknownLoc,
"unknown argument type in OpTypeFunction");
1269 argTypes.push_back(ty);
1272 if (!isVoidType(returnType)) {
1279 LogicalResult spirv::Deserializer::processCooperativeMatrixTypeKHR(
1281 if (operands.size() != 6) {
1283 "OpTypeCooperativeMatrixKHR must have element type, "
1284 "scope, row and column parameters, and use");
1290 "OpTypeCooperativeMatrixKHR references undefined <id> ")
1294 std::optional<spirv::Scope> scope =
1295 spirv::symbolizeScope(getConstantInt(operands[2]).getInt());
1299 "OpTypeCooperativeMatrixKHR references undefined scope <id> ")
1303 IntegerAttr rowsAttr = getConstantInt(operands[3]);
1304 IntegerAttr columnsAttr = getConstantInt(operands[4]);
1305 IntegerAttr useAttr = getConstantInt(operands[5]);
1308 return emitError(unknownLoc,
"OpTypeCooperativeMatrixKHR `Rows` references "
1309 "undefined constant <id> ")
1313 return emitError(unknownLoc,
"OpTypeCooperativeMatrixKHR `Columns` "
1314 "references undefined constant <id> ")
1318 return emitError(unknownLoc,
"OpTypeCooperativeMatrixKHR `Use` references "
1319 "undefined constant <id> ")
1322 unsigned rows = rowsAttr.getInt();
1323 unsigned columns = columnsAttr.getInt();
1325 std::optional<spirv::CooperativeMatrixUseKHR> use =
1326 spirv::symbolizeCooperativeMatrixUseKHR(useAttr.getInt());
1330 "OpTypeCooperativeMatrixKHR references undefined use <id> ")
1334 typeMap[operands[0]] =
1341 if (operands.size() != 2) {
1342 return emitError(unknownLoc,
"OpTypeRuntimeArray must have two operands");
1347 "OpTypeRuntimeArray references undefined <id> ")
1351 memberType, typeDecorations.lookup(operands[0]));
1359 if (operands.empty()) {
1360 return emitError(unknownLoc,
"OpTypeStruct must have at least result <id>");
1363 if (operands.size() == 1) {
1365 typeMap[operands[0]] =
1374 for (
auto op : llvm::drop_begin(operands, 1)) {
1376 bool typeForwardPtr = (typeForwardPointerIDs.count(op) != 0);
1378 if (!memberType && !typeForwardPtr)
1379 return emitError(unknownLoc,
"OpTypeStruct references undefined <id> ")
1383 unresolvedMemberTypes.emplace_back(op, memberTypes.size());
1385 memberTypes.push_back(memberType);
1390 if (memberDecorationMap.count(operands[0])) {
1391 auto &allMemberDecorations = memberDecorationMap[operands[0]];
1392 for (
auto memberIndex : llvm::seq<uint32_t>(0, memberTypes.size())) {
1393 if (allMemberDecorations.count(memberIndex)) {
1394 for (
auto &memberDecoration : allMemberDecorations[memberIndex]) {
1396 if (memberDecoration.first == spirv::Decoration::Offset) {
1398 if (offsetInfo.empty()) {
1399 offsetInfo.resize(memberTypes.size());
1401 offsetInfo[memberIndex] = memberDecoration.second[0];
1404 if (!memberDecoration.second.empty()) {
1405 memberDecorationsInfo.emplace_back(
1406 memberIndex, memberDecoration.first,
1409 memberDecorationsInfo.emplace_back(
1410 memberIndex, memberDecoration.first,
UnitAttr::get(context));
1419 if (decorations.count(operands[0])) {
1422 std::optional<spirv::Decoration> decoration = spirv::symbolizeDecoration(
1423 llvm::convertToCamelFromSnakeCase(decorationAttr.getName(),
true));
1424 assert(decoration.has_value());
1425 structDecorationsInfo.emplace_back(decoration.value(),
1426 decorationAttr.getValue());
1430 uint32_t structID = operands[0];
1431 std::string structIdentifier = nameMap.lookup(structID).str();
1433 if (structIdentifier.empty()) {
1434 assert(unresolvedMemberTypes.empty() &&
1435 "didn't expect unresolved member types");
1437 memberTypes, offsetInfo, memberDecorationsInfo, structDecorationsInfo);
1440 typeMap[structID] = structTy;
1442 if (!unresolvedMemberTypes.empty())
1443 deferredStructTypesInfos.push_back(
1444 {structTy, unresolvedMemberTypes, memberTypes, offsetInfo,
1445 memberDecorationsInfo, structDecorationsInfo});
1446 else if (
failed(structTy.trySetBody(memberTypes, offsetInfo,
1447 memberDecorationsInfo,
1448 structDecorationsInfo)))
1459 if (operands.size() != 3) {
1461 return emitError(unknownLoc,
"OpTypeMatrix must have 3 operands"
1462 " (result_id, column_type, and column_count)");
1468 "OpTypeMatrix references undefined column type.")
1472 uint32_t colsCount = operands[2];
1479 unsigned size = operands.size();
1480 if (size < 2 || size > 4)
1481 return emitError(unknownLoc,
"OpTypeTensorARM must have 2-4 operands "
1482 "(result_id, element_type, (rank), (shape)) ")
1488 "OpTypeTensorARM references undefined element type ")
1496 IntegerAttr rankAttr = getConstantInt(operands[2]);
1498 return emitError(unknownLoc,
"OpTypeTensorARM rank must come from a "
1499 "scalar integer constant instruction");
1500 unsigned rank = rankAttr.getValue().getZExtValue();
1507 std::optional<std::pair<Attribute, Type>> shapeInfo =
1508 getConstant(operands[3]);
1510 return emitError(unknownLoc,
"OpTypeTensorARM shape must come from a "
1511 "constant instruction of type OpTypeArray");
1513 ArrayAttr shapeArrayAttr = llvm::dyn_cast<ArrayAttr>(shapeInfo->first);
1515 for (
auto dimAttr : shapeArrayAttr.getValue()) {
1516 auto dimIntAttr = llvm::dyn_cast<IntegerAttr>(dimAttr);
1518 return emitError(unknownLoc,
"OpTypeTensorARM shape has an invalid "
1520 shape.push_back(dimIntAttr.getValue().getSExtValue());
1528 unsigned size = operands.size();
1530 return emitError(unknownLoc,
"OpTypeGraphARM must have at least 2 operands "
1531 "(result_id, num_inputs, (inout0_type, "
1532 "inout1_type, ...))")
1535 uint32_t numInputs = operands[1];
1538 for (
unsigned i = 2; i < size; ++i) {
1542 "OpTypeGraphARM references undefined element type.")
1545 if (i - 2 >= numInputs) {
1546 returnTypes.push_back(inOutTy);
1548 argTypes.push_back(inOutTy);
1551 typeMap[operands[0]] =
GraphType::get(context, argTypes, returnTypes);
1557 if (operands.size() != 2)
1559 "OpTypeForwardPointer instruction must have two operands");
1561 typeForwardPointerIDs.insert(operands[0]);
1571 if (operands.size() != 8)
1574 "OpTypeImage with non-eight operands are not supported yet");
1578 return emitError(unknownLoc,
"OpTypeImage references undefined <id>: ")
1581 auto dim = spirv::symbolizeDim(operands[2]);
1583 return emitError(unknownLoc,
"unknown Dim for OpTypeImage: ")
1586 auto depthInfo = spirv::symbolizeImageDepthInfo(operands[3]);
1588 return emitError(unknownLoc,
"unknown Depth for OpTypeImage: ")
1591 auto arrayedInfo = spirv::symbolizeImageArrayedInfo(operands[4]);
1593 return emitError(unknownLoc,
"unknown Arrayed for OpTypeImage: ")
1596 auto samplingInfo = spirv::symbolizeImageSamplingInfo(operands[5]);
1598 return emitError(unknownLoc,
"unknown MS for OpTypeImage: ") << operands[5];
1600 auto samplerUseInfo = spirv::symbolizeImageSamplerUseInfo(operands[6]);
1601 if (!samplerUseInfo)
1602 return emitError(unknownLoc,
"unknown Sampled for OpTypeImage: ")
1605 auto format = spirv::symbolizeImageFormat(operands[7]);
1607 return emitError(unknownLoc,
"unknown Format for OpTypeImage: ")
1611 elementTy, dim.value(), depthInfo.value(), arrayedInfo.value(),
1612 samplingInfo.value(), samplerUseInfo.value(), format.value());
1618 if (operands.size() != 2)
1619 return emitError(unknownLoc,
"OpTypeSampledImage must have two operands");
1624 "OpTypeSampledImage references undefined <id>: ")
1637 StringRef opname = isSpec ?
"OpSpecConstant" :
"OpConstant";
1639 if (operands.size() < 2) {
1641 << opname <<
" must have type <id> and result <id>";
1643 if (operands.size() < 3) {
1645 << opname <<
" must have at least 1 more parameter";
1650 return emitError(unknownLoc,
"undefined result type from <id> ")
1654 auto checkOperandSizeForBitwidth = [&](
unsigned bitwidth) -> LogicalResult {
1655 if (bitwidth == 64) {
1656 if (operands.size() == 4) {
1660 << opname <<
" should have 2 parameters for 64-bit values";
1662 if (bitwidth <= 32) {
1663 if (operands.size() == 3) {
1669 <<
" should have 1 parameter for values with no more than 32 bits";
1671 return emitError(unknownLoc,
"unsupported OpConstant bitwidth: ")
1675 auto resultID = operands[1];
1677 if (
auto intType = dyn_cast<IntegerType>(resultType)) {
1678 auto bitwidth = intType.getWidth();
1679 if (
failed(checkOperandSizeForBitwidth(bitwidth))) {
1684 if (bitwidth == 64) {
1691 } words = {operands[2], operands[3]};
1692 value = APInt(64, llvm::bit_cast<uint64_t>(words),
true);
1693 }
else if (bitwidth <= 32) {
1694 value = APInt(bitwidth, operands[2],
true,
1698 auto attr = opBuilder.getIntegerAttr(intType, value);
1701 createSpecConstant(unknownLoc, resultID, attr);
1705 constantMap.try_emplace(resultID, attr, intType);
1711 if (
auto floatType = dyn_cast<FloatType>(resultType)) {
1712 auto bitwidth = floatType.getWidth();
1713 if (
failed(checkOperandSizeForBitwidth(bitwidth))) {
1718 if (floatType.isF64()) {
1725 } words = {operands[2], operands[3]};
1726 value = APFloat(llvm::bit_cast<double>(words));
1727 }
else if (floatType.isF32()) {
1728 value = APFloat(llvm::bit_cast<float>(operands[2]));
1729 }
else if (floatType.isF16()) {
1730 APInt data(16, operands[2]);
1731 value = APFloat(APFloat::IEEEhalf(), data);
1732 }
else if (floatType.isBF16()) {
1733 APInt data(16, operands[2]);
1734 value = APFloat(APFloat::BFloat(), data);
1737 auto attr = opBuilder.getFloatAttr(floatType, value);
1739 createSpecConstant(unknownLoc, resultID, attr);
1743 constantMap.try_emplace(resultID, attr, floatType);
1749 return emitError(unknownLoc,
"OpConstant can only generate values of "
1750 "scalar integer or floating-point type");
1753 LogicalResult spirv::Deserializer::processConstantBool(
1755 if (operands.size() != 2) {
1757 << (isSpec ?
"Spec" :
"") <<
"Constant"
1758 << (isTrue ?
"True" :
"False")
1759 <<
" must have type <id> and result <id>";
1762 auto attr = opBuilder.getBoolAttr(isTrue);
1763 auto resultID = operands[1];
1765 createSpecConstant(unknownLoc, resultID, attr);
1769 constantMap.try_emplace(resultID, attr, opBuilder.getI1Type());
1777 if (operands.size() < 2) {
1779 "OpConstantComposite must have type <id> and result <id>");
1781 if (operands.size() < 3) {
1783 "OpConstantComposite must have at least 1 parameter");
1788 return emitError(unknownLoc,
"undefined result type from <id> ")
1793 elements.reserve(operands.size() - 2);
1794 for (
unsigned i = 2, e = operands.size(); i < e; ++i) {
1795 auto elementInfo = getConstant(operands[i]);
1797 return emitError(unknownLoc,
"OpConstantComposite component <id> ")
1798 << operands[i] <<
" must come from a normal constant";
1800 elements.push_back(elementInfo->first);
1803 auto resultID = operands[1];
1804 if (
auto tensorType = dyn_cast<TensorArmType>(resultType)) {
1807 if (
auto denseElemAttr = dyn_cast<DenseElementsAttr>(element)) {
1808 for (
auto value : denseElemAttr.getValues<
Attribute>())
1809 flattenedElems.push_back(value);
1811 flattenedElems.push_back(element);
1815 constantMap.try_emplace(resultID, attr, tensorType);
1816 }
else if (
auto shapedType = dyn_cast<ShapedType>(resultType)) {
1820 constantMap.try_emplace(resultID, attr, shapedType);
1821 }
else if (
auto arrayType = dyn_cast<spirv::ArrayType>(resultType)) {
1822 auto attr = opBuilder.getArrayAttr(elements);
1823 constantMap.try_emplace(resultID, attr, resultType);
1825 return emitError(unknownLoc,
"unsupported OpConstantComposite type: ")
1832 LogicalResult spirv::Deserializer::processConstantCompositeReplicateEXT(
1834 if (operands.size() != 3) {
1837 "OpConstantCompositeReplicateEXT expects 3 operands but found ")
1843 return emitError(unknownLoc,
"undefined result type from <id> ")
1847 auto compositeType = dyn_cast<CompositeType>(resultType);
1848 if (!compositeType) {
1850 "result type from <id> is not a composite type")
1854 uint32_t resultID = operands[1];
1855 uint32_t constantID = operands[2];
1857 std::optional<std::pair<Attribute, Type>> constantInfo =
1858 getConstant(constantID);
1859 if (constantInfo.has_value()) {
1860 constantCompositeReplicateMap.try_emplace(
1861 resultID, constantInfo.value().first, resultType);
1865 std::optional<std::pair<Attribute, Type>> replicatedConstantCompositeInfo =
1866 getConstantCompositeReplicate(constantID);
1867 if (replicatedConstantCompositeInfo.has_value()) {
1868 constantCompositeReplicateMap.try_emplace(
1869 resultID, replicatedConstantCompositeInfo.value().first, resultType);
1873 return emitError(unknownLoc,
"OpConstantCompositeReplicateEXT operand <id> ")
1875 <<
" must come from a normal constant or a "
1876 "OpConstantCompositeReplicateEXT";
1881 if (operands.size() < 2) {
1884 "OpSpecConstantComposite must have type <id> and result <id>");
1886 if (operands.size() < 3) {
1888 "OpSpecConstantComposite must have at least 1 parameter");
1893 return emitError(unknownLoc,
"undefined result type from <id> ")
1897 auto resultID = operands[1];
1898 auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
1901 elements.reserve(operands.size() - 2);
1902 for (
unsigned i = 2, e = operands.size(); i < e; ++i) {
1903 auto elementInfo = getSpecConstant(operands[i]);
1907 auto op = spirv::SpecConstantCompositeOp::create(
1909 opBuilder.getArrayAttr(elements));
1910 specConstCompositeMap[resultID] = op;
1915 LogicalResult spirv::Deserializer::processSpecConstantCompositeReplicateEXT(
1917 if (operands.size() != 3) {
1918 return emitError(unknownLoc,
"OpSpecConstantCompositeReplicateEXT expects "
1919 "3 operands but found ")
1925 return emitError(unknownLoc,
"undefined result type from <id> ")
1929 auto compositeType = dyn_cast<CompositeType>(resultType);
1930 if (!compositeType) {
1932 "result type from <id> is not a composite type")
1936 uint32_t resultID = operands[1];
1938 auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
1939 spirv::SpecConstantOp constituentSpecConstantOp =
1940 getSpecConstant(operands[2]);
1941 auto op = spirv::EXTSpecConstantCompositeReplicateOp::create(
1945 specConstCompositeReplicateMap[resultID] = op;
1952 if (operands.size() < 3)
1953 return emitError(unknownLoc,
"OpConstantOperation must have type <id>, "
1954 "result <id>, and operand opcode");
1956 uint32_t resultTypeID = operands[0];
1959 return emitError(unknownLoc,
"undefined result type from <id> ")
1962 uint32_t resultID = operands[1];
1963 spirv::Opcode enclosedOpcode =
static_cast<spirv::Opcode
>(operands[2]);
1964 auto emplaceResult = specConstOperationMap.try_emplace(
1966 SpecConstOperationMaterializationInfo{
1967 enclosedOpcode, resultTypeID,
1970 if (!emplaceResult.second)
1971 return emitError(unknownLoc,
"value with <id>: ")
1972 << resultID <<
" is probably defined before.";
1977 Value spirv::Deserializer::materializeSpecConstantOperation(
1978 uint32_t resultID, spirv::Opcode enclosedOpcode, uint32_t resultTypeID,
1994 llvm::SaveAndRestore valueMapGuard(valueMap, newValueMap);
1995 constexpr uint32_t fakeID =
static_cast<uint32_t
>(-3);
1998 enclosedOpResultTypeAndOperands.push_back(resultTypeID);
1999 enclosedOpResultTypeAndOperands.push_back(fakeID);
2000 enclosedOpResultTypeAndOperands.append(enclosedOpOperands.begin(),
2001 enclosedOpOperands.end());
2008 processInstruction(enclosedOpcode, enclosedOpResultTypeAndOperands)))
2015 auto loc = createFileLineColLoc(opBuilder);
2016 auto specConstOperationOp =
2017 spirv::SpecConstantOperationOp::create(opBuilder, loc, resultType);
2019 Region &body = specConstOperationOp.getBody();
2021 body.
getBlocks().splice(body.
end(), curBlock->getParent()->getBlocks(),
2028 opBuilder.setInsertionPointToEnd(&block);
2030 spirv::YieldOp::create(opBuilder, loc, block.
front().
getResult(0));
2031 return specConstOperationOp.getResult();
2036 if (operands.size() != 2) {
2038 "OpConstantNull must only have type <id> and result <id>");
2043 return emitError(unknownLoc,
"undefined result type from <id> ")
2047 auto resultID = operands[1];
2049 if (resultType.
isIntOrFloat() || isa<VectorType>(resultType)) {
2050 attr = opBuilder.getZeroAttr(resultType);
2051 }
else if (
auto tensorType = dyn_cast<TensorArmType>(resultType)) {
2052 if (
auto element = opBuilder.getZeroAttr(tensorType.getElementType()))
2059 constantMap.try_emplace(resultID, attr, resultType);
2063 return emitError(unknownLoc,
"unsupported OpConstantNull type: ")
2069 if (operands.size() < 3) {
2071 <<
"OpGraphConstantARM must have at least 2 operands";
2076 return emitError(unknownLoc,
"undefined result type from <id> ")
2080 uint32_t resultID = operands[1];
2082 if (!dyn_cast<spirv::TensorArmType>(resultType)) {
2083 return emitError(unknownLoc,
"result must be of type OpTypeTensorARM");
2086 APInt graph_constant_id = APInt(32, operands[2],
true);
2087 Type i32Ty = opBuilder.getIntegerType(32);
2088 IntegerAttr attr = opBuilder.getIntegerAttr(i32Ty, graph_constant_id);
2089 graphConstantMap.try_emplace(
2090 resultID, GraphConstantARMOpMaterializationInfo{resultType, attr});
2099 Block *spirv::Deserializer::getOrCreateBlock(uint32_t
id) {
2100 if (
auto *block = getBlock(
id)) {
2101 LLVM_DEBUG(logger.startLine() <<
"[block] got exiting block for id = " <<
id
2102 <<
" @ " << block <<
"\n");
2109 auto *block = curFunction->addBlock();
2110 LLVM_DEBUG(logger.startLine() <<
"[block] created block for id = " <<
id
2111 <<
" @ " << block <<
"\n");
2112 return blockMap[id] = block;
2117 return emitError(unknownLoc,
"OpBranch must appear inside a block");
2120 if (operands.size() != 1) {
2121 return emitError(unknownLoc,
"OpBranch must take exactly one target label");
2124 auto *target = getOrCreateBlock(operands[0]);
2125 auto loc = createFileLineColLoc(opBuilder);
2129 spirv::BranchOp::create(opBuilder, loc, target);
2139 "OpBranchConditional must appear inside a block");
2142 if (operands.size() != 3 && operands.size() != 5) {
2144 "OpBranchConditional must have condition, true label, "
2145 "false label, and optionally two branch weights");
2148 auto condition = getValue(operands[0]);
2149 auto *trueBlock = getOrCreateBlock(operands[1]);
2150 auto *falseBlock = getOrCreateBlock(operands[2]);
2152 std::optional<std::pair<uint32_t, uint32_t>> weights;
2153 if (operands.size() == 5) {
2154 weights = std::make_pair(operands[3], operands[4]);
2159 auto loc = createFileLineColLoc(opBuilder);
2160 spirv::BranchConditionalOp::create(
2161 opBuilder, loc, condition, trueBlock,
2171 return emitError(unknownLoc,
"OpLabel must appear inside a function");
2174 if (operands.size() != 1) {
2175 return emitError(unknownLoc,
"OpLabel should only have result <id>");
2178 auto labelID = operands[0];
2180 auto *block = getOrCreateBlock(labelID);
2181 LLVM_DEBUG(logger.startLine()
2182 <<
"[block] populating block " << block <<
"\n");
2184 assert(block->
empty() &&
"re-deserialize the same block!");
2186 opBuilder.setInsertionPointToStart(block);
2187 blockMap[labelID] = curBlock = block;
2192 LogicalResult spirv::Deserializer::createGraphBlock(uint32_t graphID) {
2194 return emitError(unknownLoc,
"a graph block must appear inside a graph");
2198 Block *block = getOrCreateBlock(graphID);
2199 LLVM_DEBUG(logger.startLine()
2200 <<
"[block] populating block " << block <<
"\n");
2202 assert(block->
empty() &&
"re-deserialize the same block!");
2204 opBuilder.setInsertionPointToStart(block);
2205 blockMap[graphID] = curBlock = block;
2213 return emitError(unknownLoc,
"OpSelectionMerge must appear in a block");
2216 if (operands.size() < 2) {
2219 "OpSelectionMerge must specify merge target and selection control");
2222 auto *mergeBlock = getOrCreateBlock(operands[0]);
2223 auto loc = createFileLineColLoc(opBuilder);
2224 auto selectionControl = operands[1];
2226 if (!blockMergeInfo.try_emplace(curBlock, loc, selectionControl, mergeBlock)
2230 "a block cannot have more than one OpSelectionMerge instruction");
2239 return emitError(unknownLoc,
"OpLoopMerge must appear in a block");
2242 if (operands.size() < 3) {
2243 return emitError(unknownLoc,
"OpLoopMerge must specify merge target, "
2244 "continue target and loop control");
2247 auto *mergeBlock = getOrCreateBlock(operands[0]);
2248 auto *continueBlock = getOrCreateBlock(operands[1]);
2249 auto loc = createFileLineColLoc(opBuilder);
2250 uint32_t loopControl = operands[2];
2253 .try_emplace(curBlock, loc, loopControl, mergeBlock, continueBlock)
2257 "a block cannot have more than one OpLoopMerge instruction");
2265 return emitError(unknownLoc,
"OpPhi must appear in a block");
2268 if (operands.size() < 4) {
2269 return emitError(unknownLoc,
"OpPhi must specify result type, result <id>, "
2270 "and variable-parent pairs");
2275 BlockArgument blockArg = curBlock->addArgument(blockArgType, unknownLoc);
2276 valueMap[operands[1]] = blockArg;
2277 LLVM_DEBUG(logger.startLine()
2278 <<
"[phi] created block argument " << blockArg
2279 <<
" id = " << operands[1] <<
" of type " << blockArgType <<
"\n");
2283 for (
unsigned i = 2, e = operands.size(); i < e; i += 2) {
2284 uint32_t value = operands[i];
2285 Block *predecessor = getOrCreateBlock(operands[i + 1]);
2286 std::pair<Block *, Block *> predecessorTargetPair{predecessor, curBlock};
2287 blockPhiInfo[predecessorTargetPair].
push_back(value);
2288 LLVM_DEBUG(logger.startLine() <<
"[phi] predecessor @ " << predecessor
2289 <<
" with arg id = " << value <<
"\n");
2298 class ControlFlowStructurizer {
2301 ControlFlowStructurizer(
Location loc, uint32_t control,
2304 llvm::ScopedPrinter &logger)
2305 : location(loc), control(control), blockMergeInfo(mergeInfo),
2306 headerBlock(header), mergeBlock(merge), continueBlock(cont),
2309 ControlFlowStructurizer(
Location loc, uint32_t control,
2312 : location(loc), control(control), blockMergeInfo(mergeInfo),
2313 headerBlock(header), mergeBlock(merge), continueBlock(cont) {}
2323 LogicalResult structurize();
2328 spirv::SelectionOp createSelectionOp(uint32_t selectionControl);
2331 spirv::LoopOp createLoopOp(uint32_t loopControl);
2334 void collectBlocksInConstruct();
2343 Block *continueBlock;
2349 llvm::ScopedPrinter &logger;
2355 ControlFlowStructurizer::createSelectionOp(uint32_t selectionControl) {
2358 OpBuilder builder(&mergeBlock->front());
2360 auto control =
static_cast<spirv::SelectionControl
>(selectionControl);
2361 auto selectionOp = spirv::SelectionOp::create(builder, location, control);
2362 selectionOp.addMergeBlock(builder);
2367 spirv::LoopOp ControlFlowStructurizer::createLoopOp(uint32_t loopControl) {
2370 OpBuilder builder(&mergeBlock->front());
2372 auto control =
static_cast<spirv::LoopControl
>(loopControl);
2373 auto loopOp = spirv::LoopOp::create(builder, location, control);
2374 loopOp.addEntryAndMergeBlock(builder);
2379 void ControlFlowStructurizer::collectBlocksInConstruct() {
2380 assert(constructBlocks.empty() &&
"expected empty constructBlocks");
2383 constructBlocks.insert(headerBlock);
2387 for (
unsigned i = 0; i < constructBlocks.size(); ++i) {
2388 for (
auto *successor : constructBlocks[i]->getSuccessors())
2389 if (successor != mergeBlock)
2390 constructBlocks.insert(successor);
2394 LogicalResult ControlFlowStructurizer::structurize() {
2396 bool isLoop = continueBlock !=
nullptr;
2398 if (
auto loopOp = createLoopOp(control))
2399 op = loopOp.getOperation();
2401 if (
auto selectionOp = createSelectionOp(control))
2402 op = selectionOp.getOperation();
2411 mapper.
map(mergeBlock, &body.
back());
2413 collectBlocksInConstruct();
2435 for (
auto *block : constructBlocks) {
2438 auto *newBlock = builder.createBlock(&body.
back());
2439 mapper.
map(block, newBlock);
2440 LLVM_DEBUG(logger.startLine() <<
"[cf] cloned block " << newBlock
2441 <<
" from block " << block <<
"\n");
2445 newBlock->addArgument(blockArg.
getType(), blockArg.
getLoc());
2446 mapper.
map(blockArg, newArg);
2447 LLVM_DEBUG(logger.startLine() <<
"[cf] remapped block argument "
2448 << blockArg <<
" to " << newArg <<
"\n");
2451 LLVM_DEBUG(logger.startLine()
2452 <<
"[cf] block " << block <<
" is a function entry block\n");
2455 for (
auto &op : *block)
2456 newBlock->push_back(op.
clone(mapper));
2460 auto remapOperands = [&](
Operation *op) {
2463 operand.set(mappedOp);
2466 succOp.set(mappedOp);
2468 for (
auto &block : body)
2469 block.walk(remapOperands);
2477 headerBlock->replaceAllUsesWith(mergeBlock);
2480 logger.startLine() <<
"[cf] after cloning and fixing references:\n";
2481 headerBlock->getParentOp()->
print(logger.getOStream());
2482 logger.startLine() <<
"\n";
2486 if (!mergeBlock->args_empty()) {
2487 return mergeBlock->getParentOp()->emitError(
2488 "OpPhi in loop merge block unsupported");
2495 mergeBlock->addArgument(blockArg.
getType(), blockArg.
getLoc());
2500 if (!headerBlock->args_empty())
2501 blockArgs = {mergeBlock->args_begin(), mergeBlock->args_end()};
2505 builder.setInsertionPointToEnd(&body.front());
2506 spirv::BranchOp::create(builder, location, mapper.
lookupOrNull(headerBlock),
2534 body.back().addArgument(blockArg.
getType(), blockArg.
getLoc());
2535 valuesToYield.push_back(body.back().getArguments().back());
2536 outsideUses.push_back(blockArg);
2541 LLVM_DEBUG(logger.startLine() <<
"[cf] cleaning up blocks after clone\n");
2544 for (
auto *block : constructBlocks)
2545 block->dropAllReferences();
2550 for (
Block *block : constructBlocks) {
2555 outsideUses.push_back(result);
2559 if (!arg.use_empty()) {
2561 outsideUses.push_back(arg);
2566 assert(valuesToYield.size() == outsideUses.size());
2570 if (!valuesToYield.empty()) {
2571 LLVM_DEBUG(logger.startLine()
2572 <<
"[cf] yielding values from the selection / loop region\n");
2575 auto mergeOps = body.back().getOps<spirv::MergeOp>();
2576 Operation *merge = llvm::getSingleElement(mergeOps);
2578 merge->setOperands(valuesToYield);
2586 builder.setInsertionPoint(&mergeBlock->front());
2591 newOp = spirv::LoopOp::create(builder, location,
2593 static_cast<spirv::LoopControl
>(control));
2595 newOp = spirv::SelectionOp::create(
2597 static_cast<spirv::SelectionControl
>(control));
2607 for (
unsigned i = 0, e = outsideUses.size(); i != e; ++i)
2608 outsideUses[i].replaceAllUsesWith(op->
getResult(i));
2614 mergeBlock->eraseArguments(0, mergeBlock->getNumArguments());
2621 for (
auto *block : constructBlocks) {
2624 return op.
emitOpError(
"failed control flow structurization: value has "
2625 "uses outside of the "
2626 "enclosing selection/loop construct");
2628 if (!arg.use_empty())
2629 return emitError(arg.getLoc(),
"failed control flow structurization: "
2630 "block argument has uses outside of the "
2631 "enclosing selection/loop construct");
2635 for (
auto *block : constructBlocks) {
2676 auto it = blockMergeInfo.find(block);
2677 if (it != blockMergeInfo.end()) {
2683 return emitError(loc,
"failed control flow structurization: nested "
2684 "loop header block should be remapped!");
2686 Block *newContinue = it->second.continueBlock;
2690 return emitError(loc,
"failed control flow structurization: nested "
2691 "loop continue block should be remapped!");
2694 Block *newMerge = it->second.mergeBlock;
2696 newMerge = mappedTo;
2700 blockMergeInfo.
erase(it);
2701 blockMergeInfo.try_emplace(newHeader, loc, it->second.control, newMerge,
2708 if (block->walk(updateMergeInfo).wasInterrupted())
2716 LLVM_DEBUG(logger.startLine() <<
"[cf] changing entry block " << block
2717 <<
" to only contain a spirv.Branch op\n");
2721 builder.setInsertionPointToEnd(block);
2722 spirv::BranchOp::create(builder, location, mergeBlock);
2724 LLVM_DEBUG(logger.startLine() <<
"[cf] erasing block " << block <<
"\n");
2729 LLVM_DEBUG(logger.startLine()
2730 <<
"[cf] after structurizing construct with header block "
2731 << headerBlock <<
":\n"
2737 LogicalResult spirv::Deserializer::wireUpBlockArgument() {
2740 <<
"//----- [phi] start wiring up block arguments -----//\n";
2746 for (
const auto &info : blockPhiInfo) {
2747 Block *block = info.first.first;
2748 Block *target = info.first.second;
2749 const BlockPhiInfo &phiInfo = info.second;
2751 logger.startLine() <<
"[phi] block " << block <<
"\n";
2752 logger.startLine() <<
"[phi] before creating block argument:\n";
2754 logger.startLine() <<
"\n";
2760 opBuilder.setInsertionPoint(op);
2763 blockArgs.reserve(phiInfo.size());
2764 for (uint32_t valueId : phiInfo) {
2765 if (
Value value = getValue(valueId)) {
2766 blockArgs.push_back(value);
2767 LLVM_DEBUG(logger.startLine() <<
"[phi] block argument " << value
2768 <<
" id = " << valueId <<
"\n");
2770 return emitError(unknownLoc,
"OpPhi references undefined value!");
2774 if (
auto branchOp = dyn_cast<spirv::BranchOp>(op)) {
2776 spirv::BranchOp::create(opBuilder, branchOp.getLoc(),
2777 branchOp.getTarget(), blockArgs);
2779 }
else if (
auto branchCondOp = dyn_cast<spirv::BranchConditionalOp>(op)) {
2780 assert((branchCondOp.getTrueBlock() == target ||
2781 branchCondOp.getFalseBlock() == target) &&
2782 "expected target to be either the true or false target");
2783 if (target == branchCondOp.getTrueTarget())
2784 spirv::BranchConditionalOp::create(
2785 opBuilder, branchCondOp.getLoc(), branchCondOp.getCondition(),
2786 blockArgs, branchCondOp.getFalseBlockArguments(),
2787 branchCondOp.getBranchWeightsAttr(), branchCondOp.getTrueTarget(),
2788 branchCondOp.getFalseTarget());
2790 spirv::BranchConditionalOp::create(
2791 opBuilder, branchCondOp.getLoc(), branchCondOp.getCondition(),
2792 branchCondOp.getTrueBlockArguments(), blockArgs,
2793 branchCondOp.getBranchWeightsAttr(), branchCondOp.getTrueBlock(),
2794 branchCondOp.getFalseBlock());
2796 branchCondOp.erase();
2798 return emitError(unknownLoc,
"unimplemented terminator for Phi creation");
2802 logger.startLine() <<
"[phi] after creating block argument:\n";
2804 logger.startLine() <<
"\n";
2807 blockPhiInfo.clear();
2812 <<
"//--- [phi] completed wiring up block arguments ---//\n";
2817 LogicalResult spirv::Deserializer::splitConditionalBlocks() {
2820 for (
auto it = blockMergeInfoCopy.begin(), e = blockMergeInfoCopy.end();
2822 auto &[block, mergeInfo] = *it;
2825 if (mergeInfo.continueBlock)
2834 if (!isa<spirv::BranchConditionalOp>(terminator))
2838 bool splitHeaderMergeBlock =
false;
2839 for (
const auto &[_, mergeInfo] : blockMergeInfo) {
2840 if (mergeInfo.mergeBlock == block)
2841 splitHeaderMergeBlock =
true;
2848 if (!llvm::hasSingleElement(*block) || splitHeaderMergeBlock) {
2851 spirv::BranchOp::create(builder, block->
getParent()->
getLoc(), newBlock);
2855 blockMergeInfo.erase(block);
2856 blockMergeInfo.try_emplace(newBlock, mergeInfo);
2863 LogicalResult spirv::Deserializer::structurizeControlFlow() {
2864 if (!
options.enableControlFlowStructurization) {
2868 <<
"//----- [cf] skip structurizing control flow -----//\n";
2876 <<
"//----- [cf] start structurizing control flow -----//\n";
2881 logger.startLine() <<
"[cf] split conditional blocks\n";
2882 logger.startLine() <<
"\n";
2885 if (
failed(splitConditionalBlocks())) {
2892 while (!blockMergeInfo.empty()) {
2893 Block *headerBlock = blockMergeInfo.
begin()->first;
2894 BlockMergeInfo mergeInfo = blockMergeInfo.begin()->second;
2897 logger.startLine() <<
"[cf] header block " << headerBlock <<
":\n";
2898 headerBlock->
print(logger.getOStream());
2899 logger.startLine() <<
"\n";
2902 auto *mergeBlock = mergeInfo.mergeBlock;
2903 assert(mergeBlock &&
"merge block cannot be nullptr");
2904 if (mergeInfo.continueBlock && !mergeBlock->args_empty())
2905 return emitError(unknownLoc,
"OpPhi in loop merge block unimplemented");
2907 logger.startLine() <<
"[cf] merge block " << mergeBlock <<
":\n";
2908 mergeBlock->print(logger.getOStream());
2909 logger.startLine() <<
"\n";
2912 auto *continueBlock = mergeInfo.continueBlock;
2913 LLVM_DEBUG(
if (continueBlock) {
2914 logger.startLine() <<
"[cf] continue block " << continueBlock <<
":\n";
2915 continueBlock->print(logger.getOStream());
2916 logger.startLine() <<
"\n";
2920 blockMergeInfo.erase(blockMergeInfo.begin());
2921 ControlFlowStructurizer structurizer(mergeInfo.loc, mergeInfo.control,
2922 blockMergeInfo, headerBlock,
2923 mergeBlock, continueBlock
2929 if (
failed(structurizer.structurize()))
2936 <<
"//--- [cf] completed structurizing control flow ---//\n";
2949 auto fileName = debugInfoMap.lookup(debugLine->fileID).str();
2950 if (fileName.empty())
2951 fileName =
"<unknown>";
2963 if (operands.size() != 3)
2964 return emitError(unknownLoc,
"OpLine must have 3 operands");
2965 debugLine = DebugLine{operands[0], operands[1], operands[2]};
2969 void spirv::Deserializer::clearDebugLine() { debugLine = std::nullopt; }
2973 if (operands.size() < 2)
2974 return emitError(unknownLoc,
"OpString needs at least 2 operands");
2976 if (!debugInfoMap.lookup(operands[0]).empty())
2978 "duplicate debug string found for result <id> ")
2981 unsigned wordIndex = 1;
2983 if (wordIndex != operands.size())
2985 "unexpected trailing words in OpString instruction");
static bool isLoop(Operation *op)
Returns true if the given operation represents a loop by testing whether it implements the LoopLikeOp...
static bool isFnEntryBlock(Block *block)
Returns true if the given block is a function entry block.
#define MIN_VERSION_CASE(v)
static LogicalResult deserializeCacheControlDecoration(Location loc, OpBuilder &opBuilder, DenseMap< uint32_t, NamedAttrList > &decorations, ArrayRef< uint32_t > words, StringAttr symbol, StringRef decorationName, StringRef cacheControlKind)
static llvm::ManagedStatic< PassManagerOptions > options
static void print(spirv::VerCapExtAttr triple, DialectAsmPrinter &printer)
Attributes are known-constant values of operations.
This class represents an argument of a Block.
Location getLoc() const
Return the location for this argument.
Block represents an ordered list of Operations.
void erase()
Unlink this Block from its parent region and delete it.
Block * splitBlock(iterator splitBefore)
Split the block into two blocks before the specified operation or iterator.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
Operation * getTerminator()
Get the terminator operation of this block.
void print(raw_ostream &os)
bool mightHaveTerminator()
Return "true" if this block might have a terminator.
BlockArgListType getArguments()
bool isEntryBlock()
Return if this block is the entry block in the parent region.
void push_back(Operation *op)
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
StringAttr getStringAttr(const Twine &bytes)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
static FileLineColLoc get(StringAttr filename, unsigned line, unsigned column)
A symbol reference with a reference path containing a single element.
This is a utility class for mapping one set of IR entities to another.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
auto lookupOrNull(T from) const
Lookup a mapped value within the map.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
NamedAttribute represents a combination of a name and an Attribute value.
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
Operation * clone(IRMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, NamedAttrList &&attributes, OpaqueProperties properties, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
MutableArrayRef< BlockOperand > getBlockOperands()
MutableArrayRef< OpOperand > getOpOperands()
result_range getResults()
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
BlockListType & getBlocks()
Location getLoc()
Return a location for this region.
BlockListType::iterator iterator
void takeBody(Region &other)
Takes body of another region (that region will have no body after this operation completes).
This class provides an abstraction over the various different ranges of value types.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
static ArrayType get(Type elementType, unsigned elementCount)
static CooperativeMatrixType get(Type elementType, uint32_t rows, uint32_t columns, Scope scope, CooperativeMatrixUseKHR use)
LogicalResult deserialize()
Deserializes the remembered SPIR-V binary module.
Deserializer(ArrayRef< uint32_t > binary, MLIRContext *context, const DeserializationOptions &options)
Creates a deserializer for the given SPIR-V binary module.
OwningOpRef< spirv::ModuleOp > collect()
Collects the final SPIR-V ModuleOp.
static ImageType get(Type elementType, Dim dim, ImageDepthInfo depth=ImageDepthInfo::DepthUnknown, ImageArrayedInfo arrayed=ImageArrayedInfo::NonArrayed, ImageSamplingInfo samplingInfo=ImageSamplingInfo::SingleSampled, ImageSamplerUseInfo samplerUse=ImageSamplerUseInfo::SamplerUnknown, ImageFormat format=ImageFormat::Unknown)
static MatrixType get(Type columnType, uint32_t columnCount)
static PointerType get(Type pointeeType, StorageClass storageClass)
static RuntimeArrayType get(Type elementType)
static SampledImageType get(Type imageType)
static StructType getIdentified(MLIRContext *context, StringRef identifier)
Construct an identified StructType.
static StructType getEmpty(MLIRContext *context, StringRef identifier="")
Construct a (possibly identified) StructType with no members.
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={}, ArrayRef< StructDecorationInfo > structDecorations={})
Construct a literal StructType with at least one member.
static TensorArmType get(ArrayRef< int64_t > shape, Type elementType)
static VerCapExtAttr get(Version version, ArrayRef< Capability > capabilities, ArrayRef< Extension > extensions, MLIRContext *context)
Gets a VerCapExtAttr instance.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
constexpr uint32_t kMagicNumber
SPIR-V magic number.
StringRef decodeStringLiteral(ArrayRef< uint32_t > words, unsigned &wordIndex)
Decodes a string literal in words starting at wordIndex.
DenseMap< Block *, BlockMergeInfo > BlockMergeInfoMap
Map from a selection/loop's header block to its merge (and continue) target.
constexpr unsigned kHeaderWordCount
SPIR-V binary header word count.
Include the generated interface declarations.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
static std::string debugString(T &&op)
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
This represents an operation in an abstracted form, suitable for use with the builder APIs.