I'm attempting to make an LLVM.jl pass that removes address spaces. I'm doing this because LLVM's WebAssembly backend has errors because of the use of address spaces.
The pass removes addrspacecast
instructions and removes address spaces in arguments of function declarations.
To fix the arguments of function declarations, first create a new function with fixed arguments, then replace the original with that.
The pass currently fails verify()
.
using LLVM
ctx = Context()
mod = parse(LLVM.Module, """
%jl_value_t = type opaque
@"jl_global%YY" = global %jl_value_t* null
define void @fun(i32) {
top:
%1 = load %jl_value_t*, %jl_value_t** @"jl_global%YY"
%2 = addrspacecast %jl_value_t* %1 to %jl_value_t addrspace(10)*
call void @update_fun(%jl_value_t addrspace(10)* %2)
ret void
}
declare void @update_fun(%jl_value_t addrspace(10)*)
""", ctx)
@show verify(mod)
replacetype(x) = x isa LLVM.PointerType && addrspace(x) > 0 ? LLVM.PointerType(eltype(x)) : x
function remove_address_spaces!(mod::LLVM.Module)
changed = false
for fun in functions(mod)
# Remove addrspacecast instructions
for blk in blocks(fun)
for instr in instructions(blk)
if instr isa LLVM.AddrSpaceCastInst
replace_uses!(instr, operands(instr)[1])
unsafe_delete!(LLVM.parent(instr), instr)
changed = true
end
end
end
# Fix function argument types in declarations
ft = eltype(llvmtype(fun))
rt = return_type(ft)
p = parameters(ft)
newrt = replacetype(rt)
newp = replacetype.(p)
if rt != newrt || p != newp
fn = name(fun)
newft = LLVM.FunctionType(newrt, newp)
newf = LLVM.Function(mod, "tmpfun", newft)
replace_uses!(fun, newf)
unsafe_delete!(mod, fun)
name!(newf, fn*"X")
changed = true
end
end
return changed
end
remove_address_spaces!(mod)
@show mod
@show verify(mod)
Here's the error message from verify
:
LLVM error: Called function is not the same type as the call!
call void @update_funX(%jl_value_t* %1)
What's most unusual is that the text representation of the IR looks right (see below). To me, the function declaration and the function call look like they have the correct types.
%jl_value_t = type opaque
@"jl_global%YY" = global %jl_value_t* null
define void @fun(i32) {
top:
%1 = load %jl_value_t*, %jl_value_t** @"jl_global%YY"
call void @update_funX(%jl_value_t* %1)
ret void
}
declare void @update_funX(%jl_value_t*)