llvmcpy icon indicating copy to clipboard operation
llvmcpy copied to clipboard

How to use the get_param_types() method

Open x14ngch3n opened this issue 9 months ago • 3 comments

I have a variable of FunctionType and I want to iterate its parameter types, I find the get_param_types() method might be useful, however I failed to call it with the right argument:

# the generated bindings
def get_param_types(self, arg0):
    """See LLVMGetParamTypes"""
    return libLLVMCoverageso50.LLVMGetParamTypes(self.in_ptr(), ([x.in_ptr() for x in arg0] if type(arg0) is list else arg0.out_ptr()))
# my code
f = module.get_named_function("foo") # suppose foo(arg1, arg2, arg3)
l = ?
f.type_of().get_param_types(l)

I don't know how to construct the l argument. I tried the following:

l=[llvm.ffi.new("LLVMTypeRef *")]*3
>>> f.type_of().get_param_types(l)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/xiangchen/.cache/llvmcpy/a1fe60d12ca6bf5e9ef034da2a85c1ad88886fe0b2023124da7efad7adf41914-5.0.0/llvmcpyimpl.py", line 1840, in get_param_types
    return libLLVMLTO.LLVMGetParamTypes(self.in_ptr(), ([x.in_ptr() for x in arg0] if type(arg0) is list else arg0.out_ptr()))
  File "/home/xiangchen/.cache/llvmcpy/a1fe60d12ca6bf5e9ef034da2a85c1ad88886fe0b2023124da7efad7adf41914-5.0.0/llvmcpyimpl.py", line 1840, in <listcomp>
    return libLLVMLTO.LLVMGetParamTypes(self.in_ptr(), ([x.in_ptr() for x in arg0] if type(arg0) is list else arg0.out_ptr()))
AttributeError: cdata 'struct LLVMOpaqueType * *' has no attribute 'in_ptr

x14ngch3n avatar May 21 '25 03:05 x14ngch3n

  1. Please report an easy to run reproducer, including a module. Also, report the LLVM version you're using.
  2. The second argument of LLVMGetParamTypes is an out argument. The generated bindings can't distinguish very well between out arguments and arguments pointing to an array. If you pass in a list, you're suggesting it's an argument pointing to an array. The correct usage should be
    llvm = llvmcpy.LLVMCPy
    x = llvm.Type()
    f.type_of().get_param_types(x)
    
    Clearly, this is not ideal, we should devise a better way to distinguish pointer-to-array arguments from out arguments.

aleclearmind avatar May 21 '25 06:05 aleclearmind

Thanks for your reply! I am using LLVM-5.0.0, here's the reproducer. First assemble the following ir to foo.bc

define void @foo(i32, i8 signext, i8*) {
  ret void
}

then run the python script

from llvmcpy import LLVMCPy

llvm = LLVMCPy()
buffer = llvm.create_memory_buffer_with_contents_of_file("foo.bc")
module = buffer.get_bitcode_module()

foo = module.get_named_function("foo")
t = llvm.Type()
foo.type_of().get_param_types(t)
print(t.print_type_to_string())

And the output is:

  File "<stdin>", line 1, in <module>
  File "/home/xiangchen/.cache/llvmcpy/a1fe60d12ca6bf5e9ef034da2a85c1ad88886fe0b2023124da7efad7adf41914-5.0.0/llvmcpyimpl.py", line 1831, in get_element
    return Type(libLLVMLTO.LLVMGetElementType(self.in_ptr()))
  File "/home/xiangchen/.cache/llvmcpy/a1fe60d12ca6bf5e9ef034da2a85c1ad88886fe0b2023124da7efad7adf41914-5.0.0/llvmcpyimpl.py", line 1764, in in_ptr
    raise RuntimeError("in_ptr called on uninitialized object")
RuntimeError: in_ptr called on uninitialized object

x14ngch3n avatar May 21 '25 14:05 x14ngch3n

We have a couple of issues:

  1. I understand why you were doing [llvm.ffi.new("LLVMTypeRef *")]*3: the LLVMGetElementType gets an output array not just an output argument. We don't support that in our automatic wrapping, but we could work on it.

  2. The bigger problem is that foo.type_of().dump() prints ptr, i.e., an opaque pointer, from which you cannot obtain the pointee. This is the results of the whole opaque pointers effort. Unfortunately, there doesn't seem to be a way to call Function->getFunctionType() via the LLVM-C API, which would be the proper way of getting the type of the function. This said, since you're using a very old LLVM version, you are not affected by this.

    Something like:

    t = [llvm.ffi.new("LLVMOpaqueType *"), llvm.ffi.new("LLVMOpaqueType *"), llvm.ffi.new("LLVMOpaqueType *")]
    llvm.libLLVMXRay.LLVMGetParamTypes(llvm.libLLVMXRay.LLVMGetElementType(foo.type_of().in_ptr()), t)
    

    However, I could't test this right now, I don't have access to an old enough LLVM version.

aleclearmind avatar May 22 '25 08:05 aleclearmind