Does postgres optimise repeated expressions?
Yes, the expression will be evaluated multiple times. This is easy to test:
test=&gt; \timing
Timing is on.
test=&gt; SELECT pg_sleep(id)
       FROM (VALUES (1), (2), (3)) AS x(id)
       WHERE pg_sleep(id) IS NOT NULL;
 pg_sleep 
══════════
 
 
 
(3 rows)

Time: 12013.768 ms (00:12.014)

If you want to avoid that, use a subquery:
test=&gt; SELECT v
       FROM (SELECT pg_sleep(id) AS v
             FROM (VALUES (1), (2), (3)) AS x(id)) AS t
       WHERE v IS NOT NULL;
 v 
═══
 
 
 
(3 rows)

Time: 6007.817 ms (00:06.008)