Bases: object
Assignment to some attribute. We need to detect assignments in the constructor of extension types.
Bases: object
Exception handling helper.
entry_point ControlBlock Exception handling entry point finally_enter ControlBlock Normal finally clause entry point finally_exit ControlBlock Normal finally clause exit point
Bases: object
Bases: object
Bases: object
Bases: numba.nodes.basenodes.Node
Bases: object
Control flow for the AST backend.
Adapted from Cython/Compiler/FlowControl.py
Bases: numba.nodes.cfnodes.LowLevelBasicBlockNode
Control flow graph node. Sequence of assignments and name references. This is simultaneously an AST node.
children set of children nodes parents set of parent nodes positions set of position markers
stats list of block statements gen dict of assignments generated by this block bound set of entries that are definitely bounded in this block
Example:
a = 1 b = a + c # ‘c’ is already bounded or exception here
- stats = [Assignment(a), NameReference(a), NameReference(c),
- Assignment(b)]
gen = {Entry(a): Assignment(a), Entry(b): Assignment(b)} bound = set([Entry(a), Entry(c)])
Delete a block from the cfg.
Detach block from parents and children.
Re-parent all children to the new block
Bases: object
Control-flow graph.
entry_point ControlBlock entry point for this graph exit_point ControlBlock normal exit point block ControlBlock current block blocks set children nodes entries set tracked entries loops list stack for loop descriptors exceptions list stack for exception descriptors
Add an exit block after visiting the body
Compute the dominance frontier for all blocks. This indicates for each block where dominance stops in the CFG. We use this as the place to insert Φ functions, since at the dominance frontier there are multiple control flow paths to the block, which means multiple variable definitions can reach there.
Compute the dominators for the CFG, i.e. for each basic block the set of basic blocks that dominate that block. This mean from the entry block to that block must go through the blocks in the dominator set.
dominators(x) = {x} ∪ (∩ dominators(y) for y ∈ preds(x))
Create a floating exit block. This can later be added to self.blocks. This is useful to ensure topological order.
The dominator of x that is dominated by all other dominators of x. This is the block that has the largest dominator set.
Set initial state, map assignments to bits.
Set initial state, run after SSA. There is only ever one live definition of a variable in a block, so we can simply track input and output definitions as the Variable/Entry they came as.
Map the bitstate of a variable to the definitions it represents
Mark position, will be used to draw graph nodes.
Create floating block linked to parent if given. Does NOT set the current block to the new block.
Create child block linked to current or parent if given. Sets the current block to the new block.
Delete unreachable and orphan blocks.
Per-block reaching definitions analysis.
Compute phi nodes
- for each variable v
- insert empty phi nodes in dominance frontier of each block that defines v
- this phi defines a new assignment in each block in which it is inserted, so propagate (recursively)
Reaching definitions
Set block-local symbol table for each block. This is a rudimentary form of reaching definitions, but we can do it in a single pass because all assignments are known (since we inserted the phi functions, which also count as assignments). This means the output set is known up front for each block and never changes. After setting all output sets, we can compute the input sets in a single pass:
- compute output sets for each block
- compute input sets for each block
Update phis with incoming variables. The incoming variables are last assignments of the predecessor blocks in the CFG.
Bases: numba.visitors.NumbaTransformer
Control flow analysis pass that builds the CFG and injects the blocks into the AST (but not all blocks are injected).
The CFG must be build in topological DFS order, e.g. the ‘if’ condition block must precede the clauses and the clauses must precede the exit.
Create assignment code for inner functions and mark the assignment
Populate the symbol table with variables and set their renaming status.
Variables appearing in locals, or arguments typed through the ‘jit’ decorator are not renameable.
Mark position if DOT output is enabled.
Set some defaults for warnings
Inplace assignment.
Resolve a += b to a = a + b. Set ‘inplace_op’ attribute of the Assign node so later stages may recognize inplace assignment.
Do this now, so that we can correctly mark the RHS reference.
Rewrite list comprehensions to the equivalent for loops.
AST syntax:
ListComp(expr elt, comprehension* generators) comprehension = (expr target, expr iter, expr* ifs)
‘ifs’ represent a chain of ANDs
Bases: numba.control_flow.control_flow.ControlBlock
Non-empty exit point block.
Bases: numba.nodes.basenodes.Node
Wraps an inner function node until the closure code kicks in.
Bases: numba.visitors.NumbaVisitor
Delete a (compound) statement that contains basic blocks. The statement must be at the start of the entry block.
idom: the immediate dominator of
Bases: object
Graphviz DOT renderer.
Bases: object
Graphviz subgraph object.
Render graphviz dot graph
Bases: object
Generate control flow related warnings.
Find uninitialized references and cf-hints
Generate a warning for unreachable code
Generate warnings for unused variables or arguments. This is issues when an argument or variable is unused entirely in the function.
Warn about unused variable definitions. This is issued for individual definitions, e.g.
i = 0 # this definition generates a warning i = 1 print i
Update all our phi nodes after translation is done and all Variables have their llvm values set.
Iterate over all phi nodes
Iterate over all phi nodes
Used before running type inference.
Kill phis which are not referenced. We need to do this bottom-up, i.e. in reverse topological dominator-tree order, since in SSA a definition always lexically precedes a reference.
This is important, since it kills any unnecessary promotions (e.g. ones to object, which LLVM wouldn’t be able to optimize out).
TODO: Kill phi cycles, or do reachability analysis before inserting phis.
Add all incoming phis to the phi instruction.
Handle promotions by using the promoted value from the incoming block. E.g.
bb0: if C: bb1: x = 2
else:bb2: x = 2.0
bb3: x = phi(x_bb1, x_bb2)
has a promotion for ‘x’ in basic block 1 (from int to float).
Handle phi nodes:
Handle incoming variables which are not initialized. Set incoming_variable.uninitialized_value to a constant ‘bad’ value (e.g. 0xbad for integers, NaN for floats, NULL for objects)
Handle incoming variables which need promotions. An incoming variable needs a promotion if it has a different type than the the phi. The promotion happens in each ancestor block that defines the variable which reaches us.
Promotions are set separately in the symbol table, since the ancestor may not be our immediate parent, we cannot introduce a rename and look up the latest version since there may be multiple different promotions. So during codegen, we first check whether incoming_type == phi_type, and otherwise we look up the promotion in the parent block or an ancestor.