From 0eb9ee1a74e58f94e576b66551b9d7f527db47b5 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Fri, 7 Aug 2026 14:04:08 -0400 Subject: [PATCH] Remove unnecessary rule for hvcat_fill! The new version in base should be type stable now --- src/internal_rules/core.jl | 108 +++++++++++++++++++------------------ test/basic.jl | 24 +++++---- 2 files changed, 68 insertions(+), 64 deletions(-) diff --git a/src/internal_rules/core.jl b/src/internal_rules/core.jl index 5aeca8fcb9..c1f2310abc 100644 --- a/src/internal_rules/core.jl +++ b/src/internal_rules/core.jl @@ -486,66 +486,68 @@ function EnzymeRules.reverse( return ntuple(Returns(nothing), Val(2 + length(args))) end -# Force a rule around hvcat_fill as it is type unstable if the tuple is not of the same type (e.g., int, float, int, float) -function EnzymeRules.augmented_primal( - config::EnzymeRules.RevConfig, - func::Const{typeof(Base.hvcat_fill!)}, - ::Type{RT}, - out::Annotation{AT}, - inp::Annotation{BT}, -) where {RT,AT<:Array,BT<:Tuple} - primal = if EnzymeRules.needs_primal(config) - out.val - else - nothing - end - shadow = if EnzymeRules.needs_shadow(config) - out.dval - else - nothing - end - func.val(out.val, inp.val) - return EnzymeRules.AugmentedReturn(primal, shadow, nothing) -end - -function EnzymeRules.reverse( - config::EnzymeRules.RevConfig, - func::Const{typeof(Base.hvcat_fill!)}, - ::Type{RT}, - _, - out::Annotation{AT}, - inp::Annotation{BT}, -) where {RT,AT<:Array,BT<:Tuple} - nr, nc = size(out.val, 1), size(out.val, 2) - for b = 1:EnzymeRules.width(config) - da = if EnzymeRules.width(config) == 1 +if isdefined(Base, :hvcat_fill!) + # Force a rule around hvcat_fill as it is type unstable if the tuple is not of the same type (e.g., int, float, int, float) + function EnzymeRules.augmented_primal( + config::EnzymeRules.RevConfig, + func::Const{typeof(Base.hvcat_fill!)}, + ::Type{RT}, + out::Annotation{AT}, + inp::Annotation{BT}, + ) where {RT,AT<:Array,BT<:Tuple} + primal = if EnzymeRules.needs_primal(config) + out.val + else + nothing + end + shadow = if EnzymeRules.needs_shadow(config) out.dval else - out.dval[b] + nothing end - i = 1 - j = 1 - if (typeof(inp) <: Active) - dinp = ntuple(Val(length(inp.val))) do k - Base.@_inline_meta - res = da[i, j] - da[i, j] = 0 - j += 1 - if j == nc + 1 - i += 1 - j = 1 - end - T = BT.parameters[k] - if T <: AbstractFloat - T(res) - else - T(0) + func.val(out.val, inp.val) + return EnzymeRules.AugmentedReturn(primal, shadow, nothing) + end + + function EnzymeRules.reverse( + config::EnzymeRules.RevConfig, + func::Const{typeof(Base.hvcat_fill!)}, + ::Type{RT}, + _, + out::Annotation{AT}, + inp::Annotation{BT}, + ) where {RT,AT<:Array,BT<:Tuple} + nr, nc = size(out.val, 1), size(out.val, 2) + for b = 1:EnzymeRules.width(config) + da = if EnzymeRules.width(config) == 1 + out.dval + else + out.dval[b] + end + i = 1 + j = 1 + if (typeof(inp) <: Active) + dinp = ntuple(Val(length(inp.val))) do k + Base.@_inline_meta + res = da[i, j] + da[i, j] = 0 + j += 1 + if j == nc + 1 + i += 1 + j = 1 + end + T = BT.parameters[k] + if T <: AbstractFloat + T(res) + else + T(0) + end end + return (nothing, dinp)::Tuple{Nothing,BT} end - return (nothing, dinp)::Tuple{Nothing,BT} end + return (nothing, nothing) end - return (nothing, nothing) end function EnzymeRules.forward(config, ::Const{typeof(Base.finalizer)}, _, f::Const, o) diff --git a/test/basic.jl b/test/basic.jl index 2f73e7718f..e29f75e0e4 100644 --- a/test/basic.jl +++ b/test/basic.jl @@ -618,17 +618,19 @@ end end @testset "hvcat_fill" begin - ar = Matrix{Float64}(undef, 2, 3) - dar = [1.0 2.0 3.0; 4.0 5.0 6.0] - - res = first(Enzyme.autodiff(Reverse, Base.hvcat_fill!, Const, Duplicated(ar, dar), Active((1, 2.2, 3, 4.4, 5, 6.6)))) - - @test res[2][1] == 0 - @test res[2][2] ≈ 2.0 - @test res[2][3] ≈ 0 - @test res[2][4] ≈ 4.0 - @test res[2][5] ≈ 0 - @test res[2][6] ≈ 6.0 + if isdefined(Base, :hvcat_fill!) + ar = Matrix{Float64}(undef, 2, 3) + dar = [1.0 2.0 3.0; 4.0 5.0 6.0] + + res = first(Enzyme.autodiff(Reverse, Base.hvcat_fill!, Const, Duplicated(ar, dar), Active((1, 2.2, 3, 4.4, 5, 6.6)))) + + @test res[2][1] == 0 + @test res[2][2] ≈ 2.0 + @test res[2][3] ≈ 0 + @test res[2][4] ≈ 4.0 + @test res[2][5] ≈ 0 + @test res[2][6] ≈ 6.0 + end end function named_deepcopy(x, nt)