Git Product home page Git Product logo

llvmsharp's Introduction

LLVMSharp

LLVMSharp is a multi-platform .NET Standard library for accessing the LLVM infrastructure. The bindings are auto-generated using ClangSharp parsing LLVM-C header files.

ci

A nuget package for the project is provided here: https://www.nuget.org/packages/llvmsharp.

A convenience package which provides the native libLLVM library for several platforms is provided here: https://www.nuget.org/packages/libLLVM

Nightly packages are available via the NuGet Feed URL: https://pkgs.clangsharp.dev/index.json

Source browsing is available via: https://source.clangsharp.dev/

Table of Contents

Code of Conduct

LLVMSharp and everyone contributing (this includes issues, pull requests, the wiki, etc) must abide by the .NET Foundation Code of Conduct: https://dotnetfoundation.org/about/code-of-conduct.

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [email protected].

License

Copyright (c) .NET Foundation and Contributors. All Rights Reserved. Licensed under the MIT License (MIT). See LICENSE.md in the repository root for more information.

Features

  • Auto-generated using LLVM C headers files, and supports all functionality exposed by them (more than enough to build a full compiler)
  • Type safe (LLVMValueRef and LLVMTypeRef are different types, despite being pointers internally)
  • Nearly identical to LLVM C APIs, e.g. LLVMModuleCreateWithName in C, vs. LLVM.ModuleCreateWithName (notice the . in the C# API)

Building LLVMSharp

On Linux using .NET Core:

 $ git clone http://github.com/dotnet/llvmsharp
 $ cd LLVMSharp
 $ dotnet build

On Windows using .NET Core

Note: - you need to run these commands from the Visual Studio Developer Command Prompt.

 :> git clone http://github.com/dotnet/LLVMSharp
 :> cd LLVMSharp
 :> dotnet build

llvmsharp's People

Contributors

adamdusty avatar akoeplinger avatar am11 avatar aviavni avatar donaldnevermore avatar elbuhofantasma avatar frederik-h avatar gitter-badger avatar ice1000 avatar jackoalan avatar mjsabby avatar mrahhal avatar talyian avatar tannergooding avatar tchatzigiannakis avatar tillalex avatar unixzii avatar yowl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

llvmsharp's Issues

BuildLandingPad

https://github.com/mjsabby/LLVMSharp/blob/master/IRBuilder.cs#L135

When I run
sh build.sh /usr/local/lib/llvm-3.7/lib/libLLVM-3.7.1.dylib /usr/local/lib/llvm-3.7/include

I get

IRBuilder.cs(135,25): error CS1501: No overload for method `BuildLandingPad' takes `4' arguments
Generated.cs(2069,43): (Location of the symbol related to previous error)

Should this call have 5 args in LLVM 3.7?

Managing lifetimes of [UnmanagedFunctionPointer] delegates

As per the MSDN documentation, any delegate that's passed to unmanaged code as a function pointer needs to be explicitly kept alive in managed code, since the GC doesn't track pointers on the unmanaged side.

We have many such delegates in LLVMSharp. In LLVMSharp.Api, I intend to have the relevant wrapper classes manage their lifetimes so the user won't have to call GC.KeepAlive() on them. For example, a delegate that logically belongs to a Context will be kept alive privately and will be released only when the Context is Disposed.

Suggestions on value comparisons

Suggesting to introduce intuitive value comparisons for all LLVM types (structs and classes), reasoning:

  1. The C API structs' only job is to reference the internal data structures of LLVM. Thus, it makes sense that two struct instances that point to the same internal data structure of LLVM (same type, for example), should compare as equal.
  2. The OOP API classes' only job is to wrap around the C API structs. Moreover, due to various implicit conversions we have introduced, class instances can trivially expose their struct instance and struct instances can trivially be wrapped as class instances. Thus, again, we can very easily end up with two separate instances of Type (for example) that, in fact, point to the same internal data structure of LLVM. Such instances should also compare equal, since they operate on the same data and any change to one will immediately be observable using the other.

Suggesting removal of implicit conversions between C and C++ API types

Even though there is no information loss between our boxed and unboxed types, I suggest we start gradually removing our implicit conversions.

  • For trivial conversions (such as an IRBuilder to an LLVMBuilderRef), we could just have a class constructor and optionally, for the opposite case (LLVMBuilderRef to IRBuilder) expose the value as a get-only property (and it should be consistent for all our wrapper types).
  • For non-trivial conversions (such as the Value hierarchy and LLVMValueRef), we could have a method that contains the logic we already have.

My reasoning is that (a) we avoid introducing unintended boxing, (b) we'll make it harder for client code to accidentally mix the two APIs, (c) we'll have a clearer view of what's currently missing from the C++ API, so that we can know what to add (d) it will make our code base cleaner.

If it sounds okay, I can make a PR that contains some of the changes.

System.EntryPointNotFoundException when calling DumpType

LLVM.DumpType(LLVM.TypeOf(lhs.Value));

Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'LLVMDumpType' in DLL 'libLLVM'.
   at LLVMSharp.LLVM.DumpType(LLVMTypeRef Val)
   at Goddamnfuckinglanguage.LangVisitor.VisitExpression(ExpressionContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\LangVisitor.cs:line 98
   at Goddamnfuckinglanguage.LangVisitor.VisitReturnStatement(ReturnStatementContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\LangVisitor.cs:line 78
   at parser.CMMParser.ReturnStatementContext.Accept[TResult](IParseTreeVisitor`1 visitor) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMParser.cs:line 489
   at Antlr4.Runtime.Tree.AbstractParseTreeVisitor`1.VisitChildren(IRuleNode node)
   at parser.CMMBaseVisitor`1.VisitStatement(StatementContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMBaseVisitor.cs:line 86
   at parser.CMMParser.StatementContext.Accept[TResult](IParseTreeVisitor`1 visitor) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMParser.cs:line 332
   at Antlr4.Runtime.Tree.AbstractParseTreeVisitor`1.VisitChildren(IRuleNode node)
   at parser.CMMBaseVisitor`1.VisitBlock(BlockContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMBaseVisitor.cs:line 76
   at Goddamnfuckinglanguage.LangVisitor.VisitBlock(BlockContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\LangVisitor.cs:line 69
   at parser.CMMParser.BlockContext.Accept[TResult](IParseTreeVisitor`1 visitor) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMParser.cs:line 274
   at Antlr4.Runtime.Tree.AbstractParseTreeVisitor`1.Visit(IParseTree tree)
   at Goddamnfuckinglanguage.LangVisitor.VisitMethod(MethodContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\LangVisitor.cs:line 54
   at parser.CMMParser.MethodContext.Accept[TResult](IParseTreeVisitor`1 visitor) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMParser.cs:line 168
   at Antlr4.Runtime.Tree.AbstractParseTreeVisitor`1.VisitChildren(IRuleNode node)
   at parser.CMMBaseVisitor`1.VisitFile(FileContext context) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMBaseVisitor.cs:line 46
   at parser.CMMParser.FileContext.Accept[TResult](IParseTreeVisitor`1 visitor) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\parser\CMMParser.cs:line 113
   at Antlr4.Runtime.Tree.AbstractParseTreeVisitor`1.Visit(IParseTree tree)
   at Goddamnfuckinglanguage.Program.Main(String[] args) in C:\Users\superblaubeere27\source\repos\Goddamnfuckinglanguage\Goddamnfuckinglanguage\Program.cs:line 27```

Make ReversePInvoke easier using LLVMSharp

When a user calls into LLVMSharp and wants to ReversePInvoke (i.e. LLVM generated code calling into their C# code) it's a bit hard and (to be honest) mundane for the developer to write somewhat repetitive code.

This is a very common scenario -- going to LLVM for some CPU intensive task and get the data, and then wanting the productivity of C# to deal with this data.

In fact, for a currently private project I have all the code that does on this fly and supports all C# and LLVM data types anyway, so why not just put that part into LLVMSharp?

Most likely co-ordinate with LLVM 3.7 release to expose this.

Some signatures (involving out parameters) seem to be wrong

I think some of the signatures generated by the script are wrong. I will explain why I think this is the case, but I'd like someone else to validate it as well, as I haven't gotten around to testing it yet.

Consider the example of LLVMDiagnosticHandler. On the C side, it is defined as:

typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *);

Where LLVMDiagnosticInfoRef is:

typedef struct LLVMOpaqueDiagnosticInfo* LLVMDiagnosticInfoRef

Because of this, I'm guessing LLVMDiagnosticHandler is seen by the script as:

typedef void (*LLVMDiagnosticHandler)(LLVMOpaqueDiagnosticInfo*, void *);

And the script emits the following delegate type:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void LLVMDiagnosticHandler(out LLVMOpaqueDiagnosticInfo @param0, IntPtr @param1);

On the C++ side, setting the diagnostic handler simply saves the passed arguments and, at a later point, another function calls the function pointer and passes a const DiagnosticInfo& to it. I think this means that the C++ side expects that first parameter to be an input parameter passed by reference, while the C# side assumes it is an output parameter.

If this is the case, an LLVMSharp user might not be able to create a useful handler, because the C# compiler will force any handler to overwrite the out parameter explicitly (or the C# compiler will insert an implicit overwrite). This means that anything passed to the handler from the C++ side will be lost (and the handler could even corrupt the state of the C++ side). Changing the script to generate ref instead of out should fix that.

I don't know how many other types may have this issue -- this simply happened to be the first one I attempted to work on.

Recursive struct type

Hello Im wondering how we can handle recursive struct types, like this for exampe :
%player = type { %player, i32, etc... }

Add Fluent API like Expression-Trees

Wouldn't it be cool to do the following -

Module.Create("Foo")
.Method("Bar")
.CreateAlloca("a")
.Store("b")

We'll also need APIs like

Module.Create("Foo")
.Method("Bar")
.SwitchInst("a")
.Cases("b")
.Cases("c")

In the above case (no pun intended) we return the SwitchInst back. This will require some manual thought and scrubbing to become really useful.

Add hook for AppVeyor

I've setup a test branch where LLVMSharp gets built successfully and the tests are discovered and run successfully in AppVeyor.

I propose we add AppVeyor as an additional webhook so that we can verify any commits that Travis fails to build properly.

Feedback on the OOAPI

I've pushed a version of the LLVMSharp.Api namespace that contains almost all of the functionality of the original C bindings in a form that (roughly) mimcs the C++ API but in a style that feels more like a C# library (getters/setters, IDisposable interface, generic delegates, cleaner identifiers, etc).

If anyone wants to try it and give some feedback on how to improve it, please go to the OOAPIWorkInProgress branch and build that solution. There are tests included that can be used as examples.

Make LLVMSharp .NET Core Compatible

Work involved is mostly building a new target that can reference the nuget .NET Core packages. We won't need much, I think only System.Runtime and System.Runtime.InteropServices.

Use PInvokeCompiler for LLVMSharp to support .NET CoreRT and simplify deployment

The main goal of this work item is to use the PInvokeCompiler toolchain (being developed @ http://github.com/PInvokeCompiler/PInvokeCompiler) and generate a single assembly that is runnable on:

.NET 4.0+
.NET Core
.NET CoreRT (AOT scenario)

This requires that we generate MSIL that does all the marshalling and bake it into the MSIL. This approach also has benefits for LLVMSharp beyond being able to run on CoreRT.

One key benefit is that now we will be able to use any LLVM.dll (or .so/.dylib) that is supplied to LLVMSharp and we don't have to be aware of where it is deployed. This need arises because a lot of scenarios (mostly in the Linux world) have LLVM installed on the system and they'd like to use that instead of a hypothetical one supplied with LLVMSharp (we don't supply one and don't want to).

This has one negative impact on LLVMSharp's usage which is that now we need to Initialize LLVMSharp before first use.

Add Tests for all OOP APIs (at least the easy ones)

There are some easy tests we can add for the OO APIs, like for Function, Basic Block and the implicit conversions we do.

At least some of the easy ones should be there before next release.

We can add more concrete details about which ones are easy here.

Add Object Oriented API that mirrors C++ API with objects for each instruction, value, etc.

I've gotten feedback for the project (offline) that suggests that the debugging experience of the IR would be considerably better if we could dump the instructions that LLVMSharp is building so that one could use a debugger to visualize the data structure of a module, basic block, etc.

My assessment: The benefit is pretty clear. One of the best parts about developing in C# is the debugging experience in full-featured IDE's like Visual Studio.

It is a very large undertaking (probably 2-3 weeks).

Suggestion to enhance parameter names

Most of the method signatures look something like this (matching the C++ API names verbatim):

public Instruction CreateArrayMalloc(Type @Ty, Value @Val, string @Name)

They could be changed to match the .NET naming convention:

public Instruction CreateArrayMalloc(Type ty, Value val, string name)

Or further, to something more descriptive like:

public Instruction CreateArrayMalloc(Type allocatedType, Value array, string name)

Does any of the two sound good (and which one)? If so, in future commits I may start converting some of the signatures as I go, if that's okay.

Is LLVM.GetBufferStart supposed to return a string?

We have this declaration:

[DllImport(LibraryPath, EntryPoint = "LLVMGetBufferStart", CallingConvention = CallingConvention.Cdecl)]
public static extern string GetBufferStart(LLVMMemoryBufferRef memBuf);

We can see that this function returns the BufferStart of a memory buffer. The type of that variable is const char*, not an std::string or an llvm::StringRef. It seems to me like our LLVM.GetBufferStart method should return an IntPtr (while another method or property should return the actual contents of the buffer).

Perhaps the string type on the C# side was chosen automatically by the code generator because of the char* type on the C side?

Wrong signature of LLVM.DIBuilderCreateBasicType?

If I call this as it is, for example LLVM.DIBuilderCreateBasicType(dibuilder, "i32", 32, 32, 5), and then do DumpModule, I can see that the string has become 32 characters long and has eaten some junk. The length of the string depends on the value of the third argument. Inserting an argument int nameLength after the name worked around this issue

Passing Marshalled to string Zero IntPtr to Name for LLVM.BuildCall throws AccessViolation

In order for LLVM to not give an error for trying to assign to a void typed function call, you need to pass NULL (IntPtr.Zero) to LLVM.BuildCall for the name parameter otherwise so it will generate IR like this:

call void @some_function()

instead of like this

%whatever_i_passed_build_call = call void @some_function()

When I tried this I got an AccessViolationException.

Here is my code:

var returnType = LLVM.GetReturnType(LLVM.GetElementType(LLVM.TypeOf(func)));
LLVM.BuildCall(_builder, func, out argsV[0], argumentCount, (returnType.Equals(LLVM.VoidType()) ? Marshal.PtrToStringAuto(IntPtr.Zero) : variableName));

If this is an error in my code and not in LLVMSharp, please correct me.

Migrate LibLLVM to dotnet core to suppress warnings

When I run dotnet msbuild locally, I get warning:

warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead
of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible
with your project.

Please upgrade LibLLVM to dotnet core 2.0.

Add ORC API

ORC APIs are reasonably stable from the commit changes and LLILC is also using them, so I suppose it's time to put them in here.

Note: The C API doesn't expose this as yet, which is why we'll likely to have to start having a ToT build.

LLVM 4.0.1 support?

Would it be possible to create a build with support for LLVM 4.0?
CoreRT is currently tied to latest Emscripten release, which uses LLVM 4, and so cannot update to LLVMSharp v5.
We could look at producing the LLVMSharp bindings ourselves, but there doesn't seem to be a publicly available repo for building the libLLVM dependency (which also has no v4 releases).

LLVMDIBuilder missing from NuGet library

Calls into DIBuilder, such as LLVM.NewDIBuilder fail because they're not exposed from the build of libLLVM in the matched NuGet package. This appears to be the case in both 3.9.1 and 5.0.

Document DLL creation

As far as I can see, there are at least two non-equivalent ways to build the libLLVM.dll: using the powershell script in the tools directory and using the MSBuild project in tools/libLLVM.
The latter variant seems to be less flexible. For instance, the LLVM libraries for many target architectures are hard-coded as dependencies and I am only interested in the x86 target architecture.
What is the preferred way to build the DLL? Would it be reasonable to use the powershell script in the MSBuild project or to have an alternative project which uses the script?

Implementation of "extern" functions in Kaleidoscope

Hi,
I was trying to add support for "extern" functions from libc in Kaleidoscope (which come for free in C++ version of Kaleidoscope). However, for the following IR (trying to use sin from libc):

declare double @sin(double %f)
%calltmp = call double @sin(double 9.000000e+00)

I keep getting:

Assertion failed: (isa<X>(Val) && "cast<Ty>() argument of incompatible type!"), function cast, file /tmp/llvm-5.0.0.src/include/llvm/Support/Casting.h, line 255.
Stacktrace:
  at <unknown> <0xffffffff>
  at (wrapper managed-to-native) LLVMSharp.LLVM.GetPointerToGlobal (LLVMSharp.LLVMExecutionEngineRef,LLVMSharp.LLVMValueRef) [0x00002] in <c6808a9c612144c69fe813302a5e9c29>:0

Will this require P/Invoke of any sort, or it is not doable from .NET framework as of now?
Btw. I am using MCJIT as specified in the tutorial.

Thanks!

Add AzureDevOps CI pipeline

Azure DevOps supports reading GitHub repos and generating binaries. We should build a simple pipeline that can generate Windows, Linux and macOS binaries to reduce burden for LLVM upgrades.

Setting up build configurations

There's the AnyCPU configuration in the solution, and the UnitTests project has a x64 target. But for some reason, the test runner in my VS seems to avoid x64.

In any case, I suggest we remove the AnyCPU configuration entirely (since we do have an unmanaged DLL anyway, so the whole project can't really be AnyCPU) and create just x86 and x64 build configurations. It will make the targets (and the intention) clearer to anyone building LLVMSharp from source.

If this is acceptable, I can create a quick PR right now.

How to deal with functions not present in the C++ API?

Consider, as an example, the function LLVMCreateJITCompilerForModule.

LLVM C API signature:

LLVMBool LLVMCreateJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
                                        LLVMModuleRef M,
                                        unsigned OptLevel,
                                        char **OutError)

LLVMSharp C API signature:

LLVMBool CreateMCJITCompilerForModule(out LLVMExecutionEngineRef outJit,       
                                      LLVMModuleRef m, 
                                      out LLVMMCJITCompilerOptions options, 
                                      int sizeOfOptions, 
                                      out IntPtr outError)

How do we include this in the LLVMSharp OO API?

Option 1

Create a static overload of it (in the LLVM class - or preferably in a new static class, dedicated to the OO API), with the class types in the signature.

(This is the easiest approach, but it's not how the LLVM C++ API is exposed. So in doing this, we still create an OO API but we depart from the idea of porting the LLVM C++ API specifically. If we're willing to do that, there's also option 2.)

Option 2

Expose each of these functions as an instance method of the type of its first non-out parameter. In our example, CreateMCJITCompilerForModule would be an instance method of the Module class.

For functions that don't have a non-out parameter, we fall back to static overloads (option 1).

(This is how I have it right now in the development branch.)

Option 3

We attempt to stay faithful to the C++ API and we start exposing more things, like the llvm::EngineBuilder class that used in the implementation of LLVMCreateMCJITCompilerForModule, instead of exposing the function itself.

(I think this would be ideal, but I doubt that it's feasible without ending up re-implementing the entire LLVM C++ API, which means duplicated C++/C# code.)

LLVM.InitializeAll*() functions don't exist in the bundled libLLVM.dll (nuget)

I've found a list of functions that are declared in LLVMSharp 3.6.0 but they are not visible in the x86 or x64 version of the libLLVM.dll provided in the nuget package. Calling them throws a System.EntryPointNotFoundException. Their absence can also be verified using Dependency Walker.

The functions in question are:

  • LLVM.InitializeAllTargets()
  • LLVM.InitializeAllTargetInfos()
  • LLVM.InitializeAllTargetMCs()
  • LLVM.InitializeAllAsmPrinters()
  • LLVM.InitializeAllAsmParsers()
  • LLVM.InitializeAllDisassemblers()

The corresponding functions for individual targets are available, as expected.

Prepare for LLVM 3.7

3.7 is coming out, no major changes to the API, so should be good. Need to publish nugget package and update Generated.cs here

Suggestion to change implicit operator bool(LLVMValueRef) to explicit

There is an implicit operator bool(LLVMValueRef). I suggest we make it explicit (and change its call spots to include a cast), for the following reasons:

  1. Converting from a pointer to a boolean causes information loss (unlike our other implicit conversions, which happen between practically interchangeable data types, at no information loss). According to MSDN, conversions that lose information should be explicit.
  2. Right now any comparison of LLVMValueRef instances using == will go to operator==(bool, bool). As far as I can tell from the code (I haven't tested it further), this will return true for any non-null-pointing instances, even if they point to completely different LLVM data structures. This serves us (for building the OOP API) but it's unintuitive to a user of the C API.

Failed to run the Kaleidoscope Chapter4 example on Ubuntu 16.04

Command used:

$ dotnet build
$ cd KaleidoscopeLLVM
$ dotnet run

Get:

  • build
/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/KaleidoscopeLLVM.csproj : warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project. [/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/Kaleidoscope.sln]                
Microsoft (R) Build Engine version 15.3.409.57025 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/KaleidoscopeLLVM.csproj : warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.                                                                                                   
  Kaleidoscope -> /home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/Kaleidoscope/bin/Debug/netcoreapp2.0/Kaleidoscope.dll
  KaleidoscopeLLVM -> /home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/bin/Debug/netcoreapp2.0/KaleidoscopeLLVM.dll

Build succeeded.                                                                                                                             

/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/KaleidoscopeLLVM.csproj : warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.                                                                                                   
    1 Warning(s)                                                                                                                             
    0 Error(s)

Time Elapsed 00:00:03.82
  • run:
/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/KaleidoscopeLLVM.csproj : warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.                                                                                                   
/home/ice1000/git-repos/LLVMSharp/KaleidoscopeTutorial/Chapter4/KaleidoscopeLLVM/KaleidoscopeLLVM.csproj : warning NU1701: Package 'LibLLVM 5.0.1' was restored using '.NETFramework,Version=v4.6.1' instead of the project target framework '.NETCoreApp,Version=v2.0'. This package may not be fully compatible with your project.                                                                                                   
*** Error in `dotnet': free(): invalid pointer: 0x000000000171fe58 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7f4fd74fa7e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8037a)[0x7f4fd750337a]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x4c)[0x7f4fd750753c]
[0x7f4f5d8697a5]
======= Memory map: ========
00400000-00419000 r-xp 00000000 08:02 9575263                            /usr/share/dotnet/dotnet
00618000-00619000 r--p 00018000 08:02 9575263                            /usr/share/dotnet/dotnet
00619000-0061a000 rw-p 00019000 08:02 9575263                            /usr/share/dotnet/dotnet
015d0000-0166e000 rw-p 00000000 00:00 0                                  [heap]
0166e000-0166f000 ---p 00000000 00:00 0                                  [heap]
0166f000-0172e000 rw-p 00000000 00:00 0                                  [heap]
7f4f30000000-7f4f30021000 rw-p 00000000 00:00 0 
7f4f30021000-7f4f34000000 ---p 00000000 00:00 0 
7f4f349b7000-7f4f379d1000 r-xp 00000000 08:02 6685362                    /home/ice1000/.nuget/packages/libllvm/5.0.1/runtimes/linux-x64/native/libLLVM.so

...

7f4fd8730000-7f4fd8731000 r--s 00000000 00:16 337279                     /dev/shm/lttng-ust-wait-6-1000
7f4fd8731000-7f4fd8732000 r--s 00000000 00:16 338158                     /dev/shm/lttng-ust-wait-6
7f4fd8732000-7f4fd8734000 rw-p 00000000 00:00 0
7f4fd8734000-7f4fd8735000 r--p 00025000 08:02 5505041                    /lib/x86_64-linux-gnu/ld-2.23.so
7f4fd8735000-7f4fd8736000 rw-p 00026000 08:02 5505041                    /lib/x86_64-linux-gnu/ld-2.23.so
7f4fd8736000-7f4fd8737000 rw-p 00000000 00:00 0
7ffc62a80000-7ffc62aa2000 rw-p 00000000 00:00 0                          [stack]
7ffc62ae9000-7ffc62aeb000 r--p 00000000 00:00 0                          [vvar]
7ffc62aeb000-7ffc62aed000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Does the same thing happen on Windows?

Add DIBuilder API

DIBuilder APIs are not part of C bindings, so we'll need to write some glue code.

Proposing moving the OOAPI to a new namespace

The LLVMSharp namespace is starting to get too crowded, which is made worse by the fact that there are 2 types for each thing (LLVMValueRef, Value, etc). Especially the class LLVM might get awkward if we start including some static methods that work with the equivalent class types and return the equivalent class types.

  • I propose moving the class-based API to a new namespace (e.g. LLVMSharp.API) along with its own, cleaner version of the LLVM class (that contains only references to the wrapper classes).
  • We can keep the struct-based API where it is (or we can move it to something like LLVMSharp.Bindings, for symmetry -- if this breaking change isn't too much).

Problem with AddGlobalMapping usage

Hi,

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.

My program outputs:

; 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!

My small program is:

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();
        }

    }
}

Did I missed something ?

Thank you.

Romain.

Documentation

I'm translating the official doc (Kaleidoscope) into a C# version.

It's in progress.

Link:

http://ice1000.org/llvm-cs/en/

I wonder if you can add the link to the README, and help me review+find bugs ๐Ÿ˜ƒ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.