2016-04-16 8 views
3

Ich schreibe einen Compiler in Python mit llvmlite, um Zwischen LLVM IR zu generieren. Lexer und Parser sind fertig, jetzt mache ich Code-Generierung. Der Compiler wird dynamisch und schwach typisiert sein, also muss ich etwas zur Laufzeit machen, wie die Zuweisung. Dafür habe ich bereits einige Funktionen in C implementiert, und jetzt möchte ich diese Funktionen mit builder.call von llvmlite aufrufen.Link C in llvmlite

Ich habe keine Dokumentation oder Beispiele gefunden, wie dies zu tun ist.

Diese Funktion ist nur ein einfaches Beispiel, die echten sind viel größer.

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)]); 

... 

ich die Funktionen direkt llvmlite Builder verwenden schreiben könnte, werden aber viel schnell sein, sauberer und einfach tun es in C. Jede Hilfe ist willkommen!

+0

Mit welchen Tools haben Sie Lexer & Parser entwickelt? –

Antwort

2

Sie könnten eine dynamische Bibliothek importieren, die die Laufzeitumgebung enthält.

Dann könnten Sie einfach normale Funktionsaufrufe generieren.

3

Auf der LLVM IR-Seite können Sie einfach die Funktionen mit der richtigen Signatur (und ohne Körper) deklarieren und Aufrufe an sie wie jede andere Funktion einfügen. Das ist genau wie in C man könnte eine Funktion aufrufen, die in einer anderen Datei definiert ist.

Von dort müssten Sie irgendwie gegen Ihre C-Funktionen verknüpfen. Die Details hängen davon ab, wie Sie Ihren generierten IR-Code verwenden möchten. Zum Beispiel könnten Sie clang verwenden, um es in Objektdateien umzuwandeln und es dann wie jedes andere Programm zu verknüpfen. Oder Sie könnten den llvm JIT verwenden, in diesem Fall sollte die Antwort von @ Coder3000 (llvmlite.binding.load_library_permanently) funktionieren, damit LLVM Ihre Funktionsaufrufe auflösen kann.

0

@ Coder3000 und @Ismail Badawi Antwort ist perfekt, aber es ist kein code.There ist mein Code

#!/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) 

Und die Testlib.cpp $ Referenz https://helloacm.com/calling-c-shared-library-from-python-code-linux-version/

Über dieses Problem hier ist andere ref

-Call C/C++ functions from the ExecutionEngine - Call Python code from LLVM JIT - http://eli.thegreenplace.net/2015/calling-back-into-python-from-llvmlite-jited-code/