Skip to content

Commit c85028f

Browse files
authored
Merge pull request #304 from maleadt/tb/metadata
Add support for replacing values in metadata.
2 parents 487062d + ed32178 commit c85028f

File tree

8 files changed

+88
-4
lines changed

8 files changed

+88
-4
lines changed

Manifest.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ version = "1.4.1"
3434

3535
[[LLVMExtra_jll]]
3636
deps = ["Artifacts", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg", "TOML"]
37-
git-tree-sha1 = "00d23b26d194507028b9a1c2728a691ab9914262"
37+
git-tree-sha1 = "771bfe376249626d3ca12bcd58ba243d3f961576"
3838
uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab"
39-
version = "0.0.15+0"
39+
version = "0.0.16+0"
4040

4141
[[LazyArtifacts]]
4242
deps = ["Artifacts", "Pkg"]

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
1111

1212
[compat]
1313
CEnum = "0.2, 0.3, 0.4"
14-
LLVMExtra_jll = "=0.0.15"
14+
LLVMExtra_jll = "=0.0.16"
1515
julia = "1.6"

deps/LLVMExtra/include/LLVMExtra.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ LLVMValueRef LLVMBuildCallWithOpBundle(LLVMBuilderRef B, LLVMValueRef Fn,
154154
LLVMOperandBundleDefRef *Bundles, unsigned NumBundles,
155155
const char *Name);
156156
LLVMValueRef LLVMMetadataAsValue2(LLVMContextRef C, LLVMMetadataRef Metadata);
157+
void LLVMReplaceAllMetadataUsesWith(LLVMValueRef Old, LLVMValueRef New);
158+
void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRef New);
157159

158160
LLVM_C_EXTERN_C_END
159161
#endif

deps/LLVMExtra/lib/llvm-api.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,3 +526,11 @@ LLVMValueRef LLVMMetadataAsValue2(LLVMContextRef C, LLVMMetadataRef Metadata) {
526526
else
527527
return wrap(MetadataAsValue::get(*unwrap(C), MD));
528528
}
529+
530+
void LLVMReplaceAllMetadataUsesWith(LLVMValueRef Old, LLVMValueRef New) {
531+
ValueAsMetadata::handleRAUW(unwrap<Value>(Old), unwrap<Value>(New));
532+
}
533+
534+
void LLVMReplaceMDNodeOperandWith(LLVMMetadataRef MD, unsigned I, LLVMMetadataRef New) {
535+
unwrap<MDNode>(MD)->replaceOperandWith(I, unwrap(New));
536+
}

lib/libLLVM_extra.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,11 @@ end
398398
function LLVMMetadataAsValue2(C, MD)
399399
ccall((:LLVMMetadataAsValue2, libLLVMExtra), LLVMValueRef, (LLVMContextRef, LLVMMetadataRef), C, MD)
400400
end
401+
402+
function LLVMReplaceAllMetadataUsesWith(OldVal, NewVal)
403+
ccall((:LLVMReplaceAllMetadataUsesWith, libLLVMExtra), Cvoid, (LLVMValueRef, LLVMValueRef), OldVal, NewVal)
404+
end
405+
406+
function LLVMReplaceMDNodeOperandWith(MD, I, New)
407+
ccall((:LLVMReplaceMDNodeOperandWith, libLLVMExtra), Cvoid, (LLVMMetadataRef, Cuint, LLVMMetadataRef), MD, I, New)
408+
end

src/core/metadata.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ function operands(md::MDNode)
111111
return [Metadata(op) for op in ops]
112112
end
113113

114+
# TODO: setindex?
115+
function replace_operand(md::MDNode, i, new::Metadata)
116+
API.LLVMReplaceMDNodeOperandWith(md, i-1, new)
117+
end
118+
114119

115120
## tuples
116121

src/core/value.jl

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ end
4040

4141
## general APIs
4242

43-
export llvmtype, llvmeltype, name, name!, replace_uses!, isconstant, isundef, ispoison, context
43+
export llvmtype, llvmeltype, name, name!, replace_uses!, replace_metadata_uses!, isconstant, isundef, ispoison, context
4444

4545
llvmtype(val::Value) = LLVMType(API.LLVMTypeOf(val))
4646
llvmeltype(val::Value) = eltype(llvmtype(val))
@@ -55,6 +55,39 @@ end
5555

5656
replace_uses!(old::Value, new::Value) = API.LLVMReplaceAllUsesWith(old, new)
5757

58+
function replace_metadata_uses!(old::Value, new::Value)
59+
if llvmtype(old) == llvmtype(new)
60+
API.LLVMReplaceAllMetadataUsesWith(old, new)
61+
else
62+
# NOTE: LLVM does not support replacing values of different types, either using
63+
# regular RAUW or only on metadata. The latter should probably be supported.
64+
# Instead, we replace by a bitcast to the old type.
65+
compat_new = const_bitcast(new, llvmtype(old))
66+
replace_metadata_uses!(old, compat_new)
67+
68+
# the above is often invalid, e.g. for module-level metadata identifying functions.
69+
# so we peek into such metadata and try to get rid of the bitcast. see also
70+
# https://discourse.llvm.org/t/replacing-module-metadata-uses-of-function/62431/4
71+
mod = LLVM.parent(new)
72+
while !isa(mod, LLVM.Module)
73+
mod = LLVM.parent(new)
74+
end
75+
ctx = context(mod)
76+
function recurse(md)
77+
for (i, op) in enumerate(operands(md))
78+
if op isa ValueAsMetadata && Value(op; ctx) == compat_new
79+
LLVM.replace_operand(md, i, Metadata(new))
80+
elseif isa(op, MDTuple)
81+
recurse(op)
82+
end
83+
end
84+
end
85+
for (key, md) in metadata(mod)
86+
recurse(md)
87+
end
88+
end
89+
end
90+
5891
isconstant(val::Value) = convert(Core.Bool, API.LLVMIsConstant(val))
5992

6093
isundef(val::Value) = convert(Core.Bool, API.LLVMIsUndef(val))

test/core.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,34 @@ Context() do ctx
815815
@test convert(ConstantInt, val) == int
816816
end
817817

818+
Context() do ctx
819+
mod = LLVM.Module("SomeModule"; ctx)
820+
ft = LLVM.FunctionType(LLVM.VoidType(ctx))
821+
f1 = LLVM.Function(mod, "f1", ft)
822+
823+
push!(metadata(mod)["function"], MDNode([f1]; ctx))
824+
@test Value(operands(operands(metadata(mod)["function"])[1])[1]; ctx) == f1
825+
826+
f2 = LLVM.Function(mod, "f2", ft)
827+
replace_metadata_uses!(f1, f2)
828+
@test Value(operands(operands(metadata(mod)["function"])[1])[1]; ctx) == f2
829+
end
830+
831+
# different type; requires a hack
832+
Context() do ctx
833+
mod = LLVM.Module("SomeModule"; ctx)
834+
ft1 = LLVM.FunctionType(LLVM.VoidType(ctx))
835+
f1 = LLVM.Function(mod, "f1", ft1)
836+
837+
push!(metadata(mod)["function"], MDNode([f1]; ctx))
838+
@test Value(operands(operands(metadata(mod)["function"])[1])[1]; ctx) == f1
839+
840+
ft2 = LLVM.FunctionType(LLVM.Int32Type(ctx))
841+
f2 = LLVM.Function(mod, "f2", ft2)
842+
replace_metadata_uses!(f1, f2)
843+
@test Value(operands(operands(metadata(mod)["function"])[1])[1]; ctx) == f2
844+
end
845+
818846
Context() do ctx
819847
str = MDString("foo"; ctx)
820848
node = MDNode([str]; ctx)

0 commit comments

Comments
 (0)