Ссылка C в llvmlite

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

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

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

С:

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

Питон:

...

    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, но будет гораздо быстрее, чище и проще сделать это на C. Любая помощь приветствуется!


person Batata    schedule 16.04.2016    source источник
comment
Какие инструменты вы использовали для разработки Lexer и парсера?   -  person Ahmed T. Ali    schedule 10.07.2016


Ответы (3)


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

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

Затем вы можете просто генерировать обычные вызовы функций.

person Coder3000    schedule 16.04.2016
comment
У вас есть пример того, как выполнить вызов? Загружаются ли функции внутри модуля после загрузки? И если да, то как мне найти функцию для ее вызова? - person santasmic; 27.06.2018

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

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

person Ismail Badawi    schedule 16.04.2016

Ответ @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 $reference https://helloacm.com/calling-c-shared-library-from-python-code-linux-version/

Об этой проблеме здесь другая ссылка

-Вызов функций C/C++ из ExecutionEngine -Вызов кода Python из LLVM JIT -http://eli.thegreenplace.net/2015/обратный-в-питон-из-llvmlite-jited-code/

person WireBlock    schedule 28.10.2016