Skip to content

Instantly share code, notes, and snippets.

@tshort
Last active May 13, 2019 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tshort/e4e7d97034b0f2edebf13846c8233a3b to your computer and use it in GitHub Desktop.
Save tshort/e4e7d97034b0f2edebf13846c8233a3b to your computer and use it in GitHub Desktop.
Broken LLVM.jl pass to remove address spaces

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*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment