Skip to content

Commit f07d461

Browse files
committed
Allow eliminating nothrow intrinsics during optimization
1 parent ebfbe62 commit f07d461

File tree

5 files changed

+51
-16
lines changed

5 files changed

+51
-16
lines changed

base/compiler/optimize.jl

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,6 @@ function is_pure_intrinsic_infer(f::IntrinsicFunction)
262262
f === Intrinsics.cglobal) # cglobal lookup answer changes at runtime
263263
end
264264

265-
# whether `f` is pure for optimizations
266-
function is_pure_intrinsic_optim(f::IntrinsicFunction)
267-
return !(f === Intrinsics.pointerref || # this one is volatile
268-
f === Intrinsics.pointerset || # this one is never effect-free
269-
f === Intrinsics.llvmcall || # this one is never effect-free
270-
f === Intrinsics.arraylen || # this one is volatile
271-
f === Intrinsics.checked_sdiv_int || # these may throw errors
272-
f === Intrinsics.checked_udiv_int ||
273-
f === Intrinsics.checked_srem_int ||
274-
f === Intrinsics.checked_urem_int ||
275-
f === Intrinsics.cglobal) # cglobal throws an error for symbol-not-found
276-
end
277-
278265
## Computing the cost of a function body
279266

280267
# saturating sum (inputs are nonnegative), prevents overflow with typemax(Int) below

base/compiler/ssair/inlining.jl

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,9 +1047,12 @@ function early_inline_special_case(ir::IRCode, @nospecialize(f), @nospecialize(f
10471047
if isa(etype, Const) # || isconstType(etype)
10481048
val = etype.val
10491049
is_inlineable_constant(val) || return nothing
1050-
if ispuretopfunction(f) ||
1051-
(isa(f, IntrinsicFunction) ? is_pure_intrinsic_optim(f) :
1052-
contains_is(_PURE_BUILTINS, f))
1050+
if isa(f, IntrinsicFunction)
1051+
if is_pure_intrinsic_infer(f) &&
1052+
(intrinsic_nothrow(f) || intrinsic_nothrow(f, atypes[2:end]))
1053+
return quoted(val)
1054+
end
1055+
elseif ispuretopfunction(f) || contains_is(_PURE_BUILTINS, f)
10531056
return quoted(val)
10541057
elseif contains_is(_PURE_OR_ERROR_BUILTINS, f)
10551058
if _builtin_nothrow(f, atypes[2:end], etype)

base/compiler/ssair/queries.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ function stmt_effect_free(@nospecialize(stmt), @nospecialize(rt), src, spvals::S
2222
f = singleton_type(f)
2323
f === nothing && return false
2424
is_return_type(f) && return true
25+
if isa(f, IntrinsicFunction)
26+
is_pure_intrinsic_infer(f) || return false
27+
return intrinsic_nothrow(f) ||
28+
intrinsic_nothrow(f,
29+
Any[argextype(ea[i], src, spvals) for i = 2:length(ea)])
30+
end
2531
contains_is(_PURE_BUILTINS, f) && return true
2632
contains_is(_PURE_OR_ERROR_BUILTINS, f) || return false
2733
rt === Bottom && return false

base/compiler/tfuncs.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,32 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
12401240
return tf[3](argtypes...)
12411241
end
12421242

1243+
# Query whether the given intrinsic is nothrow
1244+
intrinsic_nothrow(f::IntrinsicFunction) = !(
1245+
f === Intrinsics.checked_sdiv_int ||
1246+
f === Intrinsics.checked_udiv_int ||
1247+
f === Intrinsics.checked_srem_int ||
1248+
f === Intrinsics.checked_urem_int ||
1249+
f === Intrinsics.cglobal
1250+
)
1251+
1252+
function intrinsic_nothrow(f::IntrinsicFunction, argtypes::Array{Any, 1})
1253+
# TODO: We could do better for cglobal
1254+
f === Intrinsics.cglobal && return false
1255+
if f === Intrinsics.checked_udiv_int || f === Intrinsics.checked_urem_int || f === Intrinsics.checked_srem_int || f === Intrinsics.checked_sdiv_int
1256+
# Nothrow as long as the second argument is guaranteed not to be zero
1257+
isa(argtypes[2], Const) || return false
1258+
den_val = argtypes[2].val
1259+
den_val !== zero(typeof(den_val)) || return false
1260+
end
1261+
if f === Intrinsics.checked_sdiv_int
1262+
# Nothrow as long as we additionally don't do typemin(T)/-1
1263+
return den_val !== -1 || (isa(argtypes[1], Const) &&
1264+
argtypes[1].val !== typemin(typeof(den_val)))
1265+
end
1266+
return true
1267+
end
1268+
12431269
# TODO: this function is a very buggy and poor model of the return_type function
12441270
# since abstract_call_gf_by_type is a very inaccurate model of _method and of typeinf_type,
12451271
# while this assumes that it is an absolutely precise and accurate and exact model of both

test/inline.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,16 @@ function f_apply_typevar(T)
204204
return T
205205
end
206206
@test length(code_typed(f_apply_typevar, (Type{Any},))[1][1].code) == 1
207+
208+
# check that div can be fully eliminated
209+
function f_div(x)
210+
div(x, 1)
211+
return x
212+
end
213+
@test length(code_typed(f_div, (Int,))[1][1].code) == 1
214+
# ...unless we div by an unknown amount
215+
function f_div(x, y)
216+
div(x, y)
217+
return x
218+
end
219+
@test length(code_typed(f_div, (Int, Int))[1][1].code) > 1

0 commit comments

Comments
 (0)