Fork me on GitHub

LLVMSharp - C# and .NET LLVM bindings

LLVMSharp are strongly-typed safe C# bindings for LLVM's C bindings. They are auto-generated using ClangSharp parsing LLVM-C header files.

LLVMSharp includes type information for all LLVM-C bindings (structs, typedef and enum) and enforces type information via its interface - i.e. the type LLVMValueRef is different from LLVMTypeRef even though they are both pointers internally. This greatly improves productivity (code completion works) and reduces errors.

Windows (includes LLVM x86/x64 DLLs): LLVMSharp 3.6 Nuget (built from LLVM 3.6.0 release)

Linux/MacOSX: Requires building from source because you have to include the location of your libLLVM.so

Sources: http://github.com/mjsabby/LLVMSharp

Conventions

  • Types are exactly how they are defined in the C bindings, for example: LLVMTypeRef

  • Functions are put in a C# class called LLVM and the LLVM prefix is removed from the functions, for example: LLVM.ModuleCreateWithName("LLVMSharpIntro");

  • For certain functions requiring a pointer to an array, you must pass the array indexed into its first element. If you do not want to pass any element, you can either pass an array with a dummy element, or make a single type and pass it, otherwise you won't be able to compile, for example:
    LLVM.FunctionType(LLVM.Int32Type(), out typesArr[0], 0, False);
    is equivalent to
    LLVM.FunctionType(LLVM.Int32Type(), out type, 0, False);

Kaleidoscope Tutorial

The tutorials have been tested to run on Windows and Linux, however the build (using MSBuild) uses the Nuget packages, hence require some editing to run on Linux.

Common Issues

  • BadImageFormatException: Make sure x86 and x64 builds match, i.e. your libclang.so/dll and llvm.so/dll match your executable
  • If building on Windows, please ensure you're using the Visual Studio Command Prompt for the architecture you care about (x86 or x64)
  • Powershell requires an execution policy to be able to run scripts downloaded from the internet. At the powershell prompt, Set-ExecutionPolicy RemoteSigned should fix most issues.

Building LLVMSharp

LLVMSharp runs (and hence requires) either Mono or Microsoft .NET; and Clang and LLVM to be built as shared libraries.

 

These instructions assume you are familiar with building LLVM and/or building Clang as Shared Libraries, (for Windows there is a powershell script as it is not supported by LLVM build scripts)

 

Using Mono (on Linux, MacOSX):
$ git clone http://github.com/mjsabby/LLVMSharp
$ cd LLVMSharp
$ chmod +x build.sh
$ ./build.sh /path/to/libLLVM.so /path/llvm/include

 

Using Microsoft.NET (on Windows):

 

Building LLVM as shared libraries is not supported by LLVM's build scripts. However, you can use LLVMSharp provided Powershell scripts from Visual Studio Command Prompt to do so.

:> cd c:\path\to\llvm_source\{Release|Debug}\lib
:> git clone http://github.com/mjsabby/LLVMSharp
:> cd LLVMSharp
:> powershell ./LLVMSharp/GenLLVMDLL.ps1
:> build.bat C:\path\llvm.dll C:\path\to\llvm\include

Example application

Delegate Declaration:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int Add(int a, int b);

Main:

LLVMBool False = new LLVMBool(0);
LLVMModuleRef mod = LLVM.ModuleCreateWithName("LLVMSharpIntro");
 
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);
 
LLVMBasicBlockRef entry = LLVM.AppendBasicBlock(sum, "entry");
 
LLVMBuilderRef builder = LLVM.CreateBuilder();
LLVM.PositionBuilderAtEnd(builder, entry);
LLVMValueRef tmp = LLVM.BuildAdd(builder, LLVM.GetParam(sum, 0), LLVM.GetParam(sum, 1), "tmp");
LLVM.BuildRet(builder, tmp);
 
IntPtr error;
LLVM.VerifyModule(mod, LLVMVerifierFailureAction.LLVMAbortProcessAction, out error);
LLVM.DisposeMessage(error);
 
LLVMExecutionEngineRef engine;
 
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);
 
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.DumpModule(mod);
 
LLVM.DisposeBuilder(builder);
LLVM.DisposeExecutionEngine(engine);
Console.ReadKey();

License

Copyright (C) 2015 Mukul Sabharwal (@mjsabby)
Distributed under the University of Illinois/NCSA Open Source License, the same as Clang and LLVM.