compiler/mir/mirgen_blocks

  Source   Edit

Subordinate module to mirgen. Implements the block and scope management required for translating the AST's high-level control-flow constructs to the MIR's goto-based ones. Injecting mnkDestroy operations is also implemented here, integrated with the scope management.

Types

Block = object
  id*: Option[LabelId] ## the block's label. Initialized on-demand, meaning that 'none'
                       ## indicates that the block is unused
  case kind*: BlockKind
  of bkBlock:
      label*: PSym           ## the symbol of the block's label. nil if it's an internal block
    
  of bkScope:
      numRegistered: int     ## number of entities registered for the scope in the to-destroy list
    
  of bkTryFinally:
      selector*: Option[Value] ## the variable to store the destination index in
      exits*: seq[int]       ## a set of all original target block indices
    
  of bkFinally:
      selectorVar*: Value    ## the selector storing the dispatcher's target index
      excState*: int ## the selector value representing the "finally entered via exception"
                     ## state
    
  of bkTryExcept, bkExcept:
      nil

  
Information about a block-like structure. This not only includes |NimSkull| blocks, but also try, finally, etc.   Source   Edit
BlockCtx = object
  blocks: seq[Block]         ## stack of enclosing try, finally, etc. blocks
  toDestroy: seq[tuple[entity: Value, label: Option[LabelId]]] ## all locals/globals/temporaries that need destruction, together
                                                               ## with the label of the finally that the destroy operation is part
                                                               ## of. Only the items where the `label` changes have an initialized
                                                               ## label
  currScope: int             ## block index of the current scope
  
Per-procedure block-related state.   Source   Edit
BlockKind = enum
  bkBlock, bkScope, bkTryExcept, bkTryFinally, bkFinally, bkExcept
  Source   Edit

Procs

proc blockExit(c; graph: ModuleGraph; env: var MirEnv; bu; targetBlock: int) {.
    ...raises: [KeyError, Exception], tags: [ReadDirEffect, RootEffect].}
Emits a goto jumping to the targetBlock, together with the necessary scope and exception cleanup logic. If the jump crosses a try/finally, the finally is jumped to instead.   Source   Edit
proc closeBlock(c; bu): bool {....raises: [], tags: [].}
Finishes the current block. If required for the block (because it is a block and broken out of), emits a join and returns true, false otherwise.   Source   Edit
proc closeScope(c; bu; nextScope: int; hasStructuredExit: bool) {....raises: [],
    tags: [].}

Pops the scope from the stack and emits the scope exit actions. hasStructuredExit tells whether structured control-flow reaches the end of the scope, affecting how the exit looks like.

next is the index of the scope index returns by the previous startScope call.

  Source   Edit
proc closest(c: BlockCtx): int {....raises: [], tags: [].}
Returns the index of the closest block.   Source   Edit
proc findBlock(c: BlockCtx; label: PSym): int {....raises: [], tags: [].}
Returns the index of the block with label label.   Source   Edit
proc isInFinally(c: BlockCtx): bool {....raises: [], tags: [].}
  Source   Edit
proc labelNode(label: LabelId): MirNode {....raises: [], tags: [].}
  Source   Edit
proc raiseExit(c; bu) {....raises: [], tags: [].}
Emits the jump target for a jump to the nearest enclosing exception handler.   Source   Edit
func register(c; loc: Value) {....raises: [], tags: [].}
Registers loc for destruction at the end of the current scope. Destruction happens in the reverse order the locations are registered in.   Source   Edit
proc startScope(c): int {....raises: [], tags: [].}
Starts a new scope and returns the index of the previous one.   Source   Edit

Templates

template add(c: var BlockCtx; b: Block)
  Source   Edit
template pop(c: var BlockCtx): Block
  Source   Edit