From 7596c18d57df29b5ffa84bac61b4036f2fc39e45 Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 7 May 2026 15:32:16 +0200 Subject: [PATCH 1/4] Add support for ConstantRange and ConstantRangeList attribute kinds LLVM 17+ introduced `range` (ConstantRange) and LLVM 20+ introduced `initializes` (ConstantRangeList) attribute kinds that the C API's LLVMIsEnumAttribute/LLVMIsStringAttribute/LLVMIsTypeAttribute do not recognize, causing `Attribute(ref)` to error with "unknown attribute kind". Add LLVMIsConstantRangeAttribute (LLVM >= 17) and LLVMIsConstantRangeListAttribute (LLVM >= 20) to LLVMExtra, expose them in the per-version Julia bindings, and use them to dispatch to new ConstantRangeAttribute and ConstantRangeListAttribute types. Also adds a ConstantRangeAttribute constructor (LLVM >= 19, when LLVMCreateConstantRangeAttribute was upstreamed via llvm/llvm-project#90505) and a test. Co-Authored-By: Claude Sonnet 4.6 --- deps/LLVMExtra/include/LLVMExtra.h | 8 +++++++ deps/LLVMExtra/lib/Core.cpp | 21 ++++++++++++++++++ lib/17/libLLVM_extra.jl | 4 ++++ lib/18/libLLVM_extra.jl | 4 ++++ lib/19/libLLVM_extra.jl | 4 ++++ lib/20/libLLVM_extra.jl | 8 +++++++ lib/21/libLLVM_extra.jl | 8 +++++++ src/core/attributes.jl | 35 ++++++++++++++++++++++++++++++ test/core.jl | 10 +++++++++ 9 files changed, 102 insertions(+) diff --git a/deps/LLVMExtra/include/LLVMExtra.h b/deps/LLVMExtra/include/LLVMExtra.h index c7ec78be..cb57f1c2 100644 --- a/deps/LLVMExtra/include/LLVMExtra.h +++ b/deps/LLVMExtra/include/LLVMExtra.h @@ -84,6 +84,14 @@ void LLVMDestroyConstant(LLVMValueRef Const); LLVMTypeRef LLVMGetFunctionType(LLVMValueRef Fn); LLVMTypeRef LLVMGetGlobalValueType(LLVMValueRef Fn); +// Attribute type detection (ConstantRange/ConstantRangeList kinds not exposed in C API) +#if LLVM_VERSION_MAJOR >= 17 +LLVMBool LLVMIsConstantRangeAttribute(LLVMAttributeRef A); +#endif +#if LLVM_VERSION_MAJOR >= 20 +LLVMBool LLVMIsConstantRangeListAttribute(LLVMAttributeRef A); +#endif + // Bug fixes #if LLVM_VERSION_MAJOR < 20 // llvm/llvm-project#105521 void LLVMSetInitializer2(LLVMValueRef GlobalVar, LLVMValueRef ConstantVal); diff --git a/deps/LLVMExtra/lib/Core.cpp b/deps/LLVMExtra/lib/Core.cpp index a11222d4..d4c20ae1 100644 --- a/deps/LLVMExtra/lib/Core.cpp +++ b/deps/LLVMExtra/lib/Core.cpp @@ -295,6 +295,27 @@ LLVMTypeRef LLVMGetGlobalValueType(LLVMValueRef GV) { } +// +// Attribute type detection +// + +#if LLVM_VERSION_MAJOR >= 17 + +LLVMBool LLVMIsConstantRangeAttribute(LLVMAttributeRef A) { + return unwrap(A).isConstantRangeAttribute(); +} + +#endif + +#if LLVM_VERSION_MAJOR >= 20 + +LLVMBool LLVMIsConstantRangeListAttribute(LLVMAttributeRef A) { + return unwrap(A).isConstantRangeListAttribute(); +} + +#endif + + // // Bug fixes // diff --git a/lib/17/libLLVM_extra.jl b/lib/17/libLLVM_extra.jl index b0361b91..f6876203 100644 --- a/lib/17/libLLVM_extra.jl +++ b/lib/17/libLLVM_extra.jl @@ -110,6 +110,10 @@ function LLVMGetGlobalValueType(Fn) ccall((:LLVMGetGlobalValueType, libLLVMExtra), LLVMTypeRef, (LLVMValueRef,), Fn) end +function LLVMIsConstantRangeAttribute(A) + ccall((:LLVMIsConstantRangeAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + function LLVMSetInitializer2(GlobalVar, ConstantVal) ccall((:LLVMSetInitializer2, libLLVMExtra), Cvoid, (LLVMValueRef, LLVMValueRef), GlobalVar, ConstantVal) end diff --git a/lib/18/libLLVM_extra.jl b/lib/18/libLLVM_extra.jl index 57a78abf..be9d885a 100644 --- a/lib/18/libLLVM_extra.jl +++ b/lib/18/libLLVM_extra.jl @@ -110,6 +110,10 @@ function LLVMGetGlobalValueType(Fn) ccall((:LLVMGetGlobalValueType, libLLVMExtra), LLVMTypeRef, (LLVMValueRef,), Fn) end +function LLVMIsConstantRangeAttribute(A) + ccall((:LLVMIsConstantRangeAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + function LLVMSetInitializer2(GlobalVar, ConstantVal) ccall((:LLVMSetInitializer2, libLLVMExtra), Cvoid, (LLVMValueRef, LLVMValueRef), GlobalVar, ConstantVal) end diff --git a/lib/19/libLLVM_extra.jl b/lib/19/libLLVM_extra.jl index 57a78abf..be9d885a 100644 --- a/lib/19/libLLVM_extra.jl +++ b/lib/19/libLLVM_extra.jl @@ -110,6 +110,10 @@ function LLVMGetGlobalValueType(Fn) ccall((:LLVMGetGlobalValueType, libLLVMExtra), LLVMTypeRef, (LLVMValueRef,), Fn) end +function LLVMIsConstantRangeAttribute(A) + ccall((:LLVMIsConstantRangeAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + function LLVMSetInitializer2(GlobalVar, ConstantVal) ccall((:LLVMSetInitializer2, libLLVMExtra), Cvoid, (LLVMValueRef, LLVMValueRef), GlobalVar, ConstantVal) end diff --git a/lib/20/libLLVM_extra.jl b/lib/20/libLLVM_extra.jl index 83c6a6ac..d072fa3d 100644 --- a/lib/20/libLLVM_extra.jl +++ b/lib/20/libLLVM_extra.jl @@ -110,6 +110,14 @@ function LLVMGetGlobalValueType(Fn) ccall((:LLVMGetGlobalValueType, libLLVMExtra), LLVMTypeRef, (LLVMValueRef,), Fn) end +function LLVMIsConstantRangeAttribute(A) + ccall((:LLVMIsConstantRangeAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + +function LLVMIsConstantRangeListAttribute(A) + ccall((:LLVMIsConstantRangeListAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + function LLVMGetMDString2(MD, Length) ccall((:LLVMGetMDString2, libLLVMExtra), Cstring, (LLVMMetadataRef, Ptr{Cuint}), MD, Length) end diff --git a/lib/21/libLLVM_extra.jl b/lib/21/libLLVM_extra.jl index 62dfdda8..427e7576 100644 --- a/lib/21/libLLVM_extra.jl +++ b/lib/21/libLLVM_extra.jl @@ -110,6 +110,14 @@ function LLVMGetGlobalValueType(Fn) ccall((:LLVMGetGlobalValueType, libLLVMExtra), LLVMTypeRef, (LLVMValueRef,), Fn) end +function LLVMIsConstantRangeAttribute(A) + ccall((:LLVMIsConstantRangeAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + +function LLVMIsConstantRangeListAttribute(A) + ccall((:LLVMIsConstantRangeListAttribute, libLLVMExtra), LLVMBool, (LLVMAttributeRef,), A) +end + function LLVMGetMDString2(MD, Length) ccall((:LLVMGetMDString2, libLLVMExtra), Cstring, (LLVMMetadataRef, Ptr{Cuint}), MD, Length) end diff --git a/src/core/attributes.jl b/src/core/attributes.jl index abc20087..219fb526 100644 --- a/src/core/attributes.jl +++ b/src/core/attributes.jl @@ -3,6 +3,7 @@ export Attribute, EnumAttribute, StringAttribute, TypeAttribute, + ConstantRangeAttribute, ConstantRangeListAttribute, kind, value abstract type Attribute end @@ -21,6 +22,16 @@ end ref::API.LLVMAttributeRef end +# ConstantRange attribute kind (e.g. `range`, introduced in LLVM 17). +@checked struct ConstantRangeAttribute <: Attribute + ref::API.LLVMAttributeRef +end + +# ConstantRangeList attribute kind (e.g. `initializes`, introduced in LLVM 20). +@checked struct ConstantRangeListAttribute <: Attribute + ref::API.LLVMAttributeRef +end + # TODO: make the identify mechanism flexible enough to cover cases like this one, # and not only Value and Type @@ -33,6 +44,12 @@ function Attribute(ref::API.LLVMAttributeRef) elseif Bool(API.LLVMIsTypeAttribute(ref)) return TypeAttribute(ref) else + @static if version() >= v"20" + Bool(API.LLVMIsConstantRangeAttribute(ref)) && return ConstantRangeAttribute(ref) + Bool(API.LLVMIsConstantRangeListAttribute(ref)) && return ConstantRangeListAttribute(ref) + elseif version() >= v"17" + Bool(API.LLVMIsConstantRangeAttribute(ref)) && return ConstantRangeAttribute(ref) + end error("unknown attribute kind") end end @@ -87,3 +104,21 @@ kind(attr::TypeAttribute) = API.LLVMGetEnumAttributeKind(attr) function value(attr::TypeAttribute) return LLVMType(API.LLVMGetTypeAttributeValue(attr)) end + +## constant range attribute + +if version() >= v"19" + function ConstantRangeAttribute(kind::String, nbits::Integer, + lower::Vector{UInt64}, upper::Vector{UInt64}) + enum_kind = API.LLVMGetEnumAttributeKindForName(kind, Csize_t(length(kind))) + return ConstantRangeAttribute( + API.LLVMCreateConstantRangeAttribute(context(), enum_kind, Cuint(nbits), + lower, upper)) + end +end + +kind(attr::ConstantRangeAttribute) = API.LLVMGetEnumAttributeKind(attr) + +## constant range list attribute + +kind(attr::ConstantRangeListAttribute) = API.LLVMGetEnumAttributeKind(attr) diff --git a/test/core.jl b/test/core.jl index b45625ab..9a535a31 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1404,6 +1404,16 @@ end delete!(instr_attrs, instr_attr) @test length(instr_attrs) == 0 end + + if LLVM.version() >= v"19" + let attr = ConstantRangeAttribute("range", 32, UInt64[0], UInt64[100]) + @test attr isa ConstantRangeAttribute + @test kind(attr) != 0 + push!(return_attributes(fn), attr) + collected = collect(return_attributes(fn)) + @test any(a -> a isa ConstantRangeAttribute, collected) + end + end end for i in 1:length(parameters(fn)) From 0546d060404565256fd2ebbe5ac4d2a6f399f45c Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 7 May 2026 16:08:47 +0200 Subject: [PATCH 2/4] Fix ConstantRangeAttribute test leaving return_attributes non-empty Delete the attribute after testing it so the subsequent length == 0 check passes on LLVM >= 19. Co-Authored-By: Claude Sonnet 4.6 --- test/core.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/core.jl b/test/core.jl index 9a535a31..ecedb696 100644 --- a/test/core.jl +++ b/test/core.jl @@ -1412,6 +1412,7 @@ end push!(return_attributes(fn), attr) collected = collect(return_attributes(fn)) @test any(a -> a isa ConstantRangeAttribute, collected) + delete!(return_attributes(fn), attr) end end end From 2880585383d23f3e602e2ff4684889cdf591176e Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 7 May 2026 16:10:16 +0200 Subject: [PATCH 3/4] Fix isConstantRangeAttribute version guards: >= 17 should be >= 19 The function was added to LLVM main in March 2024 (after LLVM 18 branched) and first appeared in LLVM 19.x. Building with LLVM 18 fails because isConstantRangeAttribute() does not exist in that release. Co-Authored-By: Claude Sonnet 4.6 --- deps/LLVMExtra/include/LLVMExtra.h | 2 +- deps/LLVMExtra/lib/Core.cpp | 2 +- src/core/attributes.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/deps/LLVMExtra/include/LLVMExtra.h b/deps/LLVMExtra/include/LLVMExtra.h index cb57f1c2..06833a3a 100644 --- a/deps/LLVMExtra/include/LLVMExtra.h +++ b/deps/LLVMExtra/include/LLVMExtra.h @@ -85,7 +85,7 @@ LLVMTypeRef LLVMGetFunctionType(LLVMValueRef Fn); LLVMTypeRef LLVMGetGlobalValueType(LLVMValueRef Fn); // Attribute type detection (ConstantRange/ConstantRangeList kinds not exposed in C API) -#if LLVM_VERSION_MAJOR >= 17 +#if LLVM_VERSION_MAJOR >= 19 LLVMBool LLVMIsConstantRangeAttribute(LLVMAttributeRef A); #endif #if LLVM_VERSION_MAJOR >= 20 diff --git a/deps/LLVMExtra/lib/Core.cpp b/deps/LLVMExtra/lib/Core.cpp index d4c20ae1..c8613f26 100644 --- a/deps/LLVMExtra/lib/Core.cpp +++ b/deps/LLVMExtra/lib/Core.cpp @@ -299,7 +299,7 @@ LLVMTypeRef LLVMGetGlobalValueType(LLVMValueRef GV) { // Attribute type detection // -#if LLVM_VERSION_MAJOR >= 17 +#if LLVM_VERSION_MAJOR >= 19 LLVMBool LLVMIsConstantRangeAttribute(LLVMAttributeRef A) { return unwrap(A).isConstantRangeAttribute(); diff --git a/src/core/attributes.jl b/src/core/attributes.jl index 219fb526..8dfbd205 100644 --- a/src/core/attributes.jl +++ b/src/core/attributes.jl @@ -47,7 +47,7 @@ function Attribute(ref::API.LLVMAttributeRef) @static if version() >= v"20" Bool(API.LLVMIsConstantRangeAttribute(ref)) && return ConstantRangeAttribute(ref) Bool(API.LLVMIsConstantRangeListAttribute(ref)) && return ConstantRangeListAttribute(ref) - elseif version() >= v"17" + elseif version() >= v"19" Bool(API.LLVMIsConstantRangeAttribute(ref)) && return ConstantRangeAttribute(ref) end error("unknown attribute kind") From eb06689a9475ad4f94b6d0539acbb573bf60b4be Mon Sep 17 00:00:00 2001 From: Valentin Churavy Date: Thu, 7 May 2026 18:05:42 +0200 Subject: [PATCH 4/4] Add delete! for ConstantRangeAttribute and ConstantRangeListAttribute Both FunctionAttrSet and CallSiteAttrSet were missing delete! methods for these attribute kinds, causing a MethodError in the test suite. Co-Authored-By: Claude Sonnet 4.6 --- src/core/function.jl | 6 ++++++ src/core/instructions.jl | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/core/function.jl b/src/core/function.jl index 943e169d..2c5d51e6 100644 --- a/src/core/function.jl +++ b/src/core/function.jl @@ -166,6 +166,12 @@ Base.delete!(iter::FunctionAttrSet, attr::EnumAttribute) = Base.delete!(iter::FunctionAttrSet, attr::TypeAttribute) = API.LLVMRemoveEnumAttributeAtIndex(iter.f, iter.idx, kind(attr)) +Base.delete!(iter::FunctionAttrSet, attr::ConstantRangeAttribute) = + API.LLVMRemoveEnumAttributeAtIndex(iter.f, iter.idx, kind(attr)) + +Base.delete!(iter::FunctionAttrSet, attr::ConstantRangeListAttribute) = + API.LLVMRemoveEnumAttributeAtIndex(iter.f, iter.idx, kind(attr)) + function Base.delete!(iter::FunctionAttrSet, attr::StringAttribute) k = kind(attr) API.LLVMRemoveStringAttributeAtIndex(iter.f, iter.idx, k, length(k)) diff --git a/src/core/instructions.jl b/src/core/instructions.jl index 1a58001e..88310389 100644 --- a/src/core/instructions.jl +++ b/src/core/instructions.jl @@ -400,6 +400,12 @@ Base.delete!(iter::CallSiteAttrSet, attr::LLVM.EnumAttribute) = Base.delete!(iter::CallSiteAttrSet, attr::LLVM.TypeAttribute) = LLVM.API.LLVMRemoveCallSiteEnumAttribute(iter.instr, iter.idx, kind(attr)) +Base.delete!(iter::CallSiteAttrSet, attr::LLVM.ConstantRangeAttribute) = + LLVM.API.LLVMRemoveCallSiteEnumAttribute(iter.instr, iter.idx, kind(attr)) + +Base.delete!(iter::CallSiteAttrSet, attr::LLVM.ConstantRangeListAttribute) = + LLVM.API.LLVMRemoveCallSiteEnumAttribute(iter.instr, iter.idx, kind(attr)) + function Base.delete!(iter::CallSiteAttrSet, attr::LLVM.StringAttribute) k = kind(attr) return LLVM.API.LLVMRemoveCallSiteStringAttribute(iter.instr, iter.idx, k, length(k))