24 #include "llvm/ADT/STLExtras.h" 25 #include "llvm/ADT/Sequence.h" 26 #include "llvm/ADT/SmallVector.h" 27 #include "llvm/ADT/StringExtras.h" 28 #include "llvm/ADT/bit.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/SaveAndRestore.h" 31 #include "llvm/Support/raw_ostream.h" 35 #define DEBUG_TYPE "spirv-deserialization" 44 isa_and_nonnull<spirv::FuncOp>(block->
getParentOp());
53 : binary(binary), context(context), unknownLoc(UnknownLoc::get(context)),
54 module(createModuleOp()), opBuilder(module->getRegion())
66 <<
"//+++---------- start deserialization ----------+++//\n";
69 if (
failed(processHeader()))
72 spirv::Opcode opcode = spirv::Opcode::OpNop;
74 auto binarySize = binary.size();
75 while (curOffset < binarySize) {
78 if (
failed(sliceInstruction(opcode, operands)))
81 if (
failed(processInstruction(opcode, operands)))
85 assert(curOffset == binarySize &&
86 "deserializer should never index beyond the binary end");
88 for (
auto &deferred : deferredInstructions) {
89 if (
failed(processInstruction(deferred.first, deferred.second,
false))) {
96 LLVM_DEBUG(logger.startLine()
97 <<
"//+++-------- completed deserialization --------+++//\n");
102 return std::move(module);
111 OperationState state(unknownLoc, spirv::ModuleOp::getOperationName());
112 spirv::ModuleOp::build(builder, state);
119 "SPIR-V binary module must have a 5-word header");
122 return emitError(unknownLoc,
"incorrect magic number");
125 uint32_t majorVersion = (binary[1] << 8) >> 24;
126 uint32_t minorVersion = (binary[1] << 16) >> 24;
127 if (majorVersion == 1) {
128 switch (minorVersion) {
129 #define MIN_VERSION_CASE(v) \ 131 version = spirv::Version::V_1_##v; \ 140 #undef MIN_VERSION_CASE 142 return emitError(unknownLoc,
"unsupported SPIR-V minor version: ")
146 return emitError(unknownLoc,
"unsupported SPIR-V major version: ")
157 if (operands.size() != 1)
158 return emitError(unknownLoc,
"OpMemoryModel must have one parameter");
160 auto cap = spirv::symbolizeCapability(operands[0]);
162 return emitError(unknownLoc,
"unknown capability: ") << operands[0];
164 capabilities.insert(*cap);
172 "OpExtension must have a literal string for the extension name");
175 unsigned wordIndex = 0;
177 if (wordIndex != words.size())
179 "unexpected trailing words in OpExtension instruction");
180 auto ext = spirv::symbolizeExtension(extName);
182 return emitError(unknownLoc,
"unknown extension: ") << extName;
184 extensions.insert(*ext);
190 if (words.size() < 2) {
192 "OpExtInstImport must have a result <id> and a literal " 193 "string for the extended instruction set name");
196 unsigned wordIndex = 1;
198 if (wordIndex != words.size()) {
200 "unexpected trailing words in OpExtInstImport");
205 void spirv::Deserializer::attachVCETriple() {
207 spirv::ModuleOp::getVCETripleAttrName(),
209 extensions.getArrayRef(), context));
214 if (operands.size() != 2)
215 return emitError(unknownLoc,
"OpMemoryModel must have two operands");
231 if (words.size() < 2) {
233 unknownLoc,
"OpDecorate must have at least result <id> and Decoration");
235 auto decorationName =
236 stringifyDecoration(static_cast<spirv::Decoration>(words[1]));
237 if (decorationName.empty()) {
238 return emitError(unknownLoc,
"invalid Decoration code : ") << words[1];
240 auto attrName = llvm::convertToSnakeFromCamelCase(decorationName);
242 switch (static_cast<spirv::Decoration>(words[1])) {
243 case spirv::Decoration::DescriptorSet:
244 case spirv::Decoration::Binding:
245 if (words.size() != 3) {
246 return emitError(unknownLoc,
"OpDecorate with ")
247 << decorationName <<
" needs a single integer literal";
249 decorations[words[0]].set(
252 case spirv::Decoration::BuiltIn:
253 if (words.size() != 3) {
254 return emitError(unknownLoc,
"OpDecorate with ")
255 << decorationName <<
" needs a single integer literal";
257 decorations[words[0]].set(
259 stringifyBuiltIn(static_cast<spirv::BuiltIn>(words[2]))));
261 case spirv::Decoration::ArrayStride:
262 if (words.size() != 3) {
263 return emitError(unknownLoc,
"OpDecorate with ")
264 << decorationName <<
" needs a single integer literal";
266 typeDecorations[words[0]] = words[2];
268 case spirv::Decoration::Aliased:
269 case spirv::Decoration::Block:
270 case spirv::Decoration::BufferBlock:
271 case spirv::Decoration::Flat:
272 case spirv::Decoration::NonReadable:
273 case spirv::Decoration::NonWritable:
274 case spirv::Decoration::NoPerspective:
275 case spirv::Decoration::Restrict:
276 case spirv::Decoration::RelaxedPrecision:
277 if (words.size() != 2) {
278 return emitError(unknownLoc,
"OpDecoration with ")
279 << decorationName <<
"needs a single target <id>";
285 decorations[words[0]].set(symbol, opBuilder.
getUnitAttr());
287 case spirv::Decoration::Location:
288 case spirv::Decoration::SpecId:
289 if (words.size() != 3) {
290 return emitError(unknownLoc,
"OpDecoration with ")
291 << decorationName <<
"needs a single integer literal";
293 decorations[words[0]].set(
297 return emitError(unknownLoc,
"unhandled Decoration : '") << decorationName;
305 if (words.size() < 3) {
307 "OpMemberDecorate must have at least 3 operands");
310 auto decoration =
static_cast<spirv::Decoration
>(words[2]);
311 if (decoration == spirv::Decoration::Offset && words.size() != 4) {
313 " missing offset specification in OpMemberDecorate with " 314 "Offset decoration");
317 if (words.size() > 3) {
318 decorationOperands = words.slice(3);
320 memberDecorationMap[words[0]][words[1]][decoration] = decorationOperands;
325 if (words.size() < 3) {
326 return emitError(unknownLoc,
"OpMemberName must have at least 3 operands");
328 unsigned wordIndex = 2;
330 if (wordIndex != words.size()) {
332 "unexpected trailing words in OpMemberName instruction");
334 memberNameMap[words[0]][words[1]] = name;
341 return emitError(unknownLoc,
"found function inside function");
345 if (operands.size() != 4) {
346 return emitError(unknownLoc,
"OpFunction must have 4 parameters");
348 Type resultType = getType(operands[0]);
350 return emitError(unknownLoc,
"undefined result type from <id> ")
354 uint32_t fnID = operands[1];
355 if (funcMap.count(fnID)) {
356 return emitError(unknownLoc,
"duplicate function definition/declaration");
359 auto fnControl = spirv::symbolizeFunctionControl(operands[2]);
361 return emitError(unknownLoc,
"unknown Function Control: ") << operands[2];
364 Type fnType = getType(operands[3]);
365 if (!fnType || !fnType.
isa<FunctionType>()) {
366 return emitError(unknownLoc,
"unknown function type from <id> ")
369 auto functionType = fnType.
cast<FunctionType>();
371 if ((isVoidType(resultType) && functionType.getNumResults() != 0) ||
372 (functionType.getNumResults() == 1 &&
373 functionType.getResult(0) != resultType)) {
374 return emitError(unknownLoc,
"mismatch in function type ")
375 << functionType <<
" and return type " << resultType <<
" specified";
378 std::string fnName = getFunctionSymbol(fnID);
379 auto funcOp = opBuilder.
create<spirv::FuncOp>(
380 unknownLoc, fnName, functionType, fnControl.getValue());
381 curFunction = funcMap[fnID] = funcOp;
382 auto *entryBlock = funcOp.addEntryBlock();
385 <<
"//===-------------------------------------------===//\n";
386 logger.startLine() <<
"[fn] name: " << fnName <<
"\n";
387 logger.startLine() <<
"[fn] type: " << fnType <<
"\n";
388 logger.startLine() <<
"[fn] ID: " << fnID <<
"\n";
389 logger.startLine() <<
"[fn] entry block: " << entryBlock <<
"\n";
394 if (functionType.getNumInputs()) {
395 for (
size_t i = 0, e = functionType.getNumInputs(); i != e; ++i) {
396 auto argType = functionType.getInput(i);
397 spirv::Opcode opcode = spirv::Opcode::OpNop;
399 if (
failed(sliceInstruction(opcode, operands,
400 spirv::Opcode::OpFunctionParameter))) {
403 if (opcode != spirv::Opcode::OpFunctionParameter) {
406 "missing OpFunctionParameter instruction for argument ")
409 if (operands.size() != 2) {
412 "expected result type and result <id> for OpFunctionParameter");
414 auto argDefinedType = getType(operands[0]);
415 if (!argDefinedType || argDefinedType != argType) {
417 "mismatch in argument type between function type " 419 << functionType <<
" and argument type definition " 420 << argDefinedType <<
" at argument " << i;
422 if (getValue(operands[1])) {
423 return emitError(unknownLoc,
"duplicate definition of result <id> ")
426 auto argValue = funcOp.getArgument(i);
427 valueMap[operands[1]] = argValue;
435 spirv::Opcode opcode = spirv::Opcode::OpNop;
443 if (
failed(sliceInstruction(opcode, instOperands,
444 spirv::Opcode::OpFunctionEnd))) {
447 if (opcode == spirv::Opcode::OpFunctionEnd) {
448 return processFunctionEnd(instOperands);
450 if (opcode != spirv::Opcode::OpLabel) {
451 return emitError(unknownLoc,
"a basic block must start with OpLabel");
453 if (instOperands.size() != 1) {
454 return emitError(unknownLoc,
"OpLabel should only have result <id>");
456 blockMap[instOperands[0]] = entryBlock;
457 if (
failed(processLabel(instOperands))) {
463 while (
succeeded(sliceInstruction(opcode, instOperands,
464 spirv::Opcode::OpFunctionEnd)) &&
465 opcode != spirv::Opcode::OpFunctionEnd) {
466 if (
failed(processInstruction(opcode, instOperands))) {
470 if (opcode != spirv::Opcode::OpFunctionEnd) {
474 return processFunctionEnd(instOperands);
480 if (!operands.empty()) {
481 return emitError(unknownLoc,
"unexpected operands for OpFunctionEnd");
486 if (
failed(wireUpBlockArgument()) ||
failed(structurizeControlFlow())) {
491 curFunction = llvm::None;
496 <<
"//===-------------------------------------------===//\n";
502 spirv::Deserializer::getConstant(uint32_t
id) {
503 auto constIt = constantMap.find(
id);
504 if (constIt == constantMap.end())
506 return constIt->getSecond();
510 spirv::Deserializer::getSpecConstantOperation(uint32_t
id) {
511 auto constIt = specConstOperationMap.find(
id);
512 if (constIt == specConstOperationMap.end())
514 return constIt->getSecond();
517 std::string spirv::Deserializer::getFunctionSymbol(uint32_t
id) {
518 auto funcName = nameMap.lookup(
id).str();
519 if (funcName.empty()) {
520 funcName =
"spirv_fn_" + std::to_string(
id);
525 std::string spirv::Deserializer::getSpecConstantSymbol(uint32_t
id) {
526 auto constName = nameMap.lookup(
id).str();
527 if (constName.empty()) {
528 constName =
"spirv_spec_const_" + std::to_string(
id);
533 spirv::SpecConstantOp
534 spirv::Deserializer::createSpecConstant(
Location loc, uint32_t resultID,
536 auto symName = opBuilder.
getStringAttr(getSpecConstantSymbol(resultID));
537 auto op = opBuilder.
create<spirv::SpecConstantOp>(unknownLoc, symName,
539 if (decorations.count(resultID)) {
540 for (
auto attr : decorations[resultID].getAttrs())
541 op->
setAttr(attr.getName(), attr.getValue());
543 specConstMap[resultID] = op;
549 unsigned wordIndex = 0;
550 if (operands.size() < 3) {
553 "OpVariable needs at least 3 operands, type, <id> and storage class");
557 auto type = getType(operands[wordIndex]);
559 return emitError(unknownLoc,
"unknown result type <id> : ")
560 << operands[wordIndex];
565 "expected a result type <id> to be a spv.ptr, found : ")
571 auto variableID = operands[wordIndex];
572 auto variableName = nameMap.lookup(variableID).str();
573 if (variableName.empty()) {
574 variableName =
"spirv_var_" + std::to_string(variableID);
579 auto storageClass =
static_cast<spirv::StorageClass
>(operands[wordIndex]);
580 if (ptrType.getStorageClass() != storageClass) {
581 return emitError(unknownLoc,
"mismatch in storage class of pointer type ")
582 << type <<
" and that specified in OpVariable instruction : " 583 << stringifyStorageClass(storageClass);
589 if (wordIndex < operands.size()) {
590 auto initializerOp = getGlobalVariable(operands[wordIndex]);
591 if (!initializerOp) {
592 return emitError(unknownLoc,
"unknown <id> ")
593 << operands[wordIndex] <<
"used as initializer";
596 initializer = SymbolRefAttr::get(initializerOp.getOperation());
598 if (wordIndex != operands.size()) {
600 "found more operands than expected when deserializing " 601 "OpVariable instruction, only ")
602 << wordIndex <<
" of " << operands.size() <<
" processed";
604 auto loc = createFileLineColLoc(opBuilder);
605 auto varOp = opBuilder.
create<spirv::GlobalVariableOp>(
606 loc, TypeAttr::get(type), opBuilder.
getStringAttr(variableName),
610 if (decorations.count(variableID)) {
611 for (
auto attr : decorations[variableID].getAttrs())
612 varOp->
setAttr(attr.getName(), attr.getValue());
614 globalVariableMap[variableID] = varOp;
618 IntegerAttr spirv::Deserializer::getConstantInt(uint32_t
id) {
619 auto constInfo = getConstant(
id);
623 return constInfo->first.dyn_cast<IntegerAttr>();
627 if (operands.size() < 2) {
628 return emitError(unknownLoc,
"OpName needs at least 2 operands");
630 if (!nameMap.lookup(operands[0]).empty()) {
631 return emitError(unknownLoc,
"duplicate name found for result <id> ")
634 unsigned wordIndex = 1;
636 if (wordIndex != operands.size()) {
638 "unexpected trailing words in OpName instruction");
640 nameMap[operands[0]] = name;
648 LogicalResult spirv::Deserializer::processType(spirv::Opcode opcode,
650 if (operands.empty()) {
651 return emitError(unknownLoc,
"type instruction with opcode ")
652 << spirv::stringifyOpcode(opcode) <<
" needs at least one <id>";
657 if (typeMap.count(operands[0])) {
658 return emitError(unknownLoc,
"duplicate definition for result <id> ")
663 case spirv::Opcode::OpTypeVoid:
664 if (operands.size() != 1)
665 return emitError(unknownLoc,
"OpTypeVoid must have no parameters");
668 case spirv::Opcode::OpTypeBool:
669 if (operands.size() != 1)
670 return emitError(unknownLoc,
"OpTypeBool must have no parameters");
671 typeMap[operands[0]] = opBuilder.
getI1Type();
673 case spirv::Opcode::OpTypeInt: {
674 if (operands.size() != 3)
676 unknownLoc,
"OpTypeInt must have bitwidth and signedness parameters");
686 : IntegerType::SignednessSemantics::Signless;
687 typeMap[operands[0]] = IntegerType::get(context, operands[1], sign);
689 case spirv::Opcode::OpTypeFloat: {
690 if (operands.size() != 2)
691 return emitError(unknownLoc,
"OpTypeFloat must have bitwidth parameter");
694 switch (operands[1]) {
705 return emitError(unknownLoc,
"unsupported OpTypeFloat bitwidth: ")
708 typeMap[operands[0]] = floatTy;
710 case spirv::Opcode::OpTypeVector: {
711 if (operands.size() != 3) {
714 "OpTypeVector must have element type and count parameters");
716 Type elementTy = getType(operands[1]);
718 return emitError(unknownLoc,
"OpTypeVector references undefined <id> ")
721 typeMap[operands[0]] = VectorType::get({operands[2]}, elementTy);
723 case spirv::Opcode::OpTypePointer: {
724 return processOpTypePointer(operands);
726 case spirv::Opcode::OpTypeArray:
727 return processArrayType(operands);
728 case spirv::Opcode::OpTypeCooperativeMatrixNV:
729 return processCooperativeMatrixType(operands);
730 case spirv::Opcode::OpTypeFunction:
731 return processFunctionType(operands);
732 case spirv::Opcode::OpTypeImage:
733 return processImageType(operands);
734 case spirv::Opcode::OpTypeSampledImage:
735 return processSampledImageType(operands);
736 case spirv::Opcode::OpTypeRuntimeArray:
737 return processRuntimeArrayType(operands);
738 case spirv::Opcode::OpTypeStruct:
739 return processStructType(operands);
740 case spirv::Opcode::OpTypeMatrix:
741 return processMatrixType(operands);
743 return emitError(unknownLoc,
"unhandled type instruction");
750 if (operands.size() != 3)
751 return emitError(unknownLoc,
"OpTypePointer must have two parameters");
753 auto pointeeType = getType(operands[2]);
755 return emitError(unknownLoc,
"unknown OpTypePointer pointee type <id> ")
758 uint32_t typePointerID = operands[0];
759 auto storageClass =
static_cast<spirv::StorageClass
>(operands[1]);
762 for (
auto *deferredStructIt = std::begin(deferredStructTypesInfos);
763 deferredStructIt != std::end(deferredStructTypesInfos);) {
764 for (
auto *unresolvedMemberIt =
765 std::begin(deferredStructIt->unresolvedMemberTypes);
766 unresolvedMemberIt !=
767 std::end(deferredStructIt->unresolvedMemberTypes);) {
768 if (unresolvedMemberIt->first == typePointerID) {
772 deferredStructIt->memberTypes[unresolvedMemberIt->second] =
773 typeMap[typePointerID];
775 deferredStructIt->unresolvedMemberTypes.erase(unresolvedMemberIt);
777 ++unresolvedMemberIt;
781 if (deferredStructIt->unresolvedMemberTypes.empty()) {
783 auto structType = deferredStructIt->deferredStructType;
785 assert(structType &&
"expected a spirv::StructType");
786 assert(structType.isIdentified() &&
"expected an indentified struct");
788 if (
failed(structType.trySetBody(
789 deferredStructIt->memberTypes, deferredStructIt->offsetInfo,
790 deferredStructIt->memberDecorationsInfo)))
793 deferredStructIt = deferredStructTypesInfos.erase(deferredStructIt);
804 if (operands.size() != 3) {
806 "OpTypeArray must have element type and count parameters");
809 Type elementTy = getType(operands[1]);
811 return emitError(unknownLoc,
"OpTypeArray references undefined <id> ")
817 auto countInfo = getConstant(operands[2]);
819 return emitError(unknownLoc,
"OpTypeArray count <id> ")
820 << operands[2] <<
"can only come from normal constant right now";
823 if (
auto intVal = countInfo->first.dyn_cast<IntegerAttr>()) {
824 count = intVal.getValue().getZExtValue();
826 return emitError(unknownLoc,
"OpTypeArray count must come from a " 827 "scalar integer constant instruction");
831 elementTy, count, typeDecorations.lookup(operands[0]));
837 assert(!operands.empty() &&
"No operands for processing function type");
838 if (operands.size() == 1) {
839 return emitError(unknownLoc,
"missing return type for OpTypeFunction");
841 auto returnType = getType(operands[1]);
843 return emitError(unknownLoc,
"unknown return type in OpTypeFunction");
846 for (
size_t i = 2, e = operands.size(); i < e; ++i) {
847 auto ty = getType(operands[i]);
849 return emitError(unknownLoc,
"unknown argument type in OpTypeFunction");
851 argTypes.push_back(ty);
854 if (!isVoidType(returnType)) {
855 returnTypes = llvm::makeArrayRef(returnType);
857 typeMap[operands[0]] = FunctionType::get(context, argTypes, returnTypes);
863 if (operands.size() != 5) {
864 return emitError(unknownLoc,
"OpTypeCooperativeMatrix must have element " 865 "type and row x column parameters");
868 Type elementTy = getType(operands[1]);
871 "OpTypeCooperativeMatrix references undefined <id> ")
875 auto scope = spirv::symbolizeScope(getConstantInt(operands[2]).getInt());
878 "OpTypeCooperativeMatrix references undefined scope <id> ")
882 unsigned rows = getConstantInt(operands[3]).getInt();
883 unsigned columns = getConstantInt(operands[4]).getInt();
886 elementTy, scope.getValue(), rows, columns);
892 if (operands.size() != 2) {
893 return emitError(unknownLoc,
"OpTypeRuntimeArray must have two operands");
895 Type memberType = getType(operands[1]);
898 "OpTypeRuntimeArray references undefined <id> ")
902 memberType, typeDecorations.lookup(operands[0]));
910 if (operands.empty()) {
911 return emitError(unknownLoc,
"OpTypeStruct must have at least result <id>");
914 if (operands.size() == 1) {
916 typeMap[operands[0]] =
925 for (
auto op : llvm::drop_begin(operands, 1)) {
926 Type memberType = getType(op);
927 bool typeForwardPtr = (typeForwardPointerIDs.count(op) != 0);
929 if (!memberType && !typeForwardPtr)
930 return emitError(unknownLoc,
"OpTypeStruct references undefined <id> ")
934 unresolvedMemberTypes.emplace_back(op, memberTypes.size());
936 memberTypes.push_back(memberType);
941 if (memberDecorationMap.count(operands[0])) {
942 auto &allMemberDecorations = memberDecorationMap[operands[0]];
943 for (
auto memberIndex : llvm::seq<uint32_t>(0, memberTypes.size())) {
944 if (allMemberDecorations.count(memberIndex)) {
945 for (
auto &memberDecoration : allMemberDecorations[memberIndex]) {
947 if (memberDecoration.first == spirv::Decoration::Offset) {
949 if (offsetInfo.empty()) {
950 offsetInfo.resize(memberTypes.size());
952 offsetInfo[memberIndex] = memberDecoration.second[0];
954 if (!memberDecoration.second.empty()) {
955 memberDecorationsInfo.emplace_back(memberIndex, 1,
956 memberDecoration.first,
957 memberDecoration.second[0]);
959 memberDecorationsInfo.emplace_back(memberIndex, 0,
960 memberDecoration.first, 0);
968 uint32_t structID = operands[0];
969 std::string structIdentifier = nameMap.lookup(structID).str();
971 if (structIdentifier.empty()) {
972 assert(unresolvedMemberTypes.empty() &&
973 "didn't expect unresolved member types");
978 typeMap[structID] = structTy;
980 if (!unresolvedMemberTypes.empty())
981 deferredStructTypesInfos.push_back({structTy, unresolvedMemberTypes,
982 memberTypes, offsetInfo,
983 memberDecorationsInfo});
984 else if (
failed(structTy.trySetBody(memberTypes, offsetInfo,
985 memberDecorationsInfo)))
996 if (operands.size() != 3) {
998 return emitError(unknownLoc,
"OpTypeMatrix must have 3 operands" 999 " (result_id, column_type, and column_count)");
1002 Type elementTy = getType(operands[1]);
1005 "OpTypeMatrix references undefined column type.")
1009 uint32_t colsCount = operands[2];
1016 if (operands.size() != 2)
1018 "OpTypeForwardPointer instruction must have two operands");
1020 typeForwardPointerIDs.insert(operands[0]);
1030 if (operands.size() != 8)
1033 "OpTypeImage with non-eight operands are not supported yet");
1035 Type elementTy = getType(operands[1]);
1037 return emitError(unknownLoc,
"OpTypeImage references undefined <id>: ")
1040 auto dim = spirv::symbolizeDim(operands[2]);
1042 return emitError(unknownLoc,
"unknown Dim for OpTypeImage: ")
1045 auto depthInfo = spirv::symbolizeImageDepthInfo(operands[3]);
1047 return emitError(unknownLoc,
"unknown Depth for OpTypeImage: ")
1050 auto arrayedInfo = spirv::symbolizeImageArrayedInfo(operands[4]);
1052 return emitError(unknownLoc,
"unknown Arrayed for OpTypeImage: ")
1055 auto samplingInfo = spirv::symbolizeImageSamplingInfo(operands[5]);
1057 return emitError(unknownLoc,
"unknown MS for OpTypeImage: ") << operands[5];
1059 auto samplerUseInfo = spirv::symbolizeImageSamplerUseInfo(operands[6]);
1060 if (!samplerUseInfo)
1061 return emitError(unknownLoc,
"unknown Sampled for OpTypeImage: ")
1064 auto format = spirv::symbolizeImageFormat(operands[7]);
1066 return emitError(unknownLoc,
"unknown Format for OpTypeImage: ")
1070 elementTy, dim.getValue(), depthInfo.getValue(), arrayedInfo.getValue(),
1071 samplingInfo.getValue(), samplerUseInfo.getValue(), format.getValue());
1077 if (operands.size() != 2)
1078 return emitError(unknownLoc,
"OpTypeSampledImage must have two operands");
1080 Type elementTy = getType(operands[1]);
1083 "OpTypeSampledImage references undefined <id>: ")
1096 StringRef opname = isSpec ?
"OpSpecConstant" :
"OpConstant";
1098 if (operands.size() < 2) {
1100 << opname <<
" must have type <id> and result <id>";
1102 if (operands.size() < 3) {
1104 << opname <<
" must have at least 1 more parameter";
1107 Type resultType = getType(operands[0]);
1109 return emitError(unknownLoc,
"undefined result type from <id> ")
1113 auto checkOperandSizeForBitwidth = [&](
unsigned bitwidth) ->
LogicalResult {
1114 if (bitwidth == 64) {
1115 if (operands.size() == 4) {
1119 << opname <<
" should have 2 parameters for 64-bit values";
1121 if (bitwidth <= 32) {
1122 if (operands.size() == 3) {
1128 <<
" should have 1 parameter for values with no more than 32 bits";
1130 return emitError(unknownLoc,
"unsupported OpConstant bitwidth: ")
1134 auto resultID = operands[1];
1136 if (
auto intType = resultType.
dyn_cast<IntegerType>()) {
1137 auto bitwidth = intType.getWidth();
1138 if (
failed(checkOperandSizeForBitwidth(bitwidth))) {
1143 if (bitwidth == 64) {
1150 } words = {operands[2], operands[3]};
1151 value = APInt(64, llvm::bit_cast<uint64_t>(words),
true);
1152 }
else if (bitwidth <= 32) {
1153 value = APInt(bitwidth, operands[2],
true);
1156 auto attr = opBuilder.getIntegerAttr(intType, value);
1159 createSpecConstant(unknownLoc, resultID, attr);
1163 constantMap.try_emplace(resultID, attr, intType);
1170 auto bitwidth = floatType.getWidth();
1171 if (
failed(checkOperandSizeForBitwidth(bitwidth))) {
1176 if (floatType.isF64()) {
1183 } words = {operands[2], operands[3]};
1184 value = APFloat(llvm::bit_cast<double>(words));
1185 }
else if (floatType.isF32()) {
1186 value = APFloat(llvm::bit_cast<float>(operands[2]));
1187 }
else if (floatType.isF16()) {
1188 APInt data(16, operands[2]);
1189 value = APFloat(APFloat::IEEEhalf(), data);
1192 auto attr = opBuilder.getFloatAttr(floatType, value);
1194 createSpecConstant(unknownLoc, resultID, attr);
1198 constantMap.try_emplace(resultID, attr, floatType);
1204 return emitError(unknownLoc,
"OpConstant can only generate values of " 1205 "scalar integer or floating-point type");
1210 if (operands.size() != 2) {
1212 << (isSpec ?
"Spec" :
"") <<
"Constant" 1213 << (isTrue ?
"True" :
"False")
1214 <<
" must have type <id> and result <id>";
1217 auto attr = opBuilder.getBoolAttr(isTrue);
1218 auto resultID = operands[1];
1220 createSpecConstant(unknownLoc, resultID, attr);
1224 constantMap.try_emplace(resultID, attr, opBuilder.getI1Type());
1232 if (operands.size() < 2) {
1234 "OpConstantComposite must have type <id> and result <id>");
1236 if (operands.size() < 3) {
1238 "OpConstantComposite must have at least 1 parameter");
1241 Type resultType = getType(operands[0]);
1243 return emitError(unknownLoc,
"undefined result type from <id> ")
1248 elements.reserve(operands.size() - 2);
1249 for (
unsigned i = 2, e = operands.size(); i < e; ++i) {
1250 auto elementInfo = getConstant(operands[i]);
1252 return emitError(unknownLoc,
"OpConstantComposite component <id> ")
1253 << operands[i] <<
" must come from a normal constant";
1255 elements.push_back(elementInfo->first);
1258 auto resultID = operands[1];
1263 constantMap.try_emplace(resultID, attr, resultType);
1265 auto attr = opBuilder.getArrayAttr(elements);
1266 constantMap.try_emplace(resultID, attr, resultType);
1268 return emitError(unknownLoc,
"unsupported OpConstantComposite type: ")
1277 if (operands.size() < 2) {
1279 "OpConstantComposite must have type <id> and result <id>");
1281 if (operands.size() < 3) {
1283 "OpConstantComposite must have at least 1 parameter");
1286 Type resultType = getType(operands[0]);
1288 return emitError(unknownLoc,
"undefined result type from <id> ")
1292 auto resultID = operands[1];
1293 auto symName = opBuilder.getStringAttr(getSpecConstantSymbol(resultID));
1296 elements.reserve(operands.size() - 2);
1297 for (
unsigned i = 2, e = operands.size(); i < e; ++i) {
1298 auto elementInfo = getSpecConstant(operands[i]);
1299 elements.push_back(SymbolRefAttr::get(elementInfo));
1302 auto op = opBuilder.create<spirv::SpecConstantCompositeOp>(
1303 unknownLoc, TypeAttr::get(resultType), symName,
1304 opBuilder.getArrayAttr(elements));
1305 specConstCompositeMap[resultID] = op;
1312 if (operands.size() < 3)
1313 return emitError(unknownLoc,
"OpConstantOperation must have type <id>, " 1314 "result <id>, and operand opcode");
1316 uint32_t resultTypeID = operands[0];
1318 if (!getType(resultTypeID))
1319 return emitError(unknownLoc,
"undefined result type from <id> ")
1322 uint32_t resultID = operands[1];
1323 spirv::Opcode enclosedOpcode =
static_cast<spirv::Opcode
>(operands[2]);
1324 auto emplaceResult = specConstOperationMap.try_emplace(
1327 enclosedOpcode, resultTypeID,
1330 if (!emplaceResult.second)
1331 return emitError(unknownLoc,
"value with <id>: ")
1332 << resultID <<
" is probably defined before.";
1337 Value spirv::Deserializer::materializeSpecConstantOperation(
1338 uint32_t resultID, spirv::Opcode enclosedOpcode, uint32_t resultTypeID,
1341 Type resultType = getType(resultTypeID);
1354 llvm::SaveAndRestore<DenseMap<uint32_t, Value>> valueMapGuard(valueMap,
1356 constexpr uint32_t fakeID =
static_cast<uint32_t
>(-3);
1359 enclosedOpResultTypeAndOperands.push_back(resultTypeID);
1360 enclosedOpResultTypeAndOperands.push_back(fakeID);
1361 enclosedOpResultTypeAndOperands.append(enclosedOpOperands.begin(),
1362 enclosedOpOperands.end());
1369 processInstruction(enclosedOpcode, enclosedOpResultTypeAndOperands)))
1376 auto loc = createFileLineColLoc(opBuilder);
1377 auto specConstOperationOp =
1378 opBuilder.create<spirv::SpecConstantOperationOp>(loc, resultType);
1380 Region &body = specConstOperationOp.body();
1382 body.
getBlocks().splice(body.end(), curBlock->getParent()->getBlocks(),
1389 opBuilder.setInsertionPointToEnd(&block);
1391 opBuilder.create<spirv::YieldOp>(loc, block.
front().
getResult(0));
1392 return specConstOperationOp.getResult();
1397 if (operands.size() != 2) {
1399 "OpConstantNull must have type <id> and result <id>");
1402 Type resultType = getType(operands[0]);
1404 return emitError(unknownLoc,
"undefined result type from <id> ")
1408 auto resultID = operands[1];
1410 auto attr = opBuilder.getZeroAttr(resultType);
1413 constantMap.try_emplace(resultID, attr, resultType);
1417 return emitError(unknownLoc,
"unsupported OpConstantNull type: ")
1425 Block *spirv::Deserializer::getOrCreateBlock(uint32_t
id) {
1426 if (
auto *block = getBlock(
id)) {
1427 LLVM_DEBUG(logger.startLine() <<
"[block] got exiting block for id = " <<
id 1428 <<
" @ " << block <<
"\n");
1435 auto *block = curFunction->addBlock();
1436 LLVM_DEBUG(logger.startLine() <<
"[block] created block for id = " <<
id 1437 <<
" @ " << block <<
"\n");
1438 return blockMap[id] = block;
1443 return emitError(unknownLoc,
"OpBranch must appear inside a block");
1446 if (operands.size() != 1) {
1447 return emitError(unknownLoc,
"OpBranch must take exactly one target label");
1450 auto *target = getOrCreateBlock(operands[0]);
1451 auto loc = createFileLineColLoc(opBuilder);
1455 opBuilder.create<spirv::BranchOp>(loc, target);
1465 "OpBranchConditional must appear inside a block");
1468 if (operands.size() != 3 && operands.size() != 5) {
1470 "OpBranchConditional must have condition, true label, " 1471 "false label, and optionally two branch weights");
1474 auto condition = getValue(operands[0]);
1475 auto *trueBlock = getOrCreateBlock(operands[1]);
1476 auto *falseBlock = getOrCreateBlock(operands[2]);
1479 if (operands.size() == 5) {
1480 weights = std::make_pair(operands[3], operands[4]);
1485 auto loc = createFileLineColLoc(opBuilder);
1486 opBuilder.create<spirv::BranchConditionalOp>(
1487 loc, condition, trueBlock,
1497 return emitError(unknownLoc,
"OpLabel must appear inside a function");
1500 if (operands.size() != 1) {
1501 return emitError(unknownLoc,
"OpLabel should only have result <id>");
1504 auto labelID = operands[0];
1506 auto *block = getOrCreateBlock(labelID);
1507 LLVM_DEBUG(logger.startLine()
1508 <<
"[block] populating block " << block <<
"\n");
1510 assert(block->empty() &&
"re-deserialize the same block!");
1512 opBuilder.setInsertionPointToStart(block);
1513 blockMap[labelID] = curBlock = block;
1521 return emitError(unknownLoc,
"OpSelectionMerge must appear in a block");
1524 if (operands.size() < 2) {
1527 "OpSelectionMerge must specify merge target and selection control");
1530 auto *mergeBlock = getOrCreateBlock(operands[0]);
1531 auto loc = createFileLineColLoc(opBuilder);
1532 auto selectionControl = operands[1];
1534 if (!blockMergeInfo.try_emplace(curBlock, loc, selectionControl, mergeBlock)
1538 "a block cannot have more than one OpSelectionMerge instruction");
1547 return emitError(unknownLoc,
"OpLoopMerge must appear in a block");
1550 if (operands.size() < 3) {
1551 return emitError(unknownLoc,
"OpLoopMerge must specify merge target, " 1552 "continue target and loop control");
1555 auto *mergeBlock = getOrCreateBlock(operands[0]);
1556 auto *continueBlock = getOrCreateBlock(operands[1]);
1557 auto loc = createFileLineColLoc(opBuilder);
1558 uint32_t loopControl = operands[2];
1561 .try_emplace(curBlock, loc, loopControl, mergeBlock, continueBlock)
1565 "a block cannot have more than one OpLoopMerge instruction");
1573 return emitError(unknownLoc,
"OpPhi must appear in a block");
1576 if (operands.size() < 4) {
1577 return emitError(unknownLoc,
"OpPhi must specify result type, result <id>, " 1578 "and variable-parent pairs");
1582 Type blockArgType = getType(operands[0]);
1583 BlockArgument blockArg = curBlock->addArgument(blockArgType, unknownLoc);
1584 valueMap[operands[1]] = blockArg;
1585 LLVM_DEBUG(logger.startLine()
1586 <<
"[phi] created block argument " << blockArg
1587 <<
" id = " << operands[1] <<
" of type " << blockArgType <<
"\n");
1591 for (
unsigned i = 2, e = operands.size(); i < e; i += 2) {
1592 uint32_t
value = operands[i];
1593 Block *predecessor = getOrCreateBlock(operands[i + 1]);
1594 std::pair<Block *, Block *> predecessorTargetPair{predecessor, curBlock};
1595 blockPhiInfo[predecessorTargetPair].
push_back(value);
1596 LLVM_DEBUG(logger.startLine() <<
"[phi] predecessor @ " << predecessor
1597 <<
" with arg id = " << value <<
"\n");
1606 class ControlFlowStructurizer {
1609 ControlFlowStructurizer(
Location loc, uint32_t control,
1612 llvm::ScopedPrinter &logger)
1613 : location(loc), control(control), blockMergeInfo(mergeInfo),
1614 headerBlock(header), mergeBlock(merge), continueBlock(cont),
1617 ControlFlowStructurizer(
Location loc, uint32_t control,
1620 : location(loc), control(control), blockMergeInfo(mergeInfo),
1621 headerBlock(header), mergeBlock(merge), continueBlock(cont) {}
1635 spirv::SelectionOp createSelectionOp(uint32_t selectionControl);
1638 spirv::LoopOp createLoopOp(uint32_t loopControl);
1641 void collectBlocksInConstruct();
1650 Block *continueBlock;
1656 llvm::ScopedPrinter &logger;
1662 ControlFlowStructurizer::createSelectionOp(uint32_t selectionControl) {
1665 OpBuilder builder(&mergeBlock->front());
1667 auto control =
static_cast<spirv::SelectionControl
>(selectionControl);
1668 auto selectionOp = builder.
create<spirv::SelectionOp>(location, control);
1669 selectionOp.addMergeBlock();
1674 spirv::LoopOp ControlFlowStructurizer::createLoopOp(uint32_t loopControl) {
1677 OpBuilder builder(&mergeBlock->front());
1679 auto control =
static_cast<spirv::LoopControl
>(loopControl);
1680 auto loopOp = builder.
create<spirv::LoopOp>(location, control);
1681 loopOp.addEntryAndMergeBlock();
1686 void ControlFlowStructurizer::collectBlocksInConstruct() {
1687 assert(constructBlocks.empty() &&
"expected empty constructBlocks");
1690 constructBlocks.insert(headerBlock);
1694 for (
unsigned i = 0; i < constructBlocks.size(); ++i) {
1695 for (
auto *successor : constructBlocks[i]->getSuccessors())
1696 if (successor != mergeBlock)
1697 constructBlocks.insert(successor);
1703 bool isLoop = continueBlock !=
nullptr;
1705 if (
auto loopOp = createLoopOp(control))
1706 op = loopOp.getOperation();
1708 if (
auto selectionOp = createSelectionOp(control))
1709 op = selectionOp.getOperation();
1718 mapper.
map(mergeBlock, &body.
back());
1720 collectBlocksInConstruct();
1742 for (
auto *block : constructBlocks) {
1746 mapper.
map(block, newBlock);
1747 LLVM_DEBUG(logger.startLine() <<
"[cf] cloned block " << newBlock
1748 <<
" from block " << block <<
"\n");
1752 newBlock->addArgument(blockArg.getType(), blockArg.getLoc());
1753 mapper.
map(blockArg, newArg);
1754 LLVM_DEBUG(logger.startLine() <<
"[cf] remapped block argument " 1755 << blockArg <<
" to " << newArg <<
"\n");
1758 LLVM_DEBUG(logger.startLine()
1759 <<
"[cf] block " << block <<
" is a function entry block\n");
1762 for (
auto &op : *block)
1763 newBlock->push_back(op.
clone(mapper));
1767 auto remapOperands = [&](
Operation *op) {
1770 operand.set(mappedOp);
1773 succOp.set(mappedOp);
1775 for (
auto &block : body)
1776 block.walk(remapOperands);
1784 headerBlock->replaceAllUsesWith(mergeBlock);
1787 logger.startLine() <<
"[cf] after cloning and fixing references:\n";
1788 headerBlock->getParentOp()->print(logger.getOStream());
1789 logger.startLine() <<
"\n";
1793 if (!mergeBlock->args_empty()) {
1794 return mergeBlock->getParentOp()->emitError(
1795 "OpPhi in loop merge block unsupported");
1802 mergeBlock->addArgument(blockArg.getType(), blockArg.getLoc());
1807 if (!headerBlock->args_empty())
1808 blockArgs = {mergeBlock->args_begin(), mergeBlock->args_end()};
1819 LLVM_DEBUG(logger.startLine() <<
"[cf] cleaning up blocks after clone\n");
1822 for (
auto *block : constructBlocks)
1823 block->dropAllReferences();
1830 for (
auto *block : constructBlocks) {
1834 "failed control flow structurization: it has uses outside of the " 1835 "enclosing selection/loop construct");
1839 for (
auto *block : constructBlocks) {
1848 auto it = blockMergeInfo.find(block);
1849 if (it != blockMergeInfo.end()) {
1855 return emitError(loc,
"failed control flow structurization: nested " 1856 "loop header block should be remapped!");
1858 Block *newContinue = it->second.continueBlock;
1862 return emitError(loc,
"failed control flow structurization: nested " 1863 "loop continue block should be remapped!");
1866 Block *newMerge = it->second.mergeBlock;
1868 newMerge = mappedTo;
1872 blockMergeInfo.
erase(it);
1873 blockMergeInfo.try_emplace(newHeader, loc, it->second.control, newMerge,
1882 LLVM_DEBUG(logger.startLine() <<
"[cf] changing entry block " << block
1883 <<
" to only contain a spv.Branch op\n");
1888 builder.
create<spirv::BranchOp>(location, mergeBlock);
1890 LLVM_DEBUG(logger.startLine() <<
"[cf] erasing block " << block <<
"\n");
1895 LLVM_DEBUG(logger.startLine()
1896 <<
"[cf] after structurizing construct with header block " 1897 << headerBlock <<
":\n" 1906 <<
"//----- [phi] start wiring up block arguments -----//\n";
1912 for (
const auto &info : blockPhiInfo) {
1913 Block *block = info.first.first;
1914 Block *target = info.first.second;
1917 logger.startLine() <<
"[phi] block " << block <<
"\n";
1918 logger.startLine() <<
"[phi] before creating block argument:\n";
1920 logger.startLine() <<
"\n";
1926 opBuilder.setInsertionPoint(op);
1929 blockArgs.reserve(phiInfo.size());
1930 for (uint32_t valueId : phiInfo) {
1932 blockArgs.push_back(
value);
1933 LLVM_DEBUG(logger.startLine() <<
"[phi] block argument " <<
value 1934 <<
" id = " << valueId <<
"\n");
1936 return emitError(unknownLoc,
"OpPhi references undefined value!");
1940 if (
auto branchOp = dyn_cast<spirv::BranchOp>(op)) {
1942 opBuilder.create<spirv::BranchOp>(branchOp.getLoc(), branchOp.getTarget(),
1945 }
else if (
auto branchCondOp = dyn_cast<spirv::BranchConditionalOp>(op)) {
1946 assert((branchCondOp.getTrueBlock() == target ||
1947 branchCondOp.getFalseBlock() == target) &&
1948 "expected target to be either the true or false target");
1949 if (target == branchCondOp.trueTarget())
1950 opBuilder.create<spirv::BranchConditionalOp>(
1951 branchCondOp.getLoc(), branchCondOp.condition(), blockArgs,
1952 branchCondOp.getFalseBlockArguments(),
1953 branchCondOp.branch_weightsAttr(), branchCondOp.trueTarget(),
1954 branchCondOp.falseTarget());
1956 opBuilder.create<spirv::BranchConditionalOp>(
1957 branchCondOp.getLoc(), branchCondOp.condition(),
1958 branchCondOp.getTrueBlockArguments(), blockArgs,
1959 branchCondOp.branch_weightsAttr(), branchCondOp.getTrueBlock(),
1960 branchCondOp.getFalseBlock());
1962 branchCondOp.erase();
1964 return emitError(unknownLoc,
"unimplemented terminator for Phi creation");
1968 logger.startLine() <<
"[phi] after creating block argument:\n";
1970 logger.startLine() <<
"\n";
1973 blockPhiInfo.clear();
1978 <<
"//--- [phi] completed wiring up block arguments ---//\n";
1983 LogicalResult spirv::Deserializer::structurizeControlFlow() {
1986 <<
"//----- [cf] start structurizing control flow -----//\n";
1990 while (!blockMergeInfo.empty()) {
1991 Block *headerBlock = blockMergeInfo.
begin()->first;
1995 logger.startLine() <<
"[cf] header block " << headerBlock <<
":\n";
1996 headerBlock->
print(logger.getOStream());
1997 logger.startLine() <<
"\n";
2001 assert(mergeBlock &&
"merge block cannot be nullptr");
2002 if (!mergeBlock->args_empty())
2003 return emitError(unknownLoc,
"OpPhi in loop merge block unimplemented");
2005 logger.startLine() <<
"[cf] merge block " << mergeBlock <<
":\n";
2006 mergeBlock->print(logger.getOStream());
2007 logger.startLine() <<
"\n";
2011 LLVM_DEBUG(
if (continueBlock) {
2012 logger.startLine() <<
"[cf] continue block " << continueBlock <<
":\n";
2013 continueBlock->print(logger.getOStream());
2014 logger.startLine() <<
"\n";
2018 blockMergeInfo.
erase(blockMergeInfo.begin());
2019 ControlFlowStructurizer structurizer(mergeInfo.
loc, mergeInfo.
control,
2020 blockMergeInfo, headerBlock,
2021 mergeBlock, continueBlock
2027 if (
failed(structurizer.structurize()))
2034 <<
"//--- [cf] completed structurizing control flow ---//\n";
2047 auto fileName = debugInfoMap.lookup(debugLine->fileID).str();
2048 if (fileName.empty())
2049 fileName =
"<unknown>";
2050 return FileLineColLoc::get(opBuilder.
getStringAttr(fileName), debugLine->line,
2061 if (operands.size() != 3)
2062 return emitError(unknownLoc,
"OpLine must have 3 operands");
2063 debugLine =
DebugLine{operands[0], operands[1], operands[2]};
2067 void spirv::Deserializer::clearDebugLine() { debugLine = llvm::None; }
2071 if (operands.size() < 2)
2072 return emitError(unknownLoc,
"OpString needs at least 2 operands");
2074 if (!debugInfoMap.lookup(operands[0]).empty())
2076 "duplicate debug string found for result <id> ")
2079 unsigned wordIndex = 1;
2081 if (wordIndex != operands.size())
2083 "unexpected trailing words in OpString instruction");
TODO: Remove this file when SCCP and integer range analysis have been ported to the new framework...
static Operation * create(Location location, OperationName name, TypeRange resultTypes, ValueRange operands, ArrayRef< NamedAttribute > attributes, BlockRange successors, unsigned numRegions)
Create a new Operation with the specific fields.
static bool isFnEntryBlock(Block *block)
Returns true if the given block is a function entry block.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Operation is a basic unit of execution within MLIR.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
BlockListType & getBlocks()
Block represents an ordered list of Operations.
A symbol reference with a reference path containing a single element.
LogicalResult deserialize()
Deserializes the remembered SPIR-V binary module.
constexpr unsigned kHeaderWordCount
SPIR-V binary header word count.
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
static DenseElementsAttr get(ShapedType type, ArrayRef< Attribute > values)
Constructs a dense elements attribute from an array of element values.
BlockListType::iterator iterator
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
static RuntimeArrayType get(Type elementType)
static constexpr const bool value
void erase()
Remove this operation from its parent block and delete it.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
void map(Block *from, Block *to)
Inserts a new mapping for 'from' to 'to'.
static StructType get(ArrayRef< Type > memberTypes, ArrayRef< OffsetInfo > offsetInfo={}, ArrayRef< MemberDecorationInfo > memberDecorations={})
Construct a literal StructType with at least one member.
MutableArrayRef< OpOperand > getOpOperands()
IntegerAttr getI32IntegerAttr(int32_t value)
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
void erase()
Unlink this Block from its parent region and delete it.
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
static SampledImageType get(Type imageType)
This class represents an efficient way to signal success or failure.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
static CooperativeMatrixNVType get(Type elementType, Scope scope, unsigned rows, unsigned columns)
static ArrayType get(Type elementType, unsigned elementCount)
A struct for containing OpLine instruction information.
Operation * clone(BlockAndValueMapping &mapper, CloneOptions options=CloneOptions::all())
Create a deep copy of this operation, remapping any operands that use values outside of the operation...
Block * lookupOrNull(Block *from) const
Lookup a mapped value within the map.
Attributes are known-constant values of operations.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
bool isEntryBlock()
Return if this block is the entry block in the parent region.
This represents an operation in an abstracted form, suitable for use with the builder APIs...
MutableArrayRef< BlockOperand > getBlockOperands()
static StructType getEmpty(MLIRContext *context, StringRef identifier="")
Construct a (possibly identified) StructType with no members.
This class represents an argument of a Block.
void print(raw_ostream &os, const OpPrintingFlags &flags=llvm::None)
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
static PointerType get(Type pointeeType, StorageClass storageClass)
bool use_empty()
Returns true if this operation has no uses.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
constexpr uint32_t kMagicNumber
SPIR-V magic number.
Operation * getTerminator()
Get the terminator operation of this block.
RAII guard to reset the insertion point of the builder when destroyed.
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
void push_back(Operation *op)
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 VectorType vectorType(CodeGen &codegen, Type etp)
Constructs vector type.
StringRef decodeStringLiteral(ArrayRef< uint32_t > words, unsigned &wordIndex)
Decodes a string literal in words starting at wordIndex.
static std::string debugString(T &&op)
MLIRContext is the top-level object for a collection of MLIR operations.
Deserializer(ArrayRef< uint32_t > binary, MLIRContext *context)
Creates a deserializer for the given SPIR-V binary module.
static VerCapExtAttr get(Version version, ArrayRef< Capability > capabilities, ArrayRef< Extension > extensions, MLIRContext *context)
Gets a VerCapExtAttr instance.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
#define MIN_VERSION_CASE(v)
A struct for containing a header block's merge and continue targets.
static MatrixType get(Type columnType, uint32_t columnCount)
static StructType getIdentified(MLIRContext *context, StringRef identifier)
Construct an identified StructType.
Block * createBlock(Region *parent, Region::iterator insertPt={}, TypeRange argTypes=llvm::None, ArrayRef< Location > locs=llvm::None)
Add new block with 'argTypes' arguments and set the insertion point to the end of it...
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers...
void print(raw_ostream &os)
A struct that collects the info needed to materialize/emit a SpecConstantOperation op...
This class helps build Operations.
StringAttr getStringAttr(const Twine &bytes)
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Block * splitBlock(iterator splitBefore)
Split the block into two blocks before the specified operation or iterator.