Skip to content

Commit e5950b7

Browse files
committed
move COMPILER-HOOK to own file
1 parent 9267fd3 commit e5950b7

File tree

3 files changed

+318
-301
lines changed

3 files changed

+318
-301
lines changed

cl-quil.asd

+1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
(:static-file "cs-compile")))
6565
(:file "cfg")
6666
(:file "compilation-methods")
67+
(:file "compiler-hook")
6768
(:module "chip"
6869
:serial t
6970
:components ((:file "chip-specification")

src/compilation-methods.lisp

+2-301
Original file line numberDiff line numberDiff line change
@@ -141,305 +141,6 @@
141141
(not-protoquil () (return-from protoquil-program-p nil)))
142142
t)
143143

144-
;; Forward declaration from compressor.lisp
145-
(declaim (special *compressor-passes*))
144+
;;; COMPILER-HOOK used to be here, but has moved to
145+
;;; compiler-hook.lisp.
146146

147-
(defvar *default-addresser-state-class* 'fidelity-addresser-state)
148-
149-
;; TODO: deal with classical control and basic-blocks
150-
(defun compiler-hook (parsed-program
151-
chip-specification
152-
&key
153-
(protoquil nil)
154-
(rewiring-type (prog-initial-rewiring-heuristic parsed-program chip-specification))
155-
(destructive nil))
156-
"Runs a full compiler pass on a parsed-program object.
157-
158-
Arguments:
159-
160-
- PARSED-PROGRAM: The parsed program to compile
161-
162-
- CHIP-SPECIFICATION: The chip specification describing the target chip
163-
164-
Keyword arguments:
165-
166-
- PROTOQUIL: Whether the input and output programs should conform to protoquil restrictions
167-
168-
- REWIRING-TYPE: The scheme by which logical qubits are mapped (rewired) to physical qubits
169-
170-
- DESTRUCTIVE: Default NIL. If T, the input program is mutated and after compilation contains the compiled program. Otherwise, a copy is made of the input program and the compiled copy is returned. Note that for large programs you may prefer to mutate the original program rather than waste time copying it. For example, the server interface will mutate the program since it has no use for the unmolested original program after compilation.
171-
172-
Returns a value list: (processed-program, of type parsed-program
173-
topological-swaps, of type integer
174-
unpreserved-block-duration, of type real)"
175-
(format-noise "COMPILER-HOOK: entrance.")
176-
177-
(unless destructive
178-
(setf parsed-program (copy-instance parsed-program)))
179-
180-
;; Technically this could be fused with the above, but remains
181-
;; separate for clarity. We should not compress if the rewiring type
182-
;; is naive, or the program uses more qubits than are available on
183-
;; the chip (duh), or if the program has blocks of preserved qubits.
184-
(when (and (not (eql ':naive rewiring-type))
185-
(> (qubits-needed parsed-program)
186-
(length (chip-spec-live-qubits chip-specification)))
187-
(not (parsed-program-has-preserve-blocks-p parsed-program)))
188-
(setf parsed-program (compress-qubits parsed-program)))
189-
190-
(warm-chip-spec-lookup-cache chip-specification)
191-
192-
;; we disallow compilation of programs that use memory aliasing
193-
(loop :for mdesc :in (parsed-program-memory-definitions parsed-program)
194-
:when (memory-descriptor-sharing-parent mdesc)
195-
:do (error "Programs with aliased memory are currently unsupported."))
196-
197-
;; check that the program obeys the dead qubit rule
198-
(when (eql ':naive rewiring-type)
199-
(check-program-skips-dead-qubits parsed-program chip-specification))
200-
201-
;; check that a protoquil program is in fact protoquil
202-
(when protoquil
203-
(check-protoquil-program parsed-program))
204-
205-
;; now we walk the CFG associated to the program
206-
(multiple-value-bind (initial-rewiring l2p-components)
207-
(prog-initial-rewiring parsed-program chip-specification
208-
:type rewiring-type)
209-
(let* ((cfg (program-cfg parsed-program :dce t))
210-
;; this is a list of pairs (block-to-be-traversed registrant)
211-
(block-stack (list (list (entry-point cfg) nil)))
212-
(topological-swaps 0)
213-
(unpreserved-duration 0))
214-
215-
;; In any rewiring scheme a preserved block must not touch dead
216-
;; qubits.
217-
(check-preserved-blocks-skip-dead-qubits cfg chip-specification)
218-
219-
(let ((*print-pretty* nil))
220-
(format-noise "COMPILER-HOOK: initial rewiring ~A" initial-rewiring))
221-
222-
;; if we are expecting to manipulate protoquil, we segment the program-final
223-
;; sequence of MEASURE instructions out into a separate CFG block, so that
224-
;; the greedy addresser doesn't try to move them forward.
225-
(when protoquil
226-
(let (final-blk
227-
(instrs-measures nil)
228-
(instrs-rest nil)
229-
(new-final-blk (make-instance 'basic-block)))
230-
;; find the exit block
231-
(dolist (blk (cfg-blocks cfg))
232-
(when (typep (outgoing blk) 'terminating-edge)
233-
(setf final-blk blk)))
234-
;; segments its instructions into the MEASURES and the non-MEASURES
235-
(loop :for instr :across (basic-block-code final-blk)
236-
:if (typep instr 'measure)
237-
:do (push instr instrs-measures)
238-
:else
239-
:do (push instr instrs-rest))
240-
;; store its non-MEASURE instructions back into the block
241-
(setf (basic-block-code final-blk) (coerce (nreverse instrs-rest) 'vector))
242-
;; store its MEASURE instructions into the cordoned-off block
243-
(setf (basic-block-code new-final-blk) (coerce (nreverse instrs-measures) 'vector))
244-
;; place the new block in the CFG and re-link them
245-
(push new-final-blk (cfg-blocks cfg))
246-
(link-blocks new-final-blk terminating-edge)
247-
(link-blocks final-blk (unconditional-edge new-final-blk))))
248-
249-
;; these local functions describe how we traverse / modify the CFG.
250-
(labels
251-
;; this function introduces a new block that cajoles the compiler into
252-
;; introducing rewiring SWAPs to match the exit/enter rewires across
253-
;; a jump REGISTRANT --> BLK
254-
((edge-to-rewiring-block (blk registrant target-rewiring)
255-
(let* ((pseudoinstruction (make-instance 'application-force-rewiring
256-
:target target-rewiring))
257-
(fresh-block (make-instance 'basic-block
258-
:code (make-array 1 :initial-element pseudoinstruction)
259-
:incoming (list registrant)
260-
:outgoing (unconditional-edge blk))))
261-
;; push it into the CFG
262-
(push fresh-block (cfg-blocks cfg))
263-
;; update the target's parents
264-
(setf (incoming blk)
265-
(list* fresh-block (remove registrant (incoming blk))))
266-
;; and update the source's outgoing edge
267-
(setf (outgoing registrant)
268-
(redirect-edge blk fresh-block (outgoing registrant)))
269-
;; try again, but with this new jump
270-
(push (list fresh-block registrant) block-stack)
271-
(format-noise "COMPILER-HOOK: Introduced ~A to deal with the rewiring."
272-
(basic-block-name fresh-block))))
273-
274-
(touch-preserved-block (blk)
275-
;; if so, then we don't have any business compiling it. treat
276-
;; it as marked, with the identity rewiring on both ends,
277-
;; and proceed
278-
(setf (basic-block-in-rewiring blk) (make-rewiring (chip-spec-n-qubits chip-specification)))
279-
(setf (basic-block-out-rewiring blk) (make-rewiring (chip-spec-n-qubits chip-specification)))
280-
(change-class blk 'basic-block))
281-
282-
(touch-unpreserved-block (blk registrant)
283-
;; actually process this block
284-
(multiple-value-bind (chip-schedule initial-l2p final-l2p)
285-
(do-greedy-addressing
286-
(make-instance *default-addresser-state-class*
287-
:chip-spec chip-specification
288-
:l2p-components l2p-components
289-
:initial-l2p (if registrant
290-
(basic-block-in-rewiring blk)
291-
initial-rewiring))
292-
(coerce (basic-block-code blk) 'list)
293-
:use-free-swaps (null registrant))
294-
(let* ((duration (chip-schedule-duration chip-schedule))
295-
(straight-line-quil (chip-schedule-to-straight-quil chip-schedule))
296-
(local-topological-swaps (count-if #'swap-application-p straight-line-quil))
297-
(fully-native-quil (expand-to-native-instructions straight-line-quil chip-specification))
298-
(processed-quil fully-native-quil))
299-
;; This is useful for debugging, but can be
300-
;; extremely, extremely noisy.
301-
#+#:ignore
302-
(progn
303-
(format-noise "COMPILER-HOOK: Finished addressing, got:")
304-
(cond
305-
((null processed-quil)
306-
(format-noise " *empty program*"))
307-
(t
308-
(format-noise "~{ ~/quil:instruction-fmt/~%~}" processed-quil))))
309-
(dotimes (n *compressor-passes*)
310-
(format-noise "COMPILER-HOOK: Compressing, pass ~D/~D." (1+ n) *compressor-passes*)
311-
(setf processed-quil
312-
(compress-instructions processed-quil chip-specification
313-
:protoquil (null registrant))))
314-
;; This is useful for debugging, but can be
315-
;; extremely, extremely noisy.
316-
#+#:ignore
317-
(progn
318-
(format-noise "COMPILER-HOOK: Finished compressing, got:")
319-
(cond
320-
((null processed-quil)
321-
(format-noise " *empty program*"))
322-
(t
323-
(format-noise "~{ ~/quil:instruction-fmt/~%~}" processed-quil))))
324-
;; we're done processing. store the results back into the CFG block.
325-
(setf (basic-block-code blk) processed-quil)
326-
(setf (basic-block-in-rewiring blk) initial-l2p)
327-
(setf (basic-block-out-rewiring blk) final-l2p)
328-
(incf topological-swaps local-topological-swaps)
329-
(incf unpreserved-duration duration)
330-
(format-noise "COMPILER-HOOK: Done processing block ~A." (basic-block-name blk)))))
331-
332-
(touch-reset-block (blk)
333-
;; actually process this block
334-
(multiple-value-bind (chip-schedule initial-l2p final-l2p)
335-
(do-greedy-addressing
336-
(make-instance *default-addresser-state-class*
337-
:chip-spec chip-specification
338-
:l2p-components l2p-components
339-
:initial-l2p (prog-initial-rewiring parsed-program chip-specification
340-
:type rewiring-type))
341-
(coerce (basic-block-code blk) 'list))
342-
(let* ((duration (chip-schedule-duration chip-schedule))
343-
(straight-line-quil (chip-schedule-to-straight-quil chip-schedule))
344-
(local-topological-swaps (count-if #'swap-application-p straight-line-quil))
345-
(fully-native-quil (expand-to-native-instructions straight-line-quil chip-specification))
346-
(processed-quil fully-native-quil))
347-
(dotimes (n *compressor-passes*)
348-
(format-noise "COMPILER-HOOK: Compressing, pass ~D/~D." (1+ n) *compressor-passes*)
349-
(setf processed-quil
350-
(compress-instructions processed-quil chip-specification
351-
:protoquil t)))
352-
;; we're done processing. store the results back into the CFG block.
353-
(setf (basic-block-code blk) processed-quil)
354-
(setf (basic-block-in-rewiring blk) initial-l2p)
355-
(setf (basic-block-out-rewiring blk) final-l2p)
356-
(incf topological-swaps local-topological-swaps)
357-
(incf unpreserved-duration duration)
358-
(format-noise "COMPILER-HOOK: Done processing block ~A." (basic-block-name blk)))))
359-
360-
(process-block (blk registrant)
361-
;; if this block is expecting a rewiring, we should make sure the
362-
;; exit/enter rewirings match.
363-
(when (and registrant
364-
(not (typep blk 'reset-block))
365-
(or (basic-block-in-rewiring blk)
366-
(typep blk 'preserved-block)))
367-
;; compare incoming and outgoing l2ps.
368-
(let ((final-l2p (basic-block-out-rewiring registrant))
369-
(initial-l2p (if (typep blk 'preserved-block)
370-
(make-rewiring (chip-spec-n-qubits chip-specification))
371-
(basic-block-in-rewiring blk))))
372-
(format-noise "COMPILER-HOOK: Matching rewiring from ~A (~A) to ~A (~A)."
373-
(basic-block-name registrant)
374-
final-l2p
375-
(basic-block-name blk)
376-
initial-l2p)
377-
;; if they're the same, proceed with analyzing the jump
378-
(unless (equalp final-l2p initial-l2p)
379-
(return-from process-block
380-
(edge-to-rewiring-block blk registrant initial-l2p)))))
381-
382-
;; the source's exit rewiring now matches the target's entry rewiring.
383-
;; if this block has already been visited, skip it.
384-
(when (basic-block-in-rewiring blk)
385-
(return-from process-block))
386-
387-
(let ((*print-pretty* nil))
388-
(format-noise "COMPILER-HOOK: Visiting ~A for the first time, coming from ~A (~A)."
389-
(basic-block-name blk)
390-
(and registrant (basic-block-name registrant))
391-
(and registrant (basic-block-out-rewiring registrant))))
392-
;; set the block-initial-l2p, forced by the previous block
393-
(when registrant
394-
(setf (basic-block-in-rewiring blk)
395-
(basic-block-out-rewiring registrant)))
396-
;; add the block's children to the traversal stack
397-
(adt:match outgoing-edge (outgoing blk)
398-
((conditional-edge _ true-target false-target)
399-
(push (list true-target blk) block-stack)
400-
(push (list false-target blk) block-stack))
401-
((unconditional-edge target)
402-
(push (list target blk) block-stack))
403-
(terminating-edge nil))
404-
405-
;; now fork based on whether the block is PRESERVEd.
406-
;; note that touch-* will set block-initial-l2p, which indicates the block has been visited
407-
(typecase blk
408-
(preserved-block
409-
(touch-preserved-block blk))
410-
(reset-block
411-
(touch-reset-block blk))
412-
(otherwise
413-
(touch-unpreserved-block blk registrant))))
414-
415-
;; this is the main loop that pushes through the CFG
416-
(exhaust-stack ()
417-
(loop :until (endp block-stack) :do
418-
(apply #'process-block (pop block-stack)))))
419-
420-
;; kick off the traversal
421-
(exhaust-stack)
422-
423-
;; one more pass of CFG collapse
424-
(simplify-cfg cfg)
425-
426-
(let ((processed-program (reconstitute-program cfg)))
427-
;; Keep global PRAGMAS in the code, at the top of the file.
428-
(setf (parsed-program-executable-code processed-program)
429-
(concatenate
430-
'vector
431-
(remove-if-not #'global-pragma-instruction-p
432-
(parsed-program-executable-code parsed-program))
433-
(parsed-program-executable-code processed-program)))
434-
;; retain the old circuit and gate definitions
435-
(setf (parsed-program-gate-definitions processed-program)
436-
(parsed-program-gate-definitions parsed-program))
437-
(setf (parsed-program-circuit-definitions processed-program)
438-
(parsed-program-circuit-definitions parsed-program))
439-
(setf (parsed-program-memory-definitions processed-program)
440-
(parsed-program-memory-definitions parsed-program))
441-
;; ... and output the results.
442-
(values
443-
processed-program
444-
topological-swaps
445-
unpreserved-duration))))))

0 commit comments

Comments
 (0)