Ссылка C в llvmlite

Я пишу компилятор в Python, используя llvmlite генерировать промежуточный ИК LLVM. Лексер и парсер закончили, теперь я занимаюсь генерацией кода. Компилятор будет динамическим и слабо типизированным, поэтому мне потребуется кое-что сделать во время выполнения, например, распределение. Для этого я уже реализовал некоторые функции в C, и теперь я хочу вызвать эти функции, используя builder.call от llvmlite.

Я не нашел документацию или примеры того, как это сделать.

Эта функция просто простой пример, реальные гораздо больше.

C:

int some_function(int a)
{
     return a + 4;
}

Python:

...

    main_ty = ir.FunctionType(ir.IntType(32), [])
    func = ir.Function(module, main_ty, 'main')
    block = func.append_basic_block('entry')
    builder = ir.IRBuilder(block)

    # I want to do something like this...

    ret = builder.call(some_function, [ir.Constant(ir.IntType(32), 34)]);

...

Я мог бы написать функции напрямую, используя llvmlite builders, но это будет гораздо быстрее, чище и проще сделать это на C. Любая помощь приветствуется!

4 ответа

Решение

Вы можете импортировать динамическую библиотеку, содержащую среду выполнения.

llvmlite.binding.load_library_permanently("runtime.so")

Тогда вы можете просто генерировать нормальные вызовы функций.

На стороне LLVM IR вы можете просто объявить функции с правильной подписью (и без тела) и вставлять вызовы к ним, как и любую другую функцию. Это так же, как в C вы можете вызвать функцию, которая определена в другом файле.

Оттуда вам придется каким-то образом ссылаться на ваши функции Си. Детали здесь зависят от того, как вы собираетесь использовать сгенерированный IR-код. Например, вы можете использовать clang, чтобы превратить его в объектные файлы, а затем связать его, как любую другую программу. Или вы можете использовать llvm JIT, в этом случае ответ @Coder3000 (llvmlite.binding.load_library_permanently) должен работать, чтобы позволить LLVM разрешать ваши вызовы функций.

@Coder3000 и @Ismail Badawi ответ идеально, но нет кода. Есть мой код

    #!/usr/bin/env python
    # coding=utf-8
    from __future__ import print_function
    from ctypes import CFUNCTYPE, c_double,cdll,c_int
    import llvmlite.binding as llvm
    import llvmlite.ir as  ir

    llvm.initialize()
    llvm.initialize_native_target()
    llvm.initialize_native_asmprinter()
    #load shared library
    llvm.load_library_permanently('./TestLib.so')
    # Create some useful types
    double = ir.DoubleType()
    fnty = ir.FunctionType(double, (double, double))

    # Create an empty module...
    module = ir.Module("fdadd")
    # and declare a function named "fpadd" inside it
    func = ir.Function(module, fnty, name="fpadd")

    # Now implement the function
    block = func.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)
    a, b = func.args
    result = builder.fadd(a, b, name="res")
    builder.ret(result)
    #function call in llvm ir internal
    func2=ir.Function(module,fnty,name="fdadd")
    block2=func2.append_basic_block(name="entry")
    builder=ir.IRBuilder(block2)
    a,b=func2.args
    result2=builder.call(func,(a,b))
    builder.ret(result2)
    # llvm IR call external C++ function
    outfunc=ir.Function(module,fnty,name="SampleAddDouble")
    #just declare shared library function in module
    outaddfunc=ir.Function(module,fnty,name="outadd")
    builder=ir.IRBuilder(outaddfunc.append_basic_block(name="entry"))
    a,b=outaddfunc.args
    outresult=builder.call(outfunc,(a,b))
    builder.ret(outresult)
    strmod=str(module)
    # Print the module IR
    print(strmod)
    print("-----------------------------------------")
    #assembly llvm ir
    assmod = llvm.parse_assembly(strmod)
    assmod.verify()
    print("--parse assembly")
    target = llvm.Target.from_default_triple()
    target_machine = target.create_target_machine()
    engine = llvm.create_mcjit_compiler(assmod, target_machine)
    engine.finalize_object()
    print(engine)

    # Look up the function pointer (a Python int) 
    #llvm execution engine call llvm IR function(or dsl function)
    func_ptr = engine.get_function_address("fpadd")
    print('func_ptr is:',func_ptr)

    # Run the function via ctypes
    cfunc = CFUNCTYPE(c_double, c_double, c_double)(func_ptr)
    res = cfunc(1.0, 3.5)
    print("fpadd(...) =", res)

    #llvm binding layer call shared library function
    add_int_addr = llvm.address_of_symbol("SampleAddInt")
    print(add_int_addr)
    add_int_func=CFUNCTYPE(c_int,c_int,c_int)(add_int_addr)
    res2=add_int_func(23,34)
    print(res2)

    #llvm execution engine call shared library function ,by llvm IR 
    add_double_addr=engine.get_function_address("outadd")
    print(add_double_addr)
    add_double_func=CFUNCTYPE(c_double,c_double,c_double)(add_double_addr)
    res3=add_double_func(1.21,1.12)
    print(res3)

И ссылка на Testlib.cpp $ https://helloacm.com/calling-c-shared-library-from-python-code-linux-version/

Об этой проблеме здесь другой реф

- Вызов функций C/C++ из ExecutionEngine- Вызов кода Python из JL LLVM- http://eli.thegreenplace.net/2015/calling-back-into-python-from-llvmlite-jited-code/

Вы можете связать свой файл C с библиотекой LLVM LITE. Я не могу найти ссылки о том, какllvmlite.binding.load_library_permanently("runtime.so")команда работает. И как мне вызывать функции из этого общего файла.

Но есть альтернативный способ — вы можете преобразовать файл C в двоичный формат LLVM с помощьюclang -c -emit-llvm src/main.c -o main.bcкоманда. А затем запуститьclang [*.bc] -o executable.

Другие вопросы по тегам