qat.experimental.dialect.q1_scf.transforms.lower_scf module

Lower the builtin scf dialect into q1_scf.

This pass converts standard MLIR structured control flow (xdsl.dialects.scf) into the Q1-sequencer-specific structured control flow dialect q1_scf.

Motivation

The frontend importer produces scf.for loops to represent shot iteration and similar counted patterns. Before the q1_scf pipeline can lower those loops to hardware, the generic scf containers must first be mapped onto their Q1 counterparts.

For loops

scf.for %i = %lb to %ub step %step iter_args(%a, ...) { ... scf.yield ... } maps onto q1_scf.for %n : q1.reg iter_args(%a, ...) { ... q1_scf.yield ... } where %n is loaded with the iteration count ceil((ub - lb) / step) by a q1.ir.move instruction inserted immediately before the loop.

The scf induction variable counts up from lb toward ub; the q1_scf induction counter counts down from n toward zero. When the loop body uses the induction variable, arithmetic instructions are inserted at the top of the body to reconstruct the ascending value lb + (count - counter) * step.

Bounds that are not arith.constant integer literals, non-positive step values, zero-trip counts, and loop-carried values whose type is not q1.reg are also rejected.

Stubs

scf.if and scf.while are not yet supported. The corresponding rewrite patterns raise PassFailedException immediately.

Reference: https://docs.qblox.com/en/main/products/qblox_instruments/q1/index.html

class ForLowering

Bases: RewritePattern

Lower scf.for to q1_scf.for. The iteration count ceil((ub - lb) / step) is materialised as a q1.ir.move inserted immediately before the loop. The body induction argument is retyped from index to !q1.reg, and scf.yield is replaced by q1_scf.yield. When the body uses the induction variable, arithmetic is inserted at the top of the body block to reconstruct the ascending index from the countdown counter.

Example (lb=0, ub=10, step=2, count=5; body uses %i):

// before
%lb   = arith.constant 0 : index
%ub   = arith.constant 10 : index
%step = arith.constant 2 : index
scf.for %i = %lb to %ub step %step {
  ... uses of %i ...
  scf.yield
}

// after
%lb   = arith.constant 0 : index
%ub   = arith.constant 10 : index
%step = arith.constant 2 : index
%n    = q1.ir.move () <{imm = #q1.su32_imm<5>}> : () -> !q1.reg
q1_scf.for %n : !q1.reg {
^bb0(%counter: !q1.reg):
  %not_c  = q1.rr.not (%counter) : (!q1.reg) -> !q1.reg
  %diff   = q1.rir.add (%not_c) <{imm = #q1.su32_imm<6>}> : (!q1.reg) -> !q1.reg
  %i      = q1.rir.muls16 (%diff) <{imm = #q1.si16_imm<2>}> : (!q1.reg) -> !q1.reg
  ... uses of %i (now !q1.reg, ascending 0, 2, 4, 6, 8) ...
  q1_scf.yield
}
match_and_rewrite(op: Operation, rewriter: PatternRewriter) None

Match an operation, and optionally perform a rewrite using the rewriter.

Return type:

None

class IfLowering

Bases: RewritePattern

Stub for scf.ifq1_scf.if lowering.

Not yet implemented.

match_and_rewrite(op: Operation, rewriter: PatternRewriter) None

Match an operation, and optionally perform a rewrite using the rewriter.

Return type:

None

class LowerScfToQ1ScfPass

Bases: OrderedPass, ModulePass

Lower every scf operation in the module to its q1_scf equivalent.

Currently only scf.for is fully implemented. scf.if and scf.while raise PassFailedException if encountered.

apply(ctx, op)
Return type:

None

name: ClassVar[str] = 'lower-scf-to-q1-scf'
class WhileLowering

Bases: RewritePattern

Stub for scf.whileq1_scf.while lowering.

Not yet implemented.

match_and_rewrite(op: Operation, rewriter: PatternRewriter) None

Match an operation, and optionally perform a rewrite using the rewriter.

Return type:

None