flan/test/programs/self-read.flan
Joseph Ferano 9194f918fc An aggregate that reads its own destination sees the old value, on x86 too
x86 built a settling right-hand side straight into its destination, so (set p (P {.a (.b p) .b (.a p)})) wrote .a and read it back for .b. assign now also asks whether the value reads storage the destination lies in, and goes through the temporary when it does. The global-initialiser entry was already closed by startup_plan's Set; the unrooted-temporary entry turns out to be a both-backends rooting gap and stays open for a decision.
2026-09-25 07:05:18 +07:00

63 lines
2.2 KiB
Plaintext

;;;; An aggregate whose value reads the place it is assigned to sees the old
;;;; value of that place, in every field.
;;;;
;;;; (set p (P {.a (.b p) .b (.a p)})) swaps the two fields. It does only if
;;;; the whole right-hand side is read before any of it is stored. A backend
;;;; that builds the struct straight into [p] writes [.a] first, and the read
;;;; of [(.a p)] for [.b] then sees the new value: the answer comes back 2 2
;;;; rather than 2 1.
;;;;
;;;; Each row is a different destination: a global, a field of a global, a
;;;; local, a field of a local, a place behind a pointer, a variable read
;;;; through a pointer that points at it, and a local rebound inside a loop
;;;; whose previous turn the new value reads. The last row reads a different
;;;; variable, which is the case still built in place.
(defstruct P [a i32 b i32])
(defstruct Q [tag i32 inner P])
(defonce g P (P {.a 1 .b 2}))
(defonce gq Q (Q {.tag 0 .inner (P {.a 1 .b 2})}))
(defn show [p P] ()
(print (.a p)) (print " ") (print (.b p)) (print "\n"))
(defn main [] ()
;; A global.
(set g (P {.a (.b g) .b (.a g)}))
(show g)
;; A field of a global.
(set (.inner gq) (P {.a (.b (.inner gq)) .b (.a (.inner gq))}))
(show (.inner gq))
(let [p (P {.a 1 .b 2})
q (Q {.tag 0 .inner (P {.a 1 .b 2})})
r (P {.a 1 .b 2})
s (P {.a 1 .b 2})
t (P {.a 1 .b 2})
other (P {.a 3 .b 4})]
;; A local.
(set p (P {.a (.b p) .b (.a p)}))
(show p)
;; A field of a local.
(set (.inner q) (P {.a (.b (.inner q)) .b (.a (.inner q))}))
(show (.inner q))
;; A place behind a pointer, reading the variable it points at.
(let [pr (addr r)]
(set (deref pr) (P {.a (.b r) .b (.a r)}))
(show r))
;; A variable, reading itself through a pointer.
(let [ps (addr s)]
(set s (P {.a (.b (deref ps)) .b (.a (deref ps))}))
(show s))
;; A local rebound in a loop, reading its own previous turn.
(let [pt (addr t)
i 0]
(while (< i 2)
(let [u (P {.a (.b (deref pt)) .b (.a (deref pt))})]
(show u)
(set pt (addr u)))
(set i (+ i 1))))
;; No self-read.
(set p (P {.a (.b other) .b (.a other)}))
(show p)))