I would like to call a C# function from LLVM bytecode.
To understand the mecanism, I created a "Display" function and I tried to use AddGlobalMapping.
But I have a problem with function resolution at runtime.
; ModuleID = 'LLVMSharpIntro'
target triple = "i686-pc-windows-msvc-elf"
; Function Attrs: nounwind
declare void @display() #0
define i32 @sum(i32, i32) {
entry:
%tmp = add i32 %0, %1
call void @display()
ret i32 %tmp
}
attributes #0 = { nounwind }
LLVM ERROR: Program used external function 'display' which could not be resolved!
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using LLVMSharp;
namespace ConsoleApplication1
{
class Program
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int Add(int a, int b);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void DisplayDelegate();
public static void Display()
{
Console.WriteLine("coucou");
}
private static void Main(string[] args)
{
LLVMBool False = new LLVMBool(0);
//LLVMModuleRef mod = LLVM.ModuleCreateWithName("LLVMSharpIntro");
LLVMModuleRef mod = LLVM.ModuleCreateWithNameInContext("LLVMSharpIntro", LLVM.GetGlobalContext());
LLVMExecutionEngineRef engine;
IntPtr error;
LLVM.LinkInMCJIT();
LLVM.InitializeX86Target();
LLVM.InitializeX86TargetInfo();
LLVM.InitializeX86TargetMC();
LLVM.InitializeX86AsmPrinter();
var platform = Environment.OSVersion.Platform;
if (platform == PlatformID.Win32NT) // On Windows, LLVM currently (3.6) does not support PE/COFF
{
LLVM.SetTarget(mod, Marshal.PtrToStringAnsi(LLVM.GetDefaultTargetTriple()) + "-elf");
}
var options = new LLVMMCJITCompilerOptions();
var optionsSize = (4 * sizeof(int)) + IntPtr.Size; // LLVMMCJITCompilerOptions has 4 ints and a pointer
LLVM.InitializeMCJITCompilerOptions(out options, optionsSize);
LLVM.CreateMCJITCompilerForModule(out engine, mod, out options, optionsSize, out error);
//LLVM.CreateExecutionEngine(out engine, mod, out error);
LLVMBuilderRef builder = LLVM.CreateBuilder();
/* display */
LLVMTypeRef[] no_param_types = { LLVM.VoidType() };
LLVMTypeRef voidType = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[0], false);
var display = LLVM.AddFunction(mod, "display", voidType);
display.SetLinkage(LLVMLinkage.LLVMExternalLinkage);
/* end display */
DisplayDelegate dd = Display;
var p1 = Marshal.GetFunctionPointerForDelegate(dd);
var mock = LLVM.GetNamedFunction(mod, "display");
LLVM.AddGlobalMapping(engine, mock, p1);
LLVM.SetFunctionCallConv(mock, (uint)LLVMCallConv.LLVMCCallConv);
LLVM.AddFunctionAttr(mock, LLVMAttribute.LLVMNoUnwindAttribute);
/* sum */
LLVMTypeRef[] param_types = { LLVM.Int32Type(), LLVM.Int32Type() };
LLVMTypeRef ret_type = LLVM.FunctionType(LLVM.Int32Type(), out param_types[0], 2, False);
LLVMValueRef sum = LLVM.AddFunction(mod, "sum", ret_type);
var entry = LLVM.AppendBasicBlock(sum, "entry");
LLVM.PositionBuilderAtEnd(builder, entry);
LLVMValueRef tmp = LLVM.BuildAdd(builder, LLVM.GetParam(sum, 0), LLVM.GetParam(sum, 1), "tmp");
LLVMValueRef result1 = new LLVMValueRef();
var toCall = LLVM.GetNamedFunction(mod, "display");
LLVM.BuildCall(builder, toCall, new LLVMValueRef[0], "");
LLVM.BuildRet(builder, tmp);
/* end sum */
LLVM.VerifyModule(mod, LLVMVerifierFailureAction.LLVMAbortProcessAction, out error);
LLVM.DisposeMessage(error);
LLVM.DumpModule(mod);
var addMethod = (Add)Marshal.GetDelegateForFunctionPointer(LLVM.GetPointerToGlobal(engine, sum), typeof(Add));
int result = addMethod(10, 10);
Console.WriteLine("Result of sum is: " + result);
if (LLVM.WriteBitcodeToFile(mod, "sum.bc") != 0)
Console.WriteLine("error writing bitcode to file, skipping");
LLVM.DisposeBuilder(builder);
LLVM.DisposeExecutionEngine(engine);
Console.ReadKey();
}
}
}
Thank you.
Romain.