Skip to content

Commit 07a16d6

Browse files
authored
Change lowering of gc preserve (#34379)
This fixes #34247 by changing the way gc preserve is lowered. Instead of lowering it in a macro, lower it in the frontend. This allows us to use an SSA value directly for the return token of the gc begin expression. This bypasses the slot-renaming pass of the compiler, thus preventing the compiler from trying to save and restore the token. Of course, this kind of code would generally not be legal (because it uses an SSA value outside of the regular domination relation), but since this is a julia restriction, not an LLVM restriction, we can simply exempt gc_begin tokens from this particular validation. This works fine at the LLVM level also, because it doesn't have this particular restriction. It also doesn't have the same correctness problems as doing the same for non-token values, as the tokens get lowered away by the try/catch lowering before reaching the LLVM backend.
1 parent edac6f7 commit 07a16d6

File tree

4 files changed

+36
-16
lines changed

4 files changed

+36
-16
lines changed

base/compiler/ssair/verify.jl

+12-4
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ function check_op(ir::IRCode, domtree::DomTree, @nospecialize(op), use_bb::Int,
2929
end
3030
else
3131
if !dominates(domtree, def_bb, use_bb) && !(bb_unreachable(domtree, def_bb) && bb_unreachable(domtree, use_bb))
32+
# At the moment, we allow GC preserve tokens outside the standard domination notion
3233
#@Base.show ir
3334
@verify_error "Basic Block $def_bb does not dominate block $use_bb (tried to use value $(op.id))"
3435
error()
@@ -189,10 +190,17 @@ function verify_ir(ir::IRCode)
189190
end
190191
end
191192
end
192-
if isa(stmt, Expr) && stmt.head === :(=)
193-
if stmt.args[1] isa SSAValue
194-
@verify_error "SSAValue as assignment LHS"
195-
error()
193+
if isa(stmt, Expr)
194+
if stmt.head === :(=)
195+
if stmt.args[1] isa SSAValue
196+
@verify_error "SSAValue as assignment LHS"
197+
error()
198+
end
199+
elseif stmt.head === :gc_preserve_end
200+
# We allow gc_preserve_end tokens to span across try/catch
201+
# blocks, which isn't allowed for regular SSA values, so
202+
# we skip the validation below.
203+
continue
196204
end
197205
end
198206
for op in userefs(stmt)

base/gcutils.jl

+1-7
Original file line numberDiff line numberDiff line change
@@ -90,13 +90,7 @@ macro preserve(args...)
9090
for x in syms
9191
isa(x, Symbol) || error("Preserved variable must be a symbol")
9292
end
93-
s, r = gensym(), gensym()
94-
esc(quote
95-
$s = $(Expr(:gc_preserve_begin, syms...))
96-
$r = $(args[end])
97-
$(Expr(:gc_preserve_end, s))
98-
$r
99-
end)
93+
esc(Expr(:gc_preserve, args[end], syms...))
10094
end
10195

10296
"""

src/julia-syntax.scm

+14-5
Original file line numberDiff line numberDiff line change
@@ -2318,7 +2318,18 @@
23182318
;; TODO: this is a hack to lower simple comprehensions to loops very
23192319
;; early, to greatly reduce the # of functions and load on the compiler
23202320
(lower-comprehension (cadr e) (cadr (caddr e)) ranges))))
2321-
`(call (top collect) ,(cadr e) ,(caddr e)))))))
2321+
`(call (top collect) ,(cadr e) ,(caddr e)))))
2322+
2323+
'gc_preserve
2324+
(lambda (e)
2325+
(let* ((s (make-ssavalue))
2326+
(r (gensy)))
2327+
`(block
2328+
(= ,s (gc_preserve_begin ,@(cddr e)))
2329+
(= ,r ,(expand-forms (cadr e)))
2330+
(gc_preserve_end ,s)
2331+
,r)))
2332+
))
23222333

23232334
(define (has-return? e)
23242335
(expr-contains-p return? e (lambda (x) (not (function-def? x)))))
@@ -4009,10 +4020,8 @@ f(x) = yt(x)
40094020
'(null))
40104021

40114022
((gc_preserve_begin)
4012-
(let ((s (make-ssavalue))
4013-
(args (compile-args (cdr e) break-labels linearize-args)))
4014-
(emit `(= ,s ,(cons (car e) args)))
4015-
s))
4023+
(let ((args (compile-args (cdr e) break-labels linearize-args)))
4024+
(cons (car e) args)))
40164025

40174026
;; metadata expressions
40184027
((line meta inbounds loopinfo gc_preserve_end aliasscope popaliasscope)

test/core.jl

+9
Original file line numberDiff line numberDiff line change
@@ -7164,3 +7164,12 @@ function mre34206(a, n)
71647164
return b[1].offset1
71657165
end
71667166
@test mre34206([44], 1) == 0
7167+
7168+
# Issue #34247
7169+
function f34247(a)
7170+
GC.@preserve a try
7171+
catch
7172+
end
7173+
true
7174+
end
7175+
@test f34247("")

0 commit comments

Comments
 (0)