forked from OSchip/llvm-project
[Orc] At CBindings for LazyRexports
At C bindings and an example for LLJIT with lazy reexports Differential Revision: https://reviews.llvm.org/D104672
This commit is contained in:
parent
355bf7c1f0
commit
45e8a0befb
|
@ -14,6 +14,7 @@ add_subdirectory(OrcV2CBindingsDumpObjects)
|
|||
add_subdirectory(OrcV2CBindingsIRTransforms)
|
||||
add_subdirectory(OrcV2CBindingsReflectProcessSymbols)
|
||||
add_subdirectory(OrcV2CBindingsRemovableCode)
|
||||
add_subdirectory(OrcV2CBindingsLazy)
|
||||
|
||||
if(CMAKE_HOST_UNIX)
|
||||
add_subdirectory(LLJITWithRemoteDebugging)
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Core
|
||||
ExecutionEngine
|
||||
IRReader
|
||||
JITLink
|
||||
MC
|
||||
OrcJIT
|
||||
Support
|
||||
Target
|
||||
nativecodegen
|
||||
)
|
||||
|
||||
add_llvm_example(OrcV2CBindingsLazy
|
||||
OrcV2CBindingsLazy.c
|
||||
)
|
|
@ -0,0 +1,244 @@
|
|||
//===-------- BasicOrcV2CBindings.c - Basic OrcV2 C Bindings Demo ---------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm-c/Core.h"
|
||||
#include "llvm-c/Error.h"
|
||||
#include "llvm-c/IRReader.h"
|
||||
#include "llvm-c/Initialization.h"
|
||||
#include "llvm-c/LLJIT.h"
|
||||
#include "llvm-c/Support.h"
|
||||
#include "llvm-c/Target.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int handleError(LLVMErrorRef Err) {
|
||||
char *ErrMsg = LLVMGetErrorMessage(Err);
|
||||
fprintf(stderr, "Error: %s\n", ErrMsg);
|
||||
LLVMDisposeErrorMessage(ErrMsg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Example IR modules.
|
||||
//
|
||||
// Note that in the conditionally compiled modules, FooMod and BarMod, functions
|
||||
// have been given an _body suffix. This is to ensure that their names do not
|
||||
// clash with their lazy-reexports.
|
||||
// For clients who do not wish to rename function bodies (e.g. because they want
|
||||
// to re-use cached objects between static and JIT compiles) techniques exist to
|
||||
// avoid renaming. See the lazy-reexports section of the ORCv2 design doc.
|
||||
|
||||
const char FooMod[] = " define i32 @foo_body() { \n"
|
||||
" entry: \n"
|
||||
" ret i32 1 \n"
|
||||
" } \n";
|
||||
|
||||
const char BarMod[] = " define i32 @bar_body() { \n"
|
||||
" entry: \n"
|
||||
" ret i32 2 \n"
|
||||
" } \n";
|
||||
|
||||
const char MainMod[] =
|
||||
" define i32 @entry(i32 %argc) { \n"
|
||||
" entry: \n"
|
||||
" %and = and i32 %argc, 1 \n"
|
||||
" %tobool = icmp eq i32 %and, 0 \n"
|
||||
" br i1 %tobool, label %if.end, label %if.then \n"
|
||||
" \n"
|
||||
" if.then: \n"
|
||||
" %call = tail call i32 @foo() \n"
|
||||
" br label %return \n"
|
||||
" \n"
|
||||
" if.end: \n"
|
||||
" %call1 = tail call i32 @bar() \n"
|
||||
" br label %return \n"
|
||||
" \n"
|
||||
" return: \n"
|
||||
" %retval.0 = phi i32 [ %call, %if.then ], [ %call1, %if.end ] \n"
|
||||
" ret i32 %retval.0 \n"
|
||||
" } \n"
|
||||
" \n"
|
||||
" declare i32 @foo() \n"
|
||||
" declare i32 @bar() \n";
|
||||
|
||||
LLVMErrorRef parseExampleModule(const char *Source, size_t Len,
|
||||
const char *Name,
|
||||
LLVMOrcThreadSafeModuleRef *TSM) {
|
||||
// Create a new ThreadSafeContext and underlying LLVMContext.
|
||||
LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();
|
||||
|
||||
// Get a reference to the underlying LLVMContext.
|
||||
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);
|
||||
|
||||
// Wrap Source in a MemoryBuffer
|
||||
LLVMMemoryBufferRef MB =
|
||||
LLVMCreateMemoryBufferWithMemoryRange(Source, Len, Name, 0);
|
||||
|
||||
// Parse the LLVM module.
|
||||
LLVMModuleRef M;
|
||||
char *ErrMsg;
|
||||
if (LLVMParseIRInContext(Ctx, MB, &M, &ErrMsg)) {
|
||||
return LLVMCreateStringError(ErrMsg);
|
||||
// TODO: LLVMDisposeMessage(ErrMsg);
|
||||
}
|
||||
|
||||
// Our module is now complete. Wrap it and our ThreadSafeContext in a
|
||||
// ThreadSafeModule.
|
||||
*TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);
|
||||
|
||||
// Dispose of our local ThreadSafeContext value. The underlying LLVMContext
|
||||
// will be kept alive by our ThreadSafeModule, TSM.
|
||||
LLVMOrcDisposeThreadSafeContext(TSCtx);
|
||||
|
||||
return LLVMErrorSuccess;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
int MainResult = 0;
|
||||
|
||||
// Parse command line arguments and initialize LLVM Core.
|
||||
LLVMParseCommandLineOptions(argc, (const char **)argv, "");
|
||||
LLVMInitializeCore(LLVMGetGlobalPassRegistry());
|
||||
|
||||
// Initialize native target codegen and asm printer.
|
||||
LLVMInitializeNativeTarget();
|
||||
LLVMInitializeNativeAsmPrinter();
|
||||
|
||||
// Set up a JIT instance.
|
||||
LLVMOrcLLJITRef J;
|
||||
const char *TargetTriple;
|
||||
{
|
||||
LLVMErrorRef Err;
|
||||
if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
|
||||
MainResult = handleError(Err);
|
||||
goto llvm_shutdown;
|
||||
}
|
||||
TargetTriple = LLVMOrcLLJITGetTripleString(J);
|
||||
}
|
||||
|
||||
// Add our demo modules to the JIT.
|
||||
{
|
||||
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
|
||||
LLVMErrorRef Err;
|
||||
|
||||
LLVMOrcThreadSafeModuleRef FooTSM;
|
||||
if ((Err =
|
||||
parseExampleModule(FooMod, sizeof(FooMod), "foo-mod", &FooTSM))) {
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
|
||||
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, FooTSM))) {
|
||||
// If adding the ThreadSafeModule fails then we need to clean it up
|
||||
// ourselves. If adding it succeeds the JIT will manage the memory.
|
||||
LLVMOrcDisposeThreadSafeModule(FooTSM);
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
|
||||
LLVMOrcThreadSafeModuleRef BarTSM;
|
||||
if ((Err =
|
||||
parseExampleModule(BarMod, sizeof(BarMod), "bar-mod", &BarTSM))) {
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
|
||||
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, BarTSM))) {
|
||||
LLVMOrcDisposeThreadSafeModule(BarTSM);
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
|
||||
LLVMOrcThreadSafeModuleRef MainTSM;
|
||||
if ((Err = parseExampleModule(MainMod, sizeof(MainMod), "main-mod",
|
||||
&MainTSM))) {
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
|
||||
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, MainTSM))) {
|
||||
LLVMOrcDisposeThreadSafeModule(MainTSM);
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// add lazy reexports
|
||||
LLVMOrcIndirectStubsManagerRef ISM =
|
||||
LLVMOrcCreateLocalIndirectStubsManager(TargetTriple);
|
||||
|
||||
LLVMOrcLazyCallThroughManagerRef LCTM;
|
||||
{
|
||||
LLVMErrorRef Err;
|
||||
LLVMOrcExecutionSessionRef ES = LLVMOrcLLJITGetExecutionSession(J);
|
||||
if ((Err = LLVMOrcCreateLocalLazyCallThroughManager(TargetTriple, ES, 0,
|
||||
&LCTM))) {
|
||||
LLVMOrcDisposeIndirectStubsManager(ISM);
|
||||
MainResult = handleError(Err);
|
||||
goto jit_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMJITSymbolFlags flag = {
|
||||
LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};
|
||||
LLVMOrcCSymbolAliasMapPair ReExports[2] = {
|
||||
{LLVMOrcLLJITMangleAndIntern(J, "foo"),
|
||||
{LLVMOrcLLJITMangleAndIntern(J, "foo_body"), flag}},
|
||||
{LLVMOrcLLJITMangleAndIntern(J, "bar"),
|
||||
{LLVMOrcLLJITMangleAndIntern(J, "bar_body"), flag}},
|
||||
};
|
||||
|
||||
{
|
||||
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
|
||||
LLVMOrcMaterializationUnitRef MU =
|
||||
LLVMOrcLazyReexports(LCTM, ISM, MainJD, ReExports, 2);
|
||||
LLVMOrcJITDylibDefine(MainJD, MU);
|
||||
}
|
||||
|
||||
// Look up the address of our demo entry point.
|
||||
LLVMOrcJITTargetAddress EntryAddr;
|
||||
{
|
||||
LLVMErrorRef Err;
|
||||
if ((Err = LLVMOrcLLJITLookup(J, &EntryAddr, "entry"))) {
|
||||
MainResult = handleError(Err);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
// If we made it here then everything succeeded. Execute our JIT'd code.
|
||||
int32_t (*Entry)(int32_t) = (int32_t(*)(int32_t))EntryAddr;
|
||||
int32_t Result = Entry(argc);
|
||||
|
||||
printf("--- Result ---\n");
|
||||
printf("entry(%i) = %i\n", argc, Result);
|
||||
|
||||
cleanup : {
|
||||
LLVMOrcDisposeIndirectStubsManager(ISM);
|
||||
LLVMOrcDisposeLazyCallThroughManager(LCTM);
|
||||
}
|
||||
|
||||
jit_cleanup:
|
||||
// Destroy our JIT instance. This will clean up any memory that the JIT has
|
||||
// taken ownership of. This operation is non-trivial (e.g. it may need to
|
||||
// JIT static destructors) and may also fail. In that case we want to render
|
||||
// the error to stderr, but not overwrite any existing return value.
|
||||
{
|
||||
LLVMErrorRef Err;
|
||||
if ((Err = LLVMOrcDisposeLLJIT(J))) {
|
||||
int NewFailureResult = handleError(Err);
|
||||
if (MainResult == 0)
|
||||
MainResult = NewFailureResult;
|
||||
}
|
||||
}
|
||||
|
||||
llvm_shutdown:
|
||||
// Shut down LLVM.
|
||||
LLVMShutdown();
|
||||
|
||||
return MainResult;
|
||||
}
|
|
@ -123,6 +123,28 @@ typedef struct {
|
|||
*/
|
||||
typedef LLVMJITCSymbolMapPair *LLVMOrcCSymbolMapPairs;
|
||||
|
||||
/**
|
||||
* Represents a SymbolAliasMapEntry
|
||||
*/
|
||||
typedef struct {
|
||||
LLVMOrcSymbolStringPoolEntryRef Name;
|
||||
LLVMJITSymbolFlags Flags;
|
||||
} LLVMOrcCSymbolAliasMapEntry;
|
||||
|
||||
/**
|
||||
* Represents a pair of a symbol name and SymbolAliasMapEntry.
|
||||
*/
|
||||
typedef struct {
|
||||
LLVMOrcSymbolStringPoolEntryRef Name;
|
||||
LLVMOrcCSymbolAliasMapEntry Entry;
|
||||
} LLVMOrcCSymbolAliasMapPair;
|
||||
|
||||
/**
|
||||
* Represents a list of (SymbolStringPtr, (SymbolStringPtr, JITSymbolFlags))
|
||||
* pairs that can be used to construct a SymbolFlagsMap.
|
||||
*/
|
||||
typedef LLVMOrcCSymbolAliasMapPair *LLVMOrcCSymbolAliasMapPairs;
|
||||
|
||||
/**
|
||||
* Lookup kind. This can be used by definition generators when deciding whether
|
||||
* to produce a definition for a requested symbol.
|
||||
|
@ -373,6 +395,18 @@ typedef struct LLVMOrcOpaqueObjectTransformLayer
|
|||
typedef LLVMErrorRef (*LLVMOrcObjectTransformLayerTransformFunction)(
|
||||
void *Ctx, LLVMMemoryBufferRef *ObjInOut);
|
||||
|
||||
/**
|
||||
* A reference to an orc::IndirectStubsManager instance.
|
||||
*/
|
||||
typedef struct LLVMOrcOpaqueIndirectStubsManager
|
||||
*LLVMOrcIndirectStubsManagerRef;
|
||||
|
||||
/**
|
||||
* A reference to an orc::LazyCallThroughManager instance.
|
||||
*/
|
||||
typedef struct LLVMOrcOpaqueLazyCallThroughManager
|
||||
*LLVMOrcLazyCallThroughManagerRef;
|
||||
|
||||
/**
|
||||
* A reference to an orc::DumpObjects object.
|
||||
*
|
||||
|
@ -536,6 +570,33 @@ LLVMOrcMaterializationUnitRef LLVMOrcCreateCustomMaterializationUnit(
|
|||
LLVMOrcMaterializationUnitRef
|
||||
LLVMOrcAbsoluteSymbols(LLVMOrcCSymbolMapPairs Syms, size_t NumPairs);
|
||||
|
||||
/**
|
||||
* Create a MaterializationUnit to define lazy re-expots. These are callable
|
||||
* entry points that call through to the given symbols.
|
||||
*
|
||||
* This function takes ownership of the CallableAliases array. The Name
|
||||
* fields of the array elements are taken to have been retained for this
|
||||
* function. This allows the following pattern...
|
||||
*
|
||||
* size_t NumPairs;
|
||||
* LLVMOrcCSymbolAliasMapPairs CallableAliases;
|
||||
* -- Build CallableAliases array --
|
||||
* LLVMOrcMaterializationUnitRef MU =
|
||||
* LLVMOrcLazyReexports(LCTM, ISM, JD, CallableAliases, NumPairs);
|
||||
*
|
||||
* ... without requiring cleanup of the elements of the CallableAliases array afterwards.
|
||||
*
|
||||
* The client is still responsible for deleting the CallableAliases array itself.
|
||||
*
|
||||
* If a client wishes to reuse elements of the CallableAliases array after this call they
|
||||
* must explicitly retain each of the elements for themselves.
|
||||
*/
|
||||
LLVMOrcMaterializationUnitRef LLVMOrcLazyReexports(
|
||||
LLVMOrcLazyCallThroughManagerRef LCTM, LLVMOrcIndirectStubsManagerRef ISM,
|
||||
LLVMOrcJITDylibRef SourceRef, LLVMOrcCSymbolAliasMapPairs CallableAliases,
|
||||
size_t NumPairs);
|
||||
// TODO: ImplSymbolMad SrcJDLoc
|
||||
|
||||
/**
|
||||
* Create a "bare" JITDylib.
|
||||
*
|
||||
|
@ -799,6 +860,31 @@ void LLVMOrcObjectTransformLayerSetTransform(
|
|||
LLVMOrcObjectTransformLayerRef ObjTransformLayer,
|
||||
LLVMOrcObjectTransformLayerTransformFunction TransformFunction, void *Ctx);
|
||||
|
||||
/**
|
||||
* Create a LocalIndirectStubsManager from the given target triple.
|
||||
*
|
||||
* The resulting IndirectStubsManager is owned by the client
|
||||
* and must be disposed of by calling LLVMOrcDisposeDisposeIndirectStubsManager.
|
||||
*/
|
||||
LLVMOrcIndirectStubsManagerRef
|
||||
LLVMOrcCreateLocalIndirectStubsManager(const char *TargetTriple);
|
||||
|
||||
/**
|
||||
* Dispose of an IndirectStubsManager.
|
||||
*/
|
||||
void LLVMOrcDisposeIndirectStubsManager(LLVMOrcIndirectStubsManagerRef ISM);
|
||||
|
||||
LLVMErrorRef LLVMOrcCreateLocalLazyCallThroughManager(
|
||||
const char *TargetTriple, LLVMOrcExecutionSessionRef ES,
|
||||
LLVMOrcJITTargetAddress ErrorHandlerAddr,
|
||||
LLVMOrcLazyCallThroughManagerRef *LCTM);
|
||||
|
||||
/**
|
||||
* Dispose of an LazyCallThroughManager.
|
||||
*/
|
||||
void LLVMOrcDisposeLazyCallThroughManager(
|
||||
LLVMOrcLazyCallThroughManagerRef LCTM);
|
||||
|
||||
/**
|
||||
* Create a DumpObjects instance.
|
||||
*
|
||||
|
|
|
@ -98,9 +98,12 @@ DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IRTransformLayer, LLVMOrcIRTransformLayerRef)
|
|||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectTransformLayer,
|
||||
LLVMOrcObjectTransformLayerRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(DumpObjects, LLVMOrcDumpObjectsRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(IndirectStubsManager,
|
||||
LLVMOrcIndirectStubsManagerRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LazyCallThroughManager,
|
||||
LLVMOrcLazyCallThroughManagerRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJITBuilder, LLVMOrcLLJITBuilderRef)
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef)
|
||||
|
||||
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(TargetMachine, LLVMTargetMachineRef)
|
||||
|
||||
namespace llvm {
|
||||
|
@ -341,6 +344,26 @@ LLVMOrcAbsoluteSymbols(LLVMOrcCSymbolMapPairs Syms, size_t NumPairs) {
|
|||
return wrap(absoluteSymbols(std::move(SM)).release());
|
||||
}
|
||||
|
||||
LLVMOrcMaterializationUnitRef LLVMOrcLazyReexports(
|
||||
LLVMOrcLazyCallThroughManagerRef LCTM, LLVMOrcIndirectStubsManagerRef ISM,
|
||||
LLVMOrcJITDylibRef SourceJD, LLVMOrcCSymbolAliasMapPairs CallableAliases,
|
||||
size_t NumPairs) {
|
||||
|
||||
SymbolAliasMap SAM;
|
||||
for (size_t I = 0; I != NumPairs; ++I) {
|
||||
auto pair = CallableAliases[I];
|
||||
JITSymbolFlags Flags = toJITSymbolFlags(pair.Entry.Flags);
|
||||
SymbolStringPtr Name =
|
||||
OrcV2CAPIHelper::moveToSymbolStringPtr(unwrap(pair.Entry.Name));
|
||||
SAM[OrcV2CAPIHelper::moveToSymbolStringPtr(unwrap(pair.Name))] =
|
||||
SymbolAliasMapEntry(Name, Flags);
|
||||
}
|
||||
|
||||
return wrap(lazyReexports(*unwrap(LCTM), *unwrap(ISM), *unwrap(SourceJD),
|
||||
std::move(SAM))
|
||||
.release());
|
||||
}
|
||||
|
||||
LLVMOrcJITDylibRef
|
||||
LLVMOrcExecutionSessionCreateBareJITDylib(LLVMOrcExecutionSessionRef ES,
|
||||
const char *Name) {
|
||||
|
@ -725,3 +748,31 @@ void LLVMOrcRTDyldObjectLinkingLayerRegisterJITEventListener(
|
|||
LLVMOrcIRTransformLayerRef LLVMOrcLLJITGetIRTransformLayer(LLVMOrcLLJITRef J) {
|
||||
return wrap(&unwrap(J)->getIRTransformLayer());
|
||||
}
|
||||
|
||||
LLVMOrcIndirectStubsManagerRef
|
||||
LLVMOrcCreateLocalIndirectStubsManager(const char *TargetTriple) {
|
||||
auto builder = createLocalIndirectStubsManagerBuilder(Triple(TargetTriple));
|
||||
return wrap(builder().release());
|
||||
}
|
||||
|
||||
void LLVMOrcDisposeIndirectStubsManager(LLVMOrcIndirectStubsManagerRef ISM) {
|
||||
std::unique_ptr<IndirectStubsManager> TmpISM(unwrap(ISM));
|
||||
}
|
||||
|
||||
LLVMErrorRef LLVMOrcCreateLocalLazyCallThroughManager(
|
||||
const char *TargetTriple, LLVMOrcExecutionSessionRef ES,
|
||||
LLVMOrcJITTargetAddress ErrorHandlerAddr,
|
||||
LLVMOrcLazyCallThroughManagerRef *Result) {
|
||||
auto LCTM = createLocalLazyCallThroughManager(Triple(TargetTriple),
|
||||
*unwrap(ES), ErrorHandlerAddr);
|
||||
|
||||
if (!LCTM)
|
||||
return wrap(LCTM.takeError());
|
||||
*Result = wrap(LCTM->release());
|
||||
return LLVMErrorSuccess;
|
||||
}
|
||||
|
||||
void LLVMOrcDisposeLazyCallThroughManager(
|
||||
LLVMOrcLazyCallThroughManagerRef LCM) {
|
||||
std::unique_ptr<LazyCallThroughManager> TmpLCM(unwrap(LCM));
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@ if(LLVM_BUILD_EXAMPLES)
|
|||
OrcV2CBindingsAddObjectFile
|
||||
OrcV2CBindingsRemovableCode
|
||||
OrcV2CBindingsReflectProcessSymbols
|
||||
OrcV2CBindingsLazy
|
||||
)
|
||||
if(CMAKE_HOST_UNIX)
|
||||
list(APPEND LLVM_TEST_DEPENDS
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
# RUN: OrcV2CBindingsLazy 2>&1 | FileCheck -check-prefix=THIS %s
|
||||
# RUN: OrcV2CBindingsLazy 0 2>&1 | FileCheck -check-prefix=OTHER %s
|
||||
|
||||
# THIS: entry(1) = 1
|
||||
# OTHER: entry(2) = 2
|
|
@ -186,7 +186,8 @@ tools.extend([
|
|||
ToolSubst('OrcV2CBindingsBasicUsage', unresolved='ignore'),
|
||||
ToolSubst('OrcV2CBindingsAddObjectFile', unresolved='ignore'),
|
||||
ToolSubst('OrcV2CBindingsRemovableCode', unresolved='ignore'),
|
||||
ToolSubst('OrcV2CBindingsReflectProcessSymbols', unresolved='ignore')])
|
||||
ToolSubst('OrcV2CBindingsReflectProcessSymbols', unresolved='ignore'),
|
||||
ToolSubst('OrcV2CBindingsLazy', unresolved='ignore')])
|
||||
|
||||
llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir)
|
||||
|
||||
|
|
Loading…
Reference in New Issue