Traits
traits
¶
OpTraitInvT = TypeVar('OpTraitInvT', bound=OpTrait)
module-attribute
¶
OpTrait
dataclass
¶
A trait attached to an operation definition. Traits can be used to define operation invariants, additional semantic information, or to group operations that have similar properties. Note that traits are the merge of traits and interfaces in MLIR.
Source code in xdsl/traits.py
ConstantLike
dataclass
¶
Bases: OpTrait, ABC
Operation known to be constant-like.
To participate in constant folding and other generic mechanisms implement
HasFolder or HasFolderInterface for your operation.
See external documentation.
Source code in xdsl/traits.py
get_constant_value(ssa_value: SSAValue) -> Attribute | None
staticmethod
¶
If the value is the result of a ConstantLike operation that implements
HasFolderInterface, return the attribute returned by fold corresponding to
the value's index in the list of results.
Source code in xdsl/traits.py
HasFolder
dataclass
¶
Bases: OpTrait
Operation known to support folding.
Source code in xdsl/traits.py
fold(op: Operation) -> Sequence[SSAValue | Attribute] | None
abstractmethod
classmethod
¶
Attempts to fold the operation. The fold method cannot modify the IR. Returns either an existing SSAValue or an Attribute for each result of the operation. When folding is unsuccessful, returns None.
Source code in xdsl/traits.py
HasParent
dataclass
¶
Bases: OpTrait
Constraint the operation to have a specific parent operation.
Source code in xdsl/traits.py
op_types: tuple[type[Operation], ...]
instance-attribute
¶
__init__(head_param: type[Operation], *tail_params: type[Operation])
¶
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
HasAncestor
dataclass
¶
Bases: OpTrait
Constraint the operation to have a specific operation as ancestor, i.e. transitive parent.
Source code in xdsl/traits.py
op_types: tuple[type[Operation], ...]
instance-attribute
¶
__init__(head_param: type[Operation], *tail_params: type[Operation])
¶
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
walk_ancestors(op: Operation) -> Iterator[Operation]
¶
Iterates over the ancestors of an operation, including the input
get_ancestor(op: Operation) -> Operation | None
¶
IsTerminator
dataclass
¶
Bases: OpTrait
This trait provides verification and functionality for operations that are known to be terminators.
See external documentation.
Source code in xdsl/traits.py
verify(op: Operation) -> None
¶
Check that the operation satisfies the IsTerminator trait requirements.
Source code in xdsl/traits.py
ReturnLike
dataclass
¶
Bases: OpTrait
This trait indicates that a terminator operation is "return-like". This means that it exits its current region and forwards its operands as "exit" values to the parent region. Operations with this trait are not permitted to contain successors or produce results.
Source code in xdsl/traits.py
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
NoTerminator
dataclass
¶
Bases: OpTrait
Allow an operation to have single block regions with no terminator.
See external documentation.
Source code in xdsl/traits.py
SingleBlockImplicitTerminator
dataclass
¶
Bases: OpTrait
Checks the existence of the specified terminator to an operation which has
single-block regions.
The conditions for the implicit creation of the terminator depend on the operation
and occur during its creation using the ensure_terminator method.
This should be fully compatible with MLIR's Trait.
See external documentation.
Source code in xdsl/traits.py
op_type: type[Operation]
instance-attribute
¶
__init__(op_type: type[Operation]) -> None
¶
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
IsolatedFromAbove
dataclass
¶
Bases: OpTrait
Constrains the contained operations to use only values defined inside this operation.
This should be fully compatible with MLIR's Trait.
See external documentation.
Source code in xdsl/traits.py
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
SymbolUserOpInterface
dataclass
¶
Bases: OpTrait, ABC
Used to represent operations that reference Symbol operations. This provides the ability to perform safe and efficient verification of symbol uses, as well as additional functionality.
See external documentation.
Source code in xdsl/traits.py
verify(op: Operation) -> None
abstractmethod
¶
This method should be adapted to the requirements of specific symbol users per operation.
It corresponds to the verifySymbolUses in upstream MLIR.
Source code in xdsl/traits.py
SymbolTable
dataclass
¶
Bases: OpTrait
SymbolTable operations are containers for Symbol operations. They offer lookup functionality for Symbols, and enforce unique symbols amongst its children.
A SymbolTable operation is constrained to have a single single-block region.
Source code in xdsl/traits.py
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 | |
verify(op: Operation)
¶
Source code in xdsl/traits.py
lookup_symbol(op: Operation, name: str | StringAttr | SymbolRefAttr) -> Operation | None
staticmethod
¶
Lookup a symbol by reference, starting from a specific operation's closest SymbolTable parent.
Source code in xdsl/traits.py
insert_or_update(symbol_table_op: Operation, symbol_op: Operation) -> Operation | None
staticmethod
¶
This takes a symbol_table_op and a symbol_op. It looks if another operation inside symbol_table_op already defines symbol_ops symbol. If another operation is found, it replaces that operation with symbol_op. Otherwise, symbol_op is inserted at the end of symbol_table_op.
This method returns the operation that was replaced or None if no operation was replaced.
Source code in xdsl/traits.py
SymbolOpInterface
dataclass
¶
Bases: OpTrait
A Symbol is a named operation that resides immediately within a region that defines
a SymbolTable (TODO). A Symbol operation should use the SymbolOpInterface interface to
provide the necessary verification and accessors.
A Symbol operation may be optional or not. If - the default - it is not optional,
a sym_name attribute of type StringAttr is required. If it is optional,
the attribute is optional too.
xDSL offers OptionalSymbolOpInterface as an always-optional SymbolOpInterface helper.
More requirements are defined in MLIR; Please see MLIR documentation for Symbol and SymbolTable for the requirements that are upcoming in xDSL.
See external documentation.
Source code in xdsl/traits.py
get_sym_attr_name(op: Operation) -> StringAttr | None
¶
Returns the symbol of the operation, if any
Source code in xdsl/traits.py
is_optional_symbol(op: Operation) -> bool
¶
Returns true if this operation optionally defines a symbol based on the presence of the symbol name.
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
OptionalSymbolOpInterface
dataclass
¶
Bases: SymbolOpInterface
Helper interface specialization for an optional SymbolOpInterface.
Source code in xdsl/traits.py
CallableOpInterface
dataclass
¶
Bases: OpTrait, ABC
Interface for function-like Operations that can be called in a generic way.
Please see MLIR documentation for CallOpInterface and CallableOpInterface for more information.
See external documentation.
Source code in xdsl/traits.py
HasCanonicalizationPatternsTrait
dataclass
¶
Bases: OpTrait
Provides the rewrite passes to canonicalize an operation.
Each rewrite pattern must have the trait's op as root.
Source code in xdsl/traits.py
HasShapeInferencePatternsTrait
dataclass
¶
Bases: OpTrait
Provides the rewrite passes to shape infer an operation.
Each rewrite pattern must have the trait's op as root.
Source code in xdsl/traits.py
MemoryEffectKind
¶
Bases: Enum
The kind of side effect an operation can have.
MLIR has a more detailed version of this, able to tie effects to specific resources or values. Here, everything has its effect on the universe.
Source code in xdsl/traits.py
READ = auto()
class-attribute
instance-attribute
¶
Indicates that the operation reads from some resource. A 'read' effect implies only dereferencing of the resource, and not any visible mutation.
WRITE = auto()
class-attribute
instance-attribute
¶
Indicates that the operation writes to some resource. A 'write' effect implies only mutating a resource, and not any visible dereference or read.
ALLOC = auto()
class-attribute
instance-attribute
¶
Indicates that the operation allocates from some resource. An 'allocate' effect implies only allocation of the resource, and not any visible mutation or dereference.
FREE = auto()
class-attribute
instance-attribute
¶
Indicates that the operation frees some resource that has been allocated. A 'free' effect implies only de-allocation of the resource, and not any visible allocation, mutation or dereference.
Resource
dataclass
¶
Bases: ABC
This class represents a specific resource that an effect applies to.
Source code in xdsl/traits.py
DefaultResource
dataclass
¶
EffectInstance
dataclass
¶
An instance of a side effect.
Source code in xdsl/traits.py
kind: MemoryEffectKind
instance-attribute
¶
The kind of side effect.
value: SSAValue | SymbolRefAttr | None = field(default=None)
class-attribute
instance-attribute
¶
The value or symbol that is affected by the side effect, if known.
resource: Resource = field(default=DefaultResource())
class-attribute
instance-attribute
¶
The resource that the effect applies to.
__init__(kind: MemoryEffectKind, value: SSAValue | SymbolRefAttr | None = None, resource: Resource = DefaultResource()) -> None
¶
MemoryEffect
dataclass
¶
Bases: OpTrait
A trait that enables operations to expose their side-effects or absence thereof.
Source code in xdsl/traits.py
get_effects(op: Operation) -> AbstractSet[EffectInstance] | None
abstractmethod
classmethod
¶
Returns the concrete side effects of the operation.
Return None if the operation cannot conclude - interpreted as if the operation had no MemoryEffect interface in the first place.
Source code in xdsl/traits.py
NoMemoryEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation never has side effects.
Source code in xdsl/traits.py
MemoryReadEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation always has read side effects.
Source code in xdsl/traits.py
MemoryWriteEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation always has write side effects.
Source code in xdsl/traits.py
MemoryAllocEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation always has alloc side effects.
Source code in xdsl/traits.py
MemoryFreeEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation always has deallocation side effects.
Source code in xdsl/traits.py
RecursiveMemoryEffect
dataclass
¶
Bases: MemoryEffect
A trait that signals that an operation has the side effects of its contained operations.
Source code in xdsl/traits.py
get_effects(op: Operation) -> AbstractSet[EffectInstance] | None
classmethod
¶
Source code in xdsl/traits.py
AlwaysSpeculatable
dataclass
¶
Bases: ConditionallySpeculatable
Source code in xdsl/traits.py
RecursivelySpeculatable
dataclass
¶
Bases: ConditionallySpeculatable
Source code in xdsl/traits.py
Pure
dataclass
¶
Bases: NoMemoryEffect, AlwaysSpeculatable
In MLIR, Pure is NoMemoryEffect + AlwaysSpeculatable.
Source code in xdsl/traits.py
Commutative
dataclass
¶
HasInsnRepresentation
dataclass
¶
Bases: OpTrait, ABC
A trait providing information on how to encode an operation using a .insn assembler directive.
The returned string contains python string.format placeholders where formatted operands are inserted during printing.
See external documentation.
Source code in xdsl/traits.py
get_insn(op: Operation) -> str
abstractmethod
¶
SameOperandsAndResultType
dataclass
¶
Bases: OpTrait
Constrain the operation to have the same operands and result type.
Source code in xdsl/traits.py
__init__() -> None
¶
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
RegionSuccessor
dataclass
¶
This class represents a successor of a region. A region successor can either target another region or target an ancestor operation (at the moment, limited to the immediate parent operation). In the latter case, the control flow branches after/out of the target operation.
Source code in xdsl/traits.py
successor: Region | Operation
instance-attribute
¶
region: Region | None
property
¶
The successor region. None if the successor is an operation.
Implements MLIR RegionSuccessor::getSuccessor.
operation: Operation | None
property
¶
The successor operation. None if the successor is a region.
Implements MLIR RegionSuccessor::getSuccessorOp.
__init__(successor: Region | Operation) -> None
¶
is_region() -> bool
¶
Return true if the successor is a region.
Implements MLIR RegionSuccessor::isRegion.
is_operation() -> bool
¶
Return true if the successor is an operation.
Implements MLIR RegionSuccessor::isOperation.
RegionBranchPoint
dataclass
¶
This class represents a point being branched from in the methods of the
RegionBranchOpInterface.
One can branch from one of two kinds of places:
* The parent operation (aka the RegionBranchOpInterface implementation)
* A RegionBranchTerminatorOpInterface inside a region within the parent operation.
Construct with the terminator being branched from. Use RegionBranchPoint.PARENT to branch
from the parent operation. Raises ValueError if the terminator does not implement
RegionBranchTerminatorOpInterface. The constructor implements MLIR
RegionBranchPoint(RegionBranchTerminatorOpInterface).
Source code in xdsl/traits.py
predecessor: Operation | None
instance-attribute
¶
PARENT: RegionBranchPoint
class-attribute
¶
The RegionBranchPoint representing the parent operation.
Implements MLIR RegionBranchPoint::parent.
terminator: Operation | None
property
¶
The terminator if branching from a region. None otherwise.
Implements MLIR RegionBranchPoint::getTerminatorPredecessorOrNull.
terminator_predecessor_and_trait: tuple[Operation, RegionBranchTerminatorOpTrait] | None
property
¶
The terminator and its RegionBranchTerminatorOpTrait if branching from a
region. None otherwise.
Implements MLIR RegionBranchPoint::getTerminatorPredecessorOrNull, together with
terminator. MLIR returns a single interface handle that is both the op and its interface
methods. In xDSL the op and its trait are separate objects, and the trait methods take the
op as an argument, so this property returns both.
__init__(predecessor: Operation) -> None
¶
Source code in xdsl/traits.py
is_parent() -> bool
¶
Returns true if branching from the parent op.
Implements MLIR RegionBranchPoint::isParent.
InvocationBounds
dataclass
¶
This class represents upper and lower bounds on the number of times a region of a
RegionBranchOpInterface can be invoked. The lower bound is at least zero, but the upper bound
may not be known.
Source code in xdsl/traits.py
lower: int
instance-attribute
¶
The minimum number of times the successor region will be invoked.
Implements MLIR InvocationBounds::getLowerBound.
upper: int | None
instance-attribute
¶
The maximum number of times the successor region will be invoked or None if an upper bound
is not known.
Implements MLIR InvocationBounds::getUpperBound.
UNKNOWN: InvocationBounds
class-attribute
¶
The unknown invocation bounds, i.e., there is no information on how many times a region may be invoked.
Implements MLIR InvocationBounds::getUnknown.
__init__(lower: int, upper: int | None) -> None
¶
__post_init__() -> None
¶
Implements the checks of MLIR InvocationBounds constructor.
Source code in xdsl/traits.py
RegionBranchOpTrait
dataclass
¶
Bases: OpTrait
This interface provides information for region-holding operations that exhibit branching behavior between held regions. It models the control flow edges between regions (and between the op and its regions), as well as the data flow (value propagation) that occurs along those control flow edges.
This interface is meant to model well-defined cases of control-flow and value propagation, where what occurs along control-flow edges is assumed to be side-effect free.
A "region branch point" indicates the point from which a branch (edge) originates. It can
indicate:
1. A RegionBranchTerminatorOpInterface terminator in any of the immediately nested regions
of this op.
2. RegionBranchPoint.PARENT: the branch originates from outside of the op, i.e., when
first executing this op.
When branching from a region branch point to a region successor, the "successor operands" to
be forwarded from the region branch point can be specified with get_entry_successor_operands
/ RegionBranchTerminatorOpInterface.get_successor_operands.
A "region successor" indicates the target of a branch. It can indicate: 1. A region of this op. 2. A parent operation, i.e., the control flow leaves/resumes after that op.
The SSA values to which successor operands are forwarded are called "successor inputs".
By default, successor operands and successor block arguments/successor results must have the
same type. are_types_compatible can be implemented to allow non-equal types.
Note: This interface works in conjunction with RegionBranchTerminatorOpInterface. All
immediately nested block terminators that model branching between regions must implement the
RegionBranchTerminatorOpInterface. Otherwise, analyses/transformations may miss control flow
edges and produce incorrect results. Not every block terminator is necessarily a region branch
terminator: e.g., in the presence of unstructured control flow, a block terminator could
indicate a branch to a different block within the same region.
Example:
%r = scf.for %iv = %lb to %ub step %step iter_args(%a = %b)
-> tensor<5xf32> {
...
scf.yield %c : tensor<5xf32>
}
scf.for has one region. There are two region branch points with two identical region
successors:
* parent => op(%r), region0(%a)
* scf.yield => op(%r), region0(%a)
%a and %r are successor inputs. %b is an entry successor operand. %c is a successor
operand.
Source code in xdsl/traits.py
1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 | |
entry_successor_regions(op: Operation, operands: Sequence[Attribute | None]) -> Sequence[RegionSuccessor]
classmethod
¶
Returns all potential region successors when first executing the op.
Unlike successor_regions, this method also receives the constant operands of this op
(one entry per operand, None if the operand has no/unknown constant value). The
implementation may use this information to filter out successors. By default, it simply
dispatches to successor_regions.
Note: The control flow does not necessarily have to enter any region of this op.
Example: In the above example, this method may return two region successors: the single
region of the scf.for op and the scf.for operation (that implements this interface). If
%lb, %ub, %step are constants and it can be determined the loop does not have any
iterations, this method may choose to return only this operation. Similarly, if it can be
determined that the loop has at least one iteration, this method may choose to return only
the region of the loop.
Source code in xdsl/traits.py
successor_regions(op: Operation, point: RegionBranchPoint) -> Sequence[RegionSuccessor]
abstractmethod
classmethod
¶
Returns all potential region successors when branching from point. These are the
regions that may be selected during the flow of control.
When point = RegionBranchPoint.PARENT, this method returns the region successors when
entering the operation. Otherwise, this method returns the successor regions when branching
from the region indicated by point.
Example: In the above example, this method returns the region of the scf.for and the
scf.for op itself for either region branch point. An implementation may choose to filter
out region successors when it is statically known (e.g., by examining the operands of this
op) that those successors are not branched to.
Source code in xdsl/traits.py
successor_regions_from_region(op: Operation, region: Region) -> Iterator[RegionSuccessor]
classmethod
¶
Returns all potential region successors when branching from any terminator in
region.
Source code in xdsl/traits.py
successor_inputs(op: Operation, successor: RegionSuccessor) -> Sequence[SSAValue]
classmethod
¶
Return all successor inputs for the given region successor. If the given region successor is a region, then the returned values are block arguments. Otherwise, if the given region successor is an operation, the returned values are op results.
Source code in xdsl/traits.py
predecessors(op: Operation, successor: RegionSuccessor) -> Iterator[RegionBranchPoint]
classmethod
¶
Returns all potential branching points (predecessors) for a given region successor.
Source code in xdsl/traits.py
region_invocation_bounds(op: Operation, operands: Sequence[Attribute | None]) -> Sequence[InvocationBounds]
classmethod
¶
Returns the minimum and maximum number of times this operation will invoke the attached
regions (assuming the regions yield normally, i.e. do not abort or invoke an infinite
loop). The minimum number of invocations is at least 0. If the maximum number of
invocations cannot be statically determined, then it will be set to
InvocationBounds.UNKNOWN.
This method also passes along the constant operands of this op. operands contains an
entry for every operand of this op, with None if the operand has no constant value.
This method may be called speculatively on operations where the provided operands are not necessarily the same as the operation's current operands. This may occur in analyses that wish to determine "what would be the region invocations if these were the operands?"
Source code in xdsl/traits.py
are_types_compatible(op: Operation, lhs: Attribute, rhs: Attribute) -> bool
classmethod
¶
This method is called to compare types along control-flow edges. By default, the types are checked as equal.
Source code in xdsl/traits.py
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
all_region_branch_points(op: Operation) -> Iterator[RegionBranchPoint]
classmethod
¶
Return all possible region branch points: the region branch op itself and all region branch terminators.
Source code in xdsl/traits.py
RegionBranchTerminatorOpTrait
dataclass
¶
Bases: OpTrait
This interface provides information for branching terminator operations in the presence of a
parent RegionBranchOpInterface implementation. It acts as a marker for valid region branch
points and specifies which operands are passed to which region successor.
Note: If an operation does not implement the RegionBranchTerminatorOpInterface, then that op
has no region successors. (However, there may be other block terminators in the same region
that implement the RegionBranchTerminatorOpInterface, so the enclosing region may have region
successors.)
Source code in xdsl/traits.py
verify(op: Operation) -> None
¶
Source code in xdsl/traits.py
ensure_terminator(op: Operation, trait: SingleBlockImplicitTerminator) -> None
¶
Method that helps with the creation of an implicit terminator. This should be explicitly called during the creation of an operation that has the SingleBlockImplicitTerminator trait.
Source code in xdsl/traits.py
has_effects(op: Operation, effect: MemoryEffectKind) -> bool
¶
Returns if the operation has side effects of this kind.
has_exact_effect(op: Operation, effect: MemoryEffectKind) -> bool
¶
Returns if the operation has the given side effects and no others.
proxy for only_has_effect
only_has_effect(op: Operation, effect: MemoryEffectKind) -> bool
¶
Returns if the operation has the given side effects and no others.
is_side_effect_free(op: Operation) -> bool
¶
Boilerplate helper to check if a generic operation is side effect free for sure.
get_effects(op: Operation) -> AbstractSet[EffectInstance] | None
¶
Helper to get known side effects of an operation. None means that the operation has unknown effects, for safety.