Skip to content

Commit b8b7339

Browse files
authored
New module members and refactorings (#42)
* Removed redundant arg validator now that ValidateNotDefault is in nuget pkg * Added GlobalIndirectSymbol * Added GlobalIfunc * Added WriteOnce<T> class and applied to several places * Added Module.GetMDKind() * Added Module.Aliases * Added Module.NamedMetadata * Added docs on internal marshal support for LLVMBool and strings * Added Context bindings to support ODR unique debug types * removed obsoleted P/Invoke APIs * Changed typ of values enumerated from BitCodeModule.Globals to reflect actual underlying type as GlobalVariable. This non-breaking as it is a more derived type and makes it easier to get at the additional info from the GlobalVariable type. * Minor refactorings and corrections
1 parent 3427fec commit b8b7339

29 files changed

+445
-88
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
<PackageReference Include="StyleCop.Analyzers" Version="1.0.2" PrivateAssets="All" />
7070
<AdditionalFiles Include="$(MSBuildThisFileDirectory)stylecop.json" Link="stylecop.json" />
7171
</ItemGroup>
72-
<ItemGroup>
72+
<ItemGroup Condition="'$(NoCommonAnalyzers)'!='true'">
7373
<None Include="$(MSBuildThisFileDirectory)Ubiquity.NET.ruleset" Link="Ubiquity.NET.ruleset" />
7474
</ItemGroup>
7575
</When>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Marshaling LLVMBool
2+
3+
LLVMBool is a typdef in the LLVM-C API that is both simple and problematic. In it's
4+
simplest sense an LLVMBool is a representation of a bi-modal value. However, the
5+
problematic part is that the semantics for the value are different depending on any
6+
given API. That is, in some cases LLVMBool != 0 is a failure case, and others it is
7+
a success! The confusion stems from LLVMBool serving a dual role:
8+
1) A real boolean true/false
9+
2) A status code where 0 == success and non-zero indicates an error
10+
11+
This duality is confusing and can lead to subtle errors in usage of APIs if translated
12+
directly into language projections. This makes hands-off automatic generation of P/Invoke
13+
calls to LLVM either imposible or error prone. Thus, Llvm.NET uses manually updated P/Invoke
14+
calls that were initially auto generated to get things started but not maintined via any
15+
generation tools. In the case of LLVMBool Llvm.NET uses distinct types for the different
16+
semantics and declares the interop signatures with the form appropriate to the function
17+
being called. The two types are LLVMStatus and standard `System.Boolean` or `bool` in C#
18+
19+
## LLVMStatus
20+
This is a status value where 0 == Success and non-zero is a failure or false status.
21+
LLVMStatus is used whenever the 0 == success semantics apply to the API. For example:
22+
23+
```C#
24+
[DllImport( LibraryPath, EntryPoint = "LLVMWriteBitcodeToFD", CallingConvention = CallingConvention.Cdecl )]
25+
internal static extern LLVMStatus LLVMWriteBitcodeToFD( LLVMModuleRef @M, int @FD, int @ShouldClose, int @Unbuffered );
26+
```
27+
28+
## LLVMBool
29+
This is the traditioanl boolean value where 0==false and non-zero is true and uses the
30+
standard boolean marshaling support for System.Boolean
31+
```C#
32+
[DllImport( LibraryPath, EntryPoint = "LLVMTypeIsSized", CallingConvention = CallingConvention.Cdecl )]
33+
[return: MarshalAs( UnmanagedType.Bool )]
34+
internal static extern bool LLVMTypeIsSized( LLVMTypeRef @Ty );
35+
```
36+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Marshaling strings in LLVM.NET
2+
LLVM provides strings in several forms and this leads to complexities for
3+
P/Invoke signatures as sometimes the strings require some form of release
4+
and in other cases, they do not. Standard .NET marshaling of strings makes
5+
some assumptions with regard to strings as a return type that make the LLVM
6+
APIs difficult. (e.g. in some LLVM APIs the returned string must be released
7+
via LLVMDisposeMessage() or some other call, while in other cases it is just
8+
a pointer to an internal const string that does not need any release.)
9+
10+
To resolve these issues and make the requirements explicitly clear and consistent
11+
Llvm.NET uses custom marshaling of the strings to mark the exact behavior directly
12+
on the P/Invoke signature so it is both clear and easy to use for the upper layers
13+
(it's just a `System.String`)
14+
15+
The current forms of string marshalling are:
16+
17+
```C#
18+
// const char* owned by native LLVM, and never disposed by managed callers (just copy to managed string)
19+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(StringMarshaler))]
20+
21+
// const char* allocated in native LLVM, released by managed caller via LLVMDisposeMessage
22+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(StringMarshaler), MarshalCookie="DisposeMessage")]
23+
24+
// const char* allocated in native LLVM, released by managed caller via LLVMDisposeMangledSymbol
25+
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(StringMarshaler), MarshalCookie="MangledSymbol")]
26+
27+
```
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
# [LLVM Handles](llvm-handles.md)
22
# [Interning Handles](handleref-interning.md)
3+
# [Marshaling Strings](marshal-string.md)
4+
# [Marshaling LLVMBool](marshal-LLVMBool.md)

src/LibLLVM/ContextBindings.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "ContextBindings.h"
2+
#include <llvm\IR\LLVMContext.h>
3+
4+
using namespace llvm;
5+
6+
extern "C"
7+
{
8+
LLVMBool LLVMContextGetIsODRUniquingDebugTypes( LLVMContextRef context )
9+
{
10+
return unwrap( context )->isODRUniquingDebugTypes( );
11+
}
12+
13+
void LLVMContextSetIsODRUniquingDebugTypes( LLVMContextRef context, LLVMBool state )
14+
{
15+
auto pContext = unwrap( context );
16+
if ( state )
17+
{
18+
pContext->enableDebugTypeODRUniquing( );
19+
}
20+
else
21+
{
22+
pContext->disableDebugTypeODRUniquing( );
23+
}
24+
}
25+
}

src/LibLLVM/ContextBindings.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef _CONTEXT_BINDINGS_H_
2+
#define _CONTEXT_BINDINGS_H_
3+
4+
#include "llvm-c/Core.h"
5+
6+
#ifdef __cplusplus
7+
extern "C" {
8+
#endif
9+
10+
LLVMBool LLVMContextGetIsODRUniquingDebugTypes( LLVMContextRef context );
11+
void LLVMContextSetIsODRUniquingDebugTypes( LLVMContextRef context, LLVMBool state );
12+
13+
#ifdef __cplusplus
14+
}
15+
#endif
16+
17+
#endif

src/LibLLVM/EXPORTS.DEF

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ LLVMComdatGetName
3131
LLVMGlobalObjectGetComdat
3232
LLVMGlobalObjectSetComdat
3333

34+
LLVMModuleGetFirstGlobalAlias
35+
LLVMModuleGetNextGlobalAlias
36+
LLVMModuleGetFirstNamedMD
37+
LLVMModuleGetNextNamedMD
38+
39+
LLVMContextGetIsODRUniquingDebugTypes
40+
LLVMContextSetIsODRUniquingDebugTypes
41+
3442
LLVMCreatePassRegistry
3543
LLVMPassRegistryDispose
3644
LLVMAddModuleFlag

src/LibLLVM/LibLLVM.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
<ItemGroup>
179179
<ClCompile Include="AnalysisBindings.cpp" />
180180
<ClCompile Include="AttributeBindings.cpp" />
181+
<ClCompile Include="ContextBindings.cpp" />
181182
<ClCompile Include="DIBuilderBindings.cpp" />
182183
<ClCompile Include="DITypeBindings.cpp" />
183184
<ClCompile Include="InlinedExports.cpp" />
@@ -190,6 +191,7 @@
190191
<ItemGroup>
191192
<ClInclude Include="AnalysisBindings.h" />
192193
<ClInclude Include="AttributeBindings.h" />
194+
<ClInclude Include="ContextBindings.h" />
193195
<ClInclude Include="DIBuilderBindings.h" />
194196
<ClInclude Include="DITypeBindings.h" />
195197
<ClInclude Include="InlinedExports.h" />

src/LibLLVM/LibLLVM.vcxproj.filters

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@
6161
<ClCompile Include="AttributeBindings.cpp">
6262
<Filter>Source Files</Filter>
6363
</ClCompile>
64+
<ClCompile Include="ContextBindings.cpp">
65+
<Filter>Source Files</Filter>
66+
</ClCompile>
6467
</ItemGroup>
6568
<ItemGroup>
6669
<ClInclude Include="DIBuilderBindings.h">
@@ -102,6 +105,9 @@
102105
<ClInclude Include="AttributeBindings.h">
103106
<Filter>Header Files</Filter>
104107
</ClInclude>
108+
<ClInclude Include="ContextBindings.h">
109+
<Filter>Header Files</Filter>
110+
</ClInclude>
105111
</ItemGroup>
106112
<ItemGroup>
107113
<ResourceCompile Include="Resource.rc">

src/LibLLVM/ModuleBindings.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,44 @@ extern "C"
163163
Comdat const& comdat = *unwrap( comdatRef );
164164
return LLVMCreateMessage( comdat.getName( ).str( ).c_str( ) );
165165
}
166+
167+
LLVMValueRef LLVMModuleGetFirstGlobalAlias( LLVMModuleRef M )
168+
{
169+
Module *Mod = unwrap( M );
170+
Module::alias_iterator I = Mod->alias_begin( );
171+
if ( I == Mod->alias_end( ) )
172+
return nullptr;
173+
174+
return wrap( &*I );
175+
}
176+
177+
LLVMValueRef LLVMModuleGetNextGlobalAlias( LLVMValueRef valueRef )
178+
{
179+
GlobalAlias *pGA = unwrap<GlobalAlias>( valueRef );
180+
Module::alias_iterator I( pGA );
181+
if ( ++I == pGA->getParent( )->alias_end( ) )
182+
return nullptr;
183+
184+
return wrap( &*I );
185+
}
186+
187+
LLVMNamedMDNodeRef LLVMModuleGetFirstNamedMD( LLVMModuleRef M )
188+
{
189+
Module *Mod = unwrap( M );
190+
Module::named_metadata_iterator I = Mod->named_metadata_begin( );
191+
if ( I == Mod->named_metadata_end( ) )
192+
return nullptr;
193+
194+
return wrap( &*I );
195+
}
196+
197+
LLVMNamedMDNodeRef LLVMModuleGetNextNamedMD( LLVMNamedMDNodeRef /*NamedMDNode*/ valueRef )
198+
{
199+
NamedMDNode *pMD = unwrap( valueRef );
200+
Module::named_metadata_iterator I( pMD );
201+
if ( ++I == pMD->getParent( )->named_metadata_end( ) )
202+
return nullptr;
203+
204+
return wrap( &*I );
205+
}
166206
}

0 commit comments

Comments
 (0)