21#include "llvm/ADT/StringExtras.h"
22#include "llvm/Support/Casting.h"
34template <
typename MemoryOpTy>
43 spirv::MemoryAccess memoryAccessAttr;
44 StringAttr memoryAccessAttrName =
45 MemoryOpTy::getMemoryAccessAttrName(state.
name);
47 memoryAccessAttr, parser, state, memoryAccessAttrName))
50 if (spirv::bitEnumContainsAll(memoryAccessAttr,
51 spirv::MemoryAccess::Aligned)) {
54 StringAttr alignmentAttrName = MemoryOpTy::getAlignmentAttrName(state.
name);
69template <
typename MemoryOpTy>
78 spirv::MemoryAccess memoryAccessAttr;
79 StringRef memoryAccessAttrName =
80 MemoryOpTy::getSourceMemoryAccessAttrName(state.
name);
82 memoryAccessAttr, parser, state, memoryAccessAttrName))
85 if (spirv::bitEnumContainsAll(memoryAccessAttr,
86 spirv::MemoryAccess::Aligned)) {
89 StringAttr alignmentAttrName =
90 MemoryOpTy::getSourceAlignmentAttrName(state.
name);
105template <
typename MemoryOpTy>
109 std::optional<spirv::MemoryAccess> memoryAccessAtrrValue = std::nullopt,
110 std::optional<uint32_t> alignmentAttrValue = std::nullopt) {
115 if (
auto memAccess = (memoryAccessAtrrValue ? memoryAccessAtrrValue
116 : memoryOp.getMemoryAccess())) {
117 elidedAttrs.push_back(memoryOp.getSourceMemoryAccessAttrName());
119 printer <<
" [\"" << stringifyMemoryAccess(*memAccess) <<
"\"";
121 if (spirv::bitEnumContainsAll(*memAccess, spirv::MemoryAccess::Aligned)) {
123 if (
auto alignment = (alignmentAttrValue ? alignmentAttrValue
124 : memoryOp.getAlignment())) {
125 elidedAttrs.push_back(memoryOp.getSourceAlignmentAttrName());
126 printer <<
", " << *alignment;
131 elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
134template <
typename MemoryOpTy>
138 std::optional<spirv::MemoryAccess> memoryAccessAtrrValue = std::nullopt,
139 std::optional<uint32_t> alignmentAttrValue = std::nullopt) {
141 if (
auto memAccess = (memoryAccessAtrrValue ? memoryAccessAtrrValue
142 : memoryOp.getMemoryAccess())) {
143 elidedAttrs.push_back(memoryOp.getMemoryAccessAttrName());
145 printer <<
" [\"" << stringifyMemoryAccess(*memAccess) <<
"\"";
147 if (spirv::bitEnumContainsAll(*memAccess, spirv::MemoryAccess::Aligned)) {
149 if (
auto alignment = (alignmentAttrValue ? alignmentAttrValue
150 : memoryOp.getAlignment())) {
151 elidedAttrs.push_back(memoryOp.getAlignmentAttrName());
152 printer <<
", " << *alignment;
157 elidedAttrs.push_back(spirv::attributeName<spirv::StorageClass>());
160template <
typename LoadStoreOpTy>
169 cast<spirv::PointerType>(
ptr.getType()).getPointeeType()) {
170 return op.emitOpError(
"mismatch in result type and pointer type");
175template <
typename MemoryOpTy>
180 spirv::MemoryAccessAttr memAccessAttr = memoryOp.getMemoryAccessAttr();
181 if (!memAccessAttr) {
184 if (memoryOp.getAlignmentAttr()) {
185 return memoryOp.emitOpError(
186 "invalid alignment specification without aligned memory access "
192 spirv::MemoryAccessAttr memAccess = memAccessAttr;
195 return memoryOp.emitOpError(
"invalid memory access specifier: ")
199 if (spirv::bitEnumContainsAll(memAccess.getValue(),
200 spirv::MemoryAccess::Aligned)) {
201 if (!memoryOp.getAlignmentAttr()) {
202 return memoryOp.emitOpError(
"missing alignment value");
205 if (memoryOp.getAlignmentAttr()) {
206 return memoryOp.emitOpError(
207 "invalid alignment specification with non-aligned memory access "
218template <
typename MemoryOpTy>
223 spirv::MemoryAccessAttr memAccessAttr = memoryOp.getSourceMemoryAccessAttr();
224 if (!memAccessAttr) {
227 if (memoryOp.getSourceAlignmentAttr()) {
228 return memoryOp.emitOpError(
229 "invalid alignment specification without aligned memory access "
235 spirv::MemoryAccessAttr memAccess = memAccessAttr;
238 return memoryOp.emitOpError(
"invalid memory access specifier: ")
242 if (spirv::bitEnumContainsAll(memAccess.getValue(),
243 spirv::MemoryAccess::Aligned)) {
244 if (!memoryOp.getSourceAlignmentAttr()) {
245 return memoryOp.emitOpError(
"missing alignment value");
248 if (memoryOp.getSourceAlignmentAttr()) {
249 return memoryOp.emitOpError(
250 "invalid alignment specification with non-aligned memory access "
262 auto ptrType = dyn_cast<spirv::PointerType>(type);
264 emitError(baseLoc,
"'spirv.AccessChain' op expected a pointer "
265 "to composite type, but provided ")
270 auto resultType = ptrType.getPointeeType();
271 auto resultStorageClass = ptrType.getStorageClass();
274 for (
auto indexSSA :
indices) {
275 auto cType = dyn_cast<spirv::CompositeType>(resultType);
279 "'spirv.AccessChain' op cannot extract from non-composite type ")
280 << resultType <<
" with index " <<
index;
284 if (isa<spirv::StructType>(resultType)) {
285 Operation *op = indexSSA.getDefiningOp();
287 emitError(baseLoc,
"'spirv.AccessChain' op index must be an "
288 "integer spirv.Constant to access "
289 "element of spirv.struct");
298 "'spirv.AccessChain' index must be an integer spirv.Constant to "
299 "access element of spirv.struct, but provided ")
303 if (
index < 0 ||
static_cast<uint64_t
>(
index) >= cType.getNumElements()) {
304 emitError(baseLoc,
"'spirv.AccessChain' op index ")
305 <<
index <<
" out of bounds for " << resultType;
309 resultType = cType.getElementType(
index);
317 assert(type &&
"Unable to deduce return type based on basePtr and indices");
318 build(builder, state, type, basePtr,
indices);
321template <
typename Op>
323 printer <<
' ' << op.getBasePtr() <<
'[' <<
indices
324 <<
"] : " << op.getBasePtr().getType() <<
", " <<
indices.getTypes();
327template <
typename Op>
334 auto providedResultType =
335 dyn_cast<spirv::PointerType>(accessChainOp.getType());
336 if (!providedResultType)
338 "result type must be a pointer, but provided")
339 << providedResultType;
341 if (resultType != providedResultType)
342 return accessChainOp.
emitOpError(
"invalid result type: expected ")
343 << resultType <<
", but provided " << providedResultType;
348LogicalResult AccessChainOp::verify() {
359 assert(type &&
"Unable to deduce return type based on basePtr and indices");
360 build(builder, state, type, basePtr,
indices);
363LogicalResult InBoundsAccessChainOp::verify() {
371void LoadOp::build(OpBuilder &builder, OperationState &state, Value basePtr,
372 MemoryAccessAttr memoryAccess, IntegerAttr alignment) {
373 auto ptrType = cast<spirv::PointerType>(basePtr.
getType());
374 build(builder, state, ptrType.getPointeeType(), basePtr, memoryAccess,
378ParseResult LoadOp::parse(OpAsmParser &parser, OperationState &
result) {
380 spirv::StorageClass storageClass;
381 OpAsmParser::UnresolvedOperand ptrInfo;
395 result.addTypes(elementType);
399void LoadOp::print(OpAsmPrinter &printer) {
400 SmallVector<StringRef, 4> elidedAttrs;
401 StringRef sc = stringifyStorageClass(
402 cast<spirv::PointerType>(getPtr().
getType()).getStorageClass());
403 printer <<
" \"" << sc <<
"\" " << getPtr();
408 (*this)->getDiscardableAttrDictionary().getValue(), elidedAttrs);
412LogicalResult LoadOp::verify() {
426ParseResult StoreOp::parse(OpAsmParser &parser, OperationState &
result) {
428 spirv::StorageClass storageClass;
429 SmallVector<OpAsmParser::UnresolvedOperand, 2> operandInfo;
447void StoreOp::print(OpAsmPrinter &printer) {
448 SmallVector<StringRef, 4> elidedAttrs;
449 StringRef sc = stringifyStorageClass(
450 cast<spirv::PointerType>(getPtr().
getType()).getStorageClass());
451 printer <<
" \"" << sc <<
"\" " << getPtr() <<
", " << getValue();
455 printer <<
" : " << getValue().getType();
457 (*this)->getDiscardableAttrDictionary().getValue(), elidedAttrs);
460LogicalResult StoreOp::verify() {
472void CopyMemoryOp::print(OpAsmPrinter &printer) {
475 StringRef targetStorageClass = stringifyStorageClass(
476 cast<spirv::PointerType>(getTarget().
getType()).getStorageClass());
477 printer <<
" \"" << targetStorageClass <<
"\" " << getTarget() <<
", ";
479 StringRef sourceStorageClass = stringifyStorageClass(
480 cast<spirv::PointerType>(getSource().
getType()).getStorageClass());
481 printer <<
" \"" << sourceStorageClass <<
"\" " << getSource();
483 SmallVector<StringRef, 4> elidedAttrs;
486 getSourceMemoryAccess(),
487 getSourceAlignment());
490 (*this)->getDiscardableAttrDictionary().getValue(), elidedAttrs);
493 cast<spirv::PointerType>(getTarget().
getType()).getPointeeType();
494 printer <<
" : " << pointeeType;
497ParseResult CopyMemoryOp::parse(OpAsmParser &parser, OperationState &
result) {
498 spirv::StorageClass targetStorageClass;
499 OpAsmParser::UnresolvedOperand targetPtrInfo;
501 spirv::StorageClass sourceStorageClass;
502 OpAsmParser::UnresolvedOperand sourcePtrInfo;
538LogicalResult CopyMemoryOp::verify() {
540 cast<spirv::PointerType>(getTarget().
getType()).getPointeeType();
543 cast<spirv::PointerType>(getSource().
getType()).getPointeeType();
545 if (targetType != sourceType)
546 return emitOpError(
"both operands must be pointers to the same type");
566void InBoundsPtrAccessChainOp::build(OpBuilder &builder, OperationState &state,
567 Value basePtr, Value element,
570 assert(type &&
"Unable to deduce return type based on basePtr and indices");
571 build(builder, state, type, basePtr, element,
indices);
574LogicalResult InBoundsPtrAccessChainOp::verify() {
582void PtrAccessChainOp::build(OpBuilder &builder, OperationState &state,
585 assert(type &&
"Unable to deduce return type based on basePtr and indices");
586 build(builder, state, type, basePtr, element,
indices);
589LogicalResult PtrAccessChainOp::verify() {
597ParseResult VariableOp::parse(OpAsmParser &parser, OperationState &
result) {
599 std::optional<OpAsmParser::UnresolvedOperand> initInfo;
601 initInfo = OpAsmParser::UnresolvedOperand();
619 auto ptrType = dyn_cast<spirv::PointerType>(type);
621 return parser.
emitError(loc,
"expected spirv.ptr type");
632 ptrType.getStorageClass());
633 result.addAttribute(spirv::attributeName<spirv::StorageClass>(), attr);
638void VariableOp::print(OpAsmPrinter &printer) {
639 SmallVector<StringRef, 4> elidedAttrs{
640 spirv::attributeName<spirv::StorageClass>()};
643 printer <<
" init(" << getInitializer() <<
")";
649LogicalResult VariableOp::verify() {
653 if (getStorageClass() != spirv::StorageClass::Function) {
655 "can only be used to model function-level variables. Use "
656 "spirv.GlobalVariable for module-level variables.");
659 auto pointerType = cast<spirv::PointerType>(getPointer().
getType());
660 if (getStorageClass() != pointerType.getStorageClass())
662 "storage class must match result pointer's storage class");
667 auto *initOp = getOperand(0).getDefiningOp();
668 if (!initOp || !isa<spirv::ConstantOp,
669 spirv::ReferenceOfOp,
670 spirv::AddressOfOp>(initOp))
671 return emitOpError(
"initializer must be the result of a "
672 "constant or spirv.GlobalVariable op");
675 auto getDecorationAttr = [op = getOperation()](spirv::Decoration decoration) {
680 for (
auto decoration :
681 {spirv::Decoration::DescriptorSet, spirv::Decoration::Binding,
682 spirv::Decoration::BuiltIn}) {
683 if (
auto attr = getDecorationAttr(decoration))
684 return emitOpError(
"cannot have '")
686 <<
"' attribute (only allowed in spirv.GlobalVariable)";
getNumOperands() - 1))) return failure()
Given a list of lists of parsed operands, populates uniqueOperands with unique operands.
virtual Builder & getBuilder() const =0
Return a builder which provides useful access to MLIRContext, global objects like types and attribute...
virtual ParseResult parseOptionalAttrDict(NamedAttrList &result)=0
Parse a named dictionary into 'result' if it is present.
virtual ParseResult parseOptionalKeyword(StringRef keyword)=0
Parse the given keyword if present.
virtual ParseResult parseRParen()=0
Parse a ) token.
virtual InFlightDiagnostic emitError(SMLoc loc, const Twine &message={})=0
Emit a diagnostic at the specified location and return failure.
virtual ParseResult parseRSquare()=0
Parse a ] token.
virtual SMLoc getCurrentLocation()=0
Get the location of the next token and store it into the argument.
virtual ParseResult parseOptionalComma()=0
Parse a , token if present.
virtual ParseResult parseColon()=0
Parse a : token.
virtual ParseResult parseLParen()=0
Parse a ( token.
virtual ParseResult parseType(Type &result)=0
Parse a type.
virtual ParseResult parseComma()=0
Parse a , token.
virtual ParseResult parseOptionalLSquare()=0
Parse a [ token if present.
virtual ParseResult parseAttribute(Attribute &result, Type type={})=0
Parse an arbitrary attribute of a given type and return it in result.
Attributes are known-constant values of operations.
IntegerType getIntegerType(unsigned width)
Attr getAttr(Args &&...args)
Get or construct an instance of the attribute Attr with provided arguments.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
virtual ParseResult resolveOperand(const UnresolvedOperand &operand, Type type, SmallVectorImpl< Value > &result)=0
Resolve an operand to an SSA value, emitting an error on failure.
ParseResult resolveOperands(Operands &&operands, Type type, SmallVectorImpl< Value > &result)
Resolve a list of operands to SSA values, emitting an error on failure, or appending the results to t...
virtual ParseResult parseOperand(UnresolvedOperand &result, bool allowResultNumber=true)=0
Parse a single SSA value operand name along with a result number if allowResultNumber is true.
virtual ParseResult parseOperandList(SmallVectorImpl< UnresolvedOperand > &result, Delimiter delimiter=Delimiter::None, bool allowResultNumber=true, int requiredOperandCount=-1)=0
Parse zero or more SSA comma-separated operand references with a specified surrounding delimiter,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
virtual void printOptionalAttrDict(ArrayRef< NamedAttribute > attrs, ArrayRef< StringRef > elidedAttrs={})=0
If the specified operation has attributes, print out an attribute dictionary with their values.
This class helps build Operations.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
Operation is the basic unit of execution within MLIR.
OperationName getName()
The name of an operation is the key identifier for it.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
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.
static PointerType get(Type pointeeType, StorageClass storageClass)
Operation::operand_range getIndices(Operation *op)
Get the indices that the given load/store operation is operating on.
static ParseResult parseSourceMemoryAccessAttributes(OpAsmParser &parser, OperationState &state)
ParseResult parseEnumStrAttr(EnumClass &value, OpAsmParser &parser, StringRef attrName=spirv::attributeName< EnumClass >())
Parses the next string attribute in parser as an enumerant of the given EnumClass.
static LogicalResult verifySourceMemoryAccessAttribute(MemoryOpTy memoryOp)
static void printSourceMemoryAccessAttribute(MemoryOpTy memoryOp, OpAsmPrinter &printer, SmallVectorImpl< StringRef > &elidedAttrs, std::optional< spirv::MemoryAccess > memoryAccessAtrrValue=std::nullopt, std::optional< uint32_t > alignmentAttrValue=std::nullopt)
ParseResult parseMemoryAccessAttributes(OpAsmParser &parser, OperationState &state)
Parses optional memory access (a.k.a.
static Type getElementPtrType(Type type, ValueRange indices, Location baseLoc)
void printVariableDecorations(Operation *op, OpAsmPrinter &printer, SmallVectorImpl< StringRef > &elidedAttrs)
LogicalResult verifyPhysicalStorageBufferDecorations(Operation *op, Type pointeeType)
Verifies the SPV_KHR_physical_storage_buffer rule that a variable whose pointee is a pointer (or arra...
static LogicalResult verifyLoadStorePtrAndValTypes(LoadStoreOpTy op, Value ptr, Value val)
static LogicalResult verifyMemoryAccessAttribute(MemoryOpTy memoryOp)
static void printAccessChain(Op op, ValueRange indices, OpAsmPrinter &printer)
static void printMemoryAccessAttribute(MemoryOpTy memoryOp, OpAsmPrinter &printer, SmallVectorImpl< StringRef > &elidedAttrs, std::optional< spirv::MemoryAccess > memoryAccessAtrrValue=std::nullopt, std::optional< uint32_t > alignmentAttrValue=std::nullopt)
LogicalResult extractValueFromConstOp(Operation *op, int32_t &value)
std::string getDecorationString(Decoration decoration)
Converts a SPIR-V Decoration enum value to its snake_case string representation for use in MLIR attri...
ParseResult parseVariableDecorations(OpAsmParser &parser, OperationState &state)
static LogicalResult verifyAccessChain(Op accessChainOp, ValueRange indices)
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.
This represents an operation in an abstracted form, suitable for use with the builder APIs.