This module contains the main definitions that make up the mid-end IR (MIR).
See MIR for the grammar plus a high-level overview of the MIR.
Types
ConstId = distinct uint32
- Identifies a constant across all MIR code. This includes both user-defined constants as well as anonymous constants Source Edit
EffectKind = enum ekNone, ## no effect ekMutate, ## the value in the location is mutated ekReassign, ## a new value is assigned to the location ekKill, ## the value is removed from the location (without observing ## it), leaving the location empty ekInvalidate ## all knowledge and assumptions about the location and its ## value become outdated. The state of it is now completely ## unknown
- Source Edit
LabelId = distinct uint32
- ID of a label, used to identify the control-flow destinations and constructs. Source Edit
MirNode = object typ*: TypeId ## valid for all expression, including all calls info*: SourceId ## non-critical meta-data associated with the node (e.g., origin ## information) case kind*: MirNodeKind of mnkProc, mnkProcVal: prc*: ProcedureId of mnkGlobal: global*: GlobalId of mnkConst: cnst*: ConstId of mnkParam, mnkLocal, mnkTemp, mnkAlias: local*: LocalId of mnkField: field*: int32 ## field position of mnkIntLit, mnkUIntLit, mnkFloatLit: number*: NumberId of mnkStrLit: strVal*: StringId of mnkAstLit: ast*: AstId of mnkLabel: label*: LabelId of mnkImmediate: imm*: uint32 ## meaning depends on the context of mnkMagic: magic*: TMagic of mnkNone, mnkNilLit, mnkType, mnkResume: nil of {low(MirNodeKind)..high(MirNodeKind)} - {mnkNone..mnkResume}: len*: uint32
- Source Edit
MirNodeKind = enum mnkNone, mnkProc, ## procedure reference; only allowed in callee slots mnkProcVal, ## procedural value mnkConst, ## named constant mnkGlobal, ## global location mnkParam, ## parameter mnkLocal, ## local location mnkTemp, ## like ``mnkLocal``, but the local was introduced by the ## compiler during the MIR phase mnkAlias, ## local run-time handle. This is essentially a ``var T`` or ## ``lent T`` local mnkField, ## declarative node only allowed in special contexts mnkLabel, ## name of a label mnkNilLit, ## nil literal mnkIntLit, ## reference to signed integer literal mnkUIntLit, ## reference to unsigend integer literal mnkFloatLit, ## reference to float literal mnkStrLit, ## reference to a literal string mnkAstLit, ## reference to AST fragment mnkType, ## a type literal mnkImmediate, ## special node only allowed in certain contexts. Used to ## store extra, context-dependent information in the tree mnkMagic, ## only allowed in a callee position. Refers to a magic ## procedure mnkResume, ## special action in a target list that means "resume ## exception handling in caller" mnkDef, ## marks the start of existence of a local, global, procedure, ## or temporary. Supports an optional intial value (except for ## procedure definitions) mnkDefCursor, ## marks the start of existence of a non-owning location mnkBind, ## introduces an alias that may be used for read/write ## access, but not for direct assignments. The source ## expression must not be empty mnkBindMut, ## introduces an alias that may be used for read/write access ## and assignments. The source expression must not be empty mnkAsgn, ## normal assignment; the destination might store a value ## already. Whether the source is copied or moved depends ## on the expression mnkInit, ## similar to ``mnkAsgn``, but makes the guarantee that the ## destination contains no value (i.e., is not initialized). ## "Not initialized" doesn't make any guarantees about the ## destination's in-memory contents mnkSwitch, ## sets the value of a discriminator field, changing the active ## branch, if necessary. The destination operand must be a ## ``mnkPathVariant`` expression mnkPathNamed, ## access of a named field in a record mnkPathPos, ## access of a field in record via its position mnkPathArray, ## access of an array-like (both dynamic and static) value ## with an integer index mnkPathVariant, ## access a tagged union ## XXX: this is likely only a temporary solution. Each ## record-case part of an object should be its own ## dedicated object type, which can then be addressed ## as a normal field mnkPathConv, ## a handle conversion. That is, a conversion that produces a ## ## *handle*, and not a new *value*. At present, this operator ## ## also applies to first-class handles, like ``ref``. mnkAddr, ## create a pointer from the provided lvalue mnkDeref, ## dereference a ``ptr`` or ``ref`` value mnkView, ## create a first-class safe alias from an lvalue mnkMutView, ## create a safe mutable view from an lvalue mnkDerefView, ## dereference a first-class safe alias mnkStdConv, ## a standard conversion. Produce a new value. mnkConv, ## ``conv(x)``; a conversion. Produces a new value. mnkCast, ## cast the representation of a value into a different type mnkToSlice, ## has to variants: ## * the 1 argument variant creates an openArray from the ## full sequence specified as the operand ## * the 3 argument variant creates an openArray from the ## sub-sequence specified by the sequence and lower and ## upper bound mnkToMutSlice, ## version of ``mnkToSlice`` for creating a mutable slice mnkCall, ## invoke a procedure and pass along the provided arguments. ## Used for both static and dynamic calls mnkCheckedCall, ## invoke a magic procedure and pass along the provided arguments mnkNeg, ## signed integer and float negation (for ints, overflow is UB) mnkAdd, ## signed integer and float addition (for ints, overflow is UB) mnkSub, ## signed integer and float subtraction (for ints, overflow is UB) mnkMul, ## signed integer and float multiplication (for ints, overflow is ## UB) mnkDiv, ## signed integer and float division (for ints, division by zero is ## UB) mnkModI, ## compute the remainder of an integer division (division by zero ## is UB) mnkRaise, ## starts exceptional control-flow and jumps to the specified ## handler mnkSetConstr, ## constructor for set values mnkRange, ## range constructor. May only appear in set constructions ## and as a branch label mnkArrayConstr, ## constructor for array values mnkSeqConstr, ## constructor for seq values mnkTupleConstr, ## constructor for tuple values mnkClosureConstr, ## constructor for closure values mnkObjConstr, ## constructor for object values mnkRefConstr, ## allocates a new managed heap cell and initializes it mnkBinding, ## only valid as an object or ref construction child node. ## Associates an argument with a field mnkCopy, ## denotes the assignment as copying the source value mnkMove, ## denotes the assignment as moving the value. This does ## not imply a phyiscal change to the source location mnkSink, ## collapses into one of the following: ## - a copy (`mnkCopy`) ## - a non-destructive move (`mnkMove`) ## - a destructive move ## ## Collapsing ``mnkSink`` is the responsibility of the move ## analyzer. mnkArg, ## when used in a call: denotes an argument that may either be ## passed by value or by name. Evaluation order is unspecified ## when used in a construction: denotes a value that is copied ## (shallow) into the aggregate value mnkName, ## denotes an argument that is passed by name mnkConsume, ## similar to ``mnkArg``, but moves (non-destructively) the ## value into the aggregate or parameter mnkVoid, ## either a: ## * syntactic statement node for representing void calls ## * statement acting as a use of the given lvalue mnkScope, ## starts a scope, which are used to delimit lifetime of locals ## they enclose. Can be nested, but must always be paired with ## exactly one ``mnkEndScope`` statement mnkEndScope, ## closes the current scope. Must always be paired with a ## ``mnkScope`` statement mnkGoto, ## unconditional jump mnkIf, ## depending on the run-time value of `x`, transfers control- ## flow to either the start or the end of the spanned code mnkCase, ## dispatches to one of its branches based on the run-time ## value of the operand mnkBranch, ## a branch in a ``mnkCase`` dispatcher mnkLoop, ## unconditional jump to the associated-with loop start mnkJoin, ## join point for gotos and branches mnkLoopJoin, ## join point for loops. Represents the start of a loop mnkExcept, ## starts an exception handler mnkFinally, ## starts a finally section. Must be paired with exactly one ## ``mnkContinue`` that follows mnkContinue, ## marks the end of a finally section mnkEndStruct, ## marks the end of an if or except mnkDestroy, ## destroys the value stored in the given location, leaving the ## location in an undefined state mnkAsm, ## embeds backend-dependent code directly into the output mnkEmit ## embeds backend-dependent code directly into the output
- Users of MirNodeKind should not depend on the absolute or relative order between the enum values Source Edit
MirNodeSeq = seq[MirNode]
- A buffer of MIR nodes without any further meaning Source Edit
NodePosition = distinct int32
- refers to a MirNode of which the position relative to other nodes has meaning. Uses a signed integer as the base Source Edit
NumberId = distinct uint32
- Uniquely identifies some numerical value (float, signed int, unsigned int). Two values with the same bit pattern have the same ID Source Edit
ProcedureId = distinct uint32
- Identifies a procedure Source Edit
SourceId = distinct range[0'u32 .. high(uint32) - 1]
- The ID of a source-mapping that's stored separately from the MIR nodes. Source Edit
Consts
AllNodeKinds = {mnkNone..mnkEmit}
- Convenience set containing all existing node kinds Source Edit
ArgumentNodes = {mnkArg, mnkName, mnkConsume}
- Nodes only allowed in argument contexts. Source Edit
Atoms = {mnkNone, mnkProcVal..mnkAlias, mnkNilLit..mnkType}
- Nodes that may be appear in atom-expecting slots. Source Edit
ConstrTreeNodes = {mnkProcVal, mnkField, mnkNilLit..mnkAstLit, mnkSetConstr..mnkBinding, mnkArg}
- Nodes that can appear in the MIR subset used for constant expressions. Source Edit
DefNodes = {mnkDef, mnkDefCursor, mnkBind, mnkBindMut}
- Node kinds that represent definition statements (i.e. something that introduces a named entity) Source Edit
ExprKinds = {mnkProcVal..mnkAlias, mnkNilLit..mnkType, mnkPathNamed..mnkModI, mnkSetConstr, mnkArrayConstr..mnkRefConstr, mnkCopy..mnkSink}
- Source Edit
LabelNodes = {mnkLabel}
- Source Edit
LiteralDataNodes = {mnkNilLit, mnkIntLit, mnkUIntLit, mnkFloatLit, mnkStrLit, mnkAstLit}
- Source Edit
LvalueExprKinds = {mnkPathPos, mnkPathNamed, mnkPathArray, mnkPathVariant, mnkPathConv, mnkDeref, mnkDerefView, mnkTemp, mnkAlias, mnkLocal, mnkParam, mnkConst, mnkGlobal}
- Source Edit
ModifierNodes = {mnkCopy, mnkMove, mnkSink}
- Assignment modifiers. Nodes that can only appear directly in the source slot of assignments. Source Edit
RvalueExprKinds = {mnkProcVal, mnkNilLit..mnkType, mnkAddr, mnkView..mnkMutView, mnkStdConv..mnkToMutSlice, mnkNeg..mnkModI}
- Source Edit
SingleOperandNodes = {mnkPathNamed, mnkPathPos, mnkPathVariant, mnkPathConv, mnkAddr, mnkDeref, mnkView, mnkDerefView, mnkStdConv, mnkConv, mnkCast, mnkArg, mnkName, mnkConsume, mnkVoid, mnkCopy, mnkMove, mnkSink, mnkDestroy, mnkMutView, mnkToMutSlice}
- Nodes that start sub-trees but that always have a single sub node. Source Edit
StmtNodes = {mnkDef..mnkSwitch, mnkRaise, mnkVoid..mnkCase, mnkLoop..mnkEmit}
- Nodes that are treated like statements, in terms of syntax. Source Edit
SubTreeNodes = {mnkDef..mnkEmit}
- Nodes that start a sub-tree. They always store a length. Source Edit
Procs
func `<=`(a, b: NodePosition): bool {.borrow, inline, ...raises: [], tags: [].}
- Source Edit
func `<`(a, b: NodePosition): bool {.borrow, inline, ...raises: [], tags: [].}
- Source Edit
func `==`(a, b: NodePosition): bool {.borrow, inline, ...raises: [], tags: [].}
- Source Edit
func `==`(a, b: ProcedureId): bool {.borrow, ...raises: [], tags: [].}
- Source Edit
func `[]`(tree: MirTree; n: NodePosition; index: Natural): lent MirNode {. ...raises: [], tags: [].}
- Source Edit
func `[]`(tree: MirTree; n: OpValue; index: Natural): lent MirNode {....raises: [], tags: [].}
- Source Edit
func `in`(p: NodePosition; tree: MirTree): bool {.inline, ...raises: [], tags: [].}
- Source Edit
func argument(tree: MirTree; n: NodePosition; i: Natural): OpValue {....raises: [], tags: [].}
- Returns the i-th argument in the call-like tree at n, skipping tag nodes. It is expected that the call has at least i + 1 arguments. Source Edit
func callee(tree: MirTree; n: NodePosition): NodePosition {.inline, ...raises: [], tags: [].}
- Returns the callee node for the call subtree n. Source Edit
func child(tree: MirTree; n: NodePosition; index: Natural): NodePosition {. ...raises: [], tags: [].}
- Returns the position of the child node at index index. index must refer to a valid sub-node -- no validation is performed Source Edit
func computeSpan(tree: MirTree; n: NodePosition): Slice[NodePosition] {. ...raises: [], tags: [].}
- If n refers to a leaf node, returns a span with the n as the single item. Otherwise, computes and returns the span of nodes part of the sub-tree at n. The 'end' node is included. Source Edit
func effect(tree: MirTree; n: NodePosition): EffectKind {.inline, ...raises: [], tags: [].}
- Returns the effect for the mnkName node at n. Source Edit
func extract(id: ConstId): DataId {....raises: [], tags: [].}
- Extracts the DataId from id. Source Edit
func field(tree: MirTree; n: NodePosition): int32 {.inline, ...raises: [], tags: [].}
- Returns the field position specified for the field access at n. Source Edit
func findDef(tree: MirTree; n: NodePosition): NodePosition {....raises: [], tags: [].}
- Finds and returns the first definition for the name of the temporary at node n. No control-flow analysis is performed. Source Edit
func findParent(tree: MirTree; start: NodePosition; kind: MirNodeKind): NodePosition {. ...raises: [], tags: [].}
- Searches for the first enclosing sub-tree node of kind kind (which is required to exist). The node at start is itself also considered during the search Source Edit
func isAnon(id: ConstId): bool {....raises: [], tags: [].}
- Returns whether id represents an anonymous constant. Source Edit
func last(tree: MirTree; n: NodePosition): NodePosition {....raises: [], tags: [].}
- Returns the last child node in the subtree at n. Source Edit
func len(tree: MirTree; n: NodePosition): int {....raises: [], tags: [].}
- Computes the number of child nodes for the given sub-tree node. Source Edit
proc mutatesGlobal(tree: MirTree; n: NodePosition): bool {.inline, ...raises: [], tags: [].}
- Whether evaluating the call expression at n potentially mutates global state. Source Edit
func numArgs(tree: MirTree; n: NodePosition): int {....raises: [], tags: [].}
- Counts and returns the number of call arguments in the call tree at n. Source Edit
func operand(tree: MirTree; n: NodePosition; i: Natural): OpValue {.inline, ...raises: [], tags: [].}
- Returns the i-th operand to the sub-tree at n. It is expected that the operation has at least i + 1 operands. Source Edit
func operand(tree: MirTree; op: OpValue | NodePosition): OpValue
- Returns the index (OpValue) of the operand for the single-operand operation at op. Source Edit
func parent(tree: MirTree; n: NodePosition): NodePosition {....raises: [], tags: [].}
- Source Edit
func previous(tree: MirTree; n: NodePosition): NodePosition {....raises: [], tags: [].}
- Computes the index of n's the preceding sibling node. If there is none, returns the index of the parent node. This is a slow operation, it should be used sparsely. Source Edit
func sibling(tree: MirTree; n: NodePosition): NodePosition {....raises: [], tags: [].}
- Computes the index of the next node/sub-tree following the node at n. Source Edit
Iterators
iterator arguments(tree: MirTree; n: NodePosition): (ArgKinds, EffectKind, OpValue) {....raises: [], tags: [].}
- Returns the argument kinds together with the operand node (or tag tree). Source Edit
iterator subNodes(tree: MirTree; n: NodePosition; start = 0): NodePosition {. ...raises: [], tags: [].}
- Returns in order of apperance all direct child nodes of n, starting with start. Source Edit
Templates
template `+`(a: NodePosition; b: int): NodePosition
- Source Edit
template `-`(a: NodePosition; b: int): NodePosition
- Source Edit
template dec(a: var NodePosition)
- Source Edit
template inc(a: var NodePosition)
- Source Edit