858 lines · cpp
1//===--- OrcCAPITest.cpp - Unit tests for the OrcJIT v2 C API ---*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm-c/Core.h"10#include "llvm-c/Error.h"11#include "llvm-c/LLJIT.h"12#include "llvm-c/LLJITUtils.h"13#include "llvm-c/Orc.h"14#include "gtest/gtest.h"15 16#include "llvm/Analysis/TargetLibraryInfo.h"17#include "llvm/ExecutionEngine/Orc/CompileUtils.h"18#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"19#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"20#include "llvm/IR/LLVMContext.h"21#include "llvm/IR/Module.h"22#include "llvm/IRReader/IRReader.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/FormatVariadic.h"25#include "llvm/Support/SourceMgr.h"26#include "llvm/TargetParser/Triple.h"27#include "llvm/Testing/Support/Error.h"28#include <string>29 30using namespace llvm;31using namespace llvm::orc;32 33DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)34DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)35 36// A class that sets strings for extension attributes by querying37// TargetLibraryInfo.38struct TargetI32ArgExtensions {39 std::string Ret;40 std::string Arg;41 TargetI32ArgExtensions(std::string TargetTriple, bool Signed = true) {42 Triple T(TargetTriple);43 if (auto AK = TargetLibraryInfo::getExtAttrForI32Return(T, Signed))44 Ret = Attribute::getNameFromAttrKind(AK).str() + " ";45 if (auto AK = TargetLibraryInfo::getExtAttrForI32Param(T, Signed))46 Arg = Attribute::getNameFromAttrKind(AK).str() + " ";47 }48};49 50// OrcCAPITestBase contains several helper methods and pointers for unit tests51// written for the LLVM-C API. It provides the following helpers:52//53// 1. Jit: an LLVMOrcLLJIT instance which is freed upon test exit54// 2. ExecutionSession: the LLVMOrcExecutionSession for the JIT55// 3. MainDylib: the main JITDylib for the LLJIT instance56// 4. materializationUnitFn: function pointer to an empty function, used for57// materialization unit testing58// 5. definitionGeneratorFn: function pointer for a basic59// LLVMOrcCAPIDefinitionGeneratorTryToGenerateFunction60// 6. createTestModule: helper method for creating a basic thread-safe-module61class OrcCAPITestBase : public testing::Test {62protected:63 LLVMOrcLLJITRef Jit = nullptr;64 LLVMOrcExecutionSessionRef ExecutionSession = nullptr;65 LLVMOrcJITDylibRef MainDylib = nullptr;66 67public:68 static void SetUpTestCase() {69 LLVMInitializeNativeTarget();70 LLVMInitializeNativeAsmParser();71 LLVMInitializeNativeAsmPrinter();72 73 // Attempt to set up a JIT instance once to verify that we can.74 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;75 if (LLVMErrorRef E = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB)) {76 // If setup fails then disable these tests.77 LLVMConsumeError(E);78 TargetSupported = false;79 return;80 }81 82 // Capture the target triple. We'll use it for both verification that83 // this target is *supposed* to be supported, and error messages in84 // the case that it fails anyway.85 char *TT = LLVMOrcJITTargetMachineBuilderGetTargetTriple(JTMB);86 TargetTriple = TT;87 LLVMDisposeMessage(TT);88 89 if (!isSupported(TargetTriple)) {90 // If this triple isn't supported then bail out.91 TargetSupported = false;92 LLVMOrcDisposeJITTargetMachineBuilder(JTMB);93 return;94 }95 96 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();97 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);98 LLVMOrcLLJITRef J;99 if (LLVMErrorRef E = LLVMOrcCreateLLJIT(&J, Builder)) {100 // If setup fails then disable these tests.101 TargetSupported = false;102 LLVMConsumeError(E);103 return;104 }105 106 LLVMOrcDisposeLLJIT(J);107 TargetSupported = true;108 109 // Create test functions in text format, with the proper extension110 // attributes.111 if (SumExample.empty()) {112 TargetI32ArgExtensions ArgExt(TargetTriple);113 std::ostringstream OS;114 OS << "define " << ArgExt.Ret << "i32 "115 << "@sum(i32 " << ArgExt.Arg << "%x, i32 " << ArgExt.Arg << "%y)"116 << R"( {117 entry:118 %r = add nsw i32 %x, %y119 ret i32 %r120 }121 )";122 SumExample = OS.str();123 124 OS << R"(125 !llvm.module.flags = !{!0}126 !llvm.dbg.cu = !{!1}127 !0 = !{i32 2, !"Debug Info Version", i32 3}128 !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, emissionKind: FullDebug)129 !2 = !DIFile(filename: "sum.c", directory: "/tmp")130 )";131 SumDebugExample = OS.str();132 }133 }134 135 void SetUp() override {136 if (!TargetSupported)137 GTEST_SKIP();138 139 LLVMOrcJITTargetMachineBuilderRef JTMB = nullptr;140 LLVMErrorRef E1 = LLVMOrcJITTargetMachineBuilderDetectHost(&JTMB);141 assert(E1 == LLVMErrorSuccess && "Expected call to detect host to succeed");142 (void)E1;143 144 LLVMOrcLLJITBuilderRef Builder = LLVMOrcCreateLLJITBuilder();145 LLVMOrcLLJITBuilderSetJITTargetMachineBuilder(Builder, JTMB);146 LLVMErrorRef E2 = LLVMOrcCreateLLJIT(&Jit, Builder);147 assert(E2 == LLVMErrorSuccess &&148 "Expected call to create LLJIT to succeed");149 (void)E2;150 ExecutionSession = LLVMOrcLLJITGetExecutionSession(Jit);151 MainDylib = LLVMOrcLLJITGetMainJITDylib(Jit);152 }153 void TearDown() override {154 // Check whether Jit has already been torn down -- we allow clients to do155 // this manually to check teardown behavior.156 if (Jit) {157 LLVMOrcDisposeLLJIT(Jit);158 Jit = nullptr;159 }160 }161 162protected:163 static bool isSupported(StringRef Triple) {164 // TODO: Print error messages in failure logs, use them to audit this list.165 // Some architectures may be unsupportable or missing key components, but166 // some may just be failing due to bugs in this testcase.167 if (Triple.starts_with("armv7") || Triple.starts_with("armv8l"))168 return false;169 return true;170 }171 172 static void materializationUnitFn() {}173 174 // Stub definition generator, where all Names are materialized from the175 // materializationUnitFn() test function and defined into the JIT Dylib176 static LLVMErrorRef177 definitionGeneratorFn(LLVMOrcDefinitionGeneratorRef G, void *Ctx,178 LLVMOrcLookupStateRef *LS, LLVMOrcLookupKind K,179 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags F,180 LLVMOrcCLookupSet Names, size_t NamesCount) {181 for (size_t I = 0; I < NamesCount; I++) {182 LLVMOrcCLookupSetElement Element = Names[I];183 LLVMOrcJITTargetAddress Addr =184 (LLVMOrcJITTargetAddress)(&materializationUnitFn);185 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};186 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};187 LLVMOrcRetainSymbolStringPoolEntry(Element.Name);188 LLVMOrcCSymbolMapPair Pair = {Element.Name, Sym};189 LLVMOrcCSymbolMapPair Pairs[] = {Pair};190 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);191 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);192 if (Err)193 return Err;194 }195 return LLVMErrorSuccess;196 }197 198 static Error createSMDiagnosticError(llvm::SMDiagnostic &Diag) {199 std::string Msg;200 {201 raw_string_ostream OS(Msg);202 Diag.print("", OS);203 }204 return make_error<StringError>(std::move(Msg), inconvertibleErrorCode());205 }206 207 // Create an LLVM IR module from the given StringRef.208 static Expected<std::unique_ptr<Module>>209 parseTestModule(LLVMContext &Ctx, StringRef Source, StringRef Name) {210 assert(TargetSupported &&211 "Attempted to create module for unsupported target");212 SMDiagnostic Err;213 if (auto M = parseIR(MemoryBufferRef(Source, Name), Err, Ctx))214 return std::move(M);215 return createSMDiagnosticError(Err);216 }217 218 // returns the sum of its two parameters219 static LLVMOrcThreadSafeModuleRef createTestModule(StringRef Source,220 StringRef Name) {221 auto Ctx = std::make_unique<LLVMContext>();222 auto M = cantFail(parseTestModule(*Ctx, Source, Name));223 return wrap(new ThreadSafeModule(std::move(M), std::move(Ctx)));224 }225 226 static LLVMMemoryBufferRef createTestObject(StringRef Source,227 StringRef Name) {228 auto Ctx = std::make_unique<LLVMContext>();229 auto M = cantFail(parseTestModule(*Ctx, Source, Name));230 231 auto JTMB = cantFail(JITTargetMachineBuilder::detectHost());232 M->setDataLayout(cantFail(JTMB.getDefaultDataLayoutForTarget()));233 auto TM = cantFail(JTMB.createTargetMachine());234 235 SimpleCompiler SC(*TM);236 auto ObjBuffer = cantFail(SC(*M));237 return wrap(ObjBuffer.release());238 }239 240 static std::string TargetTriple;241 static bool TargetSupported;242 243 static std::string SumExample;244 static std::string SumDebugExample;245};246 247std::string OrcCAPITestBase::TargetTriple;248bool OrcCAPITestBase::TargetSupported = false;249 250std::string OrcCAPITestBase::SumExample;251std::string OrcCAPITestBase::SumDebugExample;252 253// Consumes the given error ref and returns the string error message.254static std::string toString(LLVMErrorRef E) {255 char *ErrMsg = LLVMGetErrorMessage(E);256 std::string Result(ErrMsg);257 LLVMDisposeErrorMessage(ErrMsg);258 return Result;259}260 261TEST_F(OrcCAPITestBase, SymbolStringPoolUniquing) {262 LLVMOrcSymbolStringPoolEntryRef E1 =263 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");264 LLVMOrcSymbolStringPoolEntryRef E2 =265 LLVMOrcExecutionSessionIntern(ExecutionSession, "aaa");266 LLVMOrcSymbolStringPoolEntryRef E3 =267 LLVMOrcExecutionSessionIntern(ExecutionSession, "bbb");268 const char *SymbolName = LLVMOrcSymbolStringPoolEntryStr(E1);269 ASSERT_EQ(E1, E2) << "String pool entries are not unique";270 ASSERT_NE(E1, E3) << "Unique symbol pool entries are equal";271 ASSERT_STREQ("aaa", SymbolName) << "String value of symbol is not equal";272 LLVMOrcReleaseSymbolStringPoolEntry(E1);273 LLVMOrcReleaseSymbolStringPoolEntry(E2);274 LLVMOrcReleaseSymbolStringPoolEntry(E3);275}276 277TEST_F(OrcCAPITestBase, JITDylibLookup) {278 LLVMOrcJITDylibRef DoesNotExist =279 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");280 ASSERT_FALSE(!!DoesNotExist);281 LLVMOrcJITDylibRef L1 =282 LLVMOrcExecutionSessionCreateBareJITDylib(ExecutionSession, "test");283 LLVMOrcJITDylibRef L2 =284 LLVMOrcExecutionSessionGetJITDylibByName(ExecutionSession, "test");285 ASSERT_EQ(L1, L2) << "Located JIT Dylib is not equal to original";286}287 288TEST_F(OrcCAPITestBase, MaterializationUnitCreation) {289 LLVMOrcSymbolStringPoolEntryRef Name =290 LLVMOrcLLJITMangleAndIntern(Jit, "test");291 LLVMJITSymbolFlags Flags = {LLVMJITSymbolGenericFlagsWeak, 0};292 LLVMOrcJITTargetAddress Addr =293 (LLVMOrcJITTargetAddress)(&materializationUnitFn);294 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};295 LLVMOrcCSymbolMapPair Pair = {Name, Sym};296 LLVMOrcCSymbolMapPair Pairs[] = {Pair};297 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);298 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MU))299 FAIL() << "Unexpected error while adding \"test\" symbol (triple = "300 << TargetTriple << "): " << toString(E);301 LLVMOrcJITTargetAddress OutAddr;302 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))303 FAIL() << "Failed to look up \"test\" symbol (triple = " << TargetTriple304 << "): " << toString(E);305 ASSERT_EQ(Addr, OutAddr);306}307 308struct ExecutionSessionLookupHelper {309 bool ExpectSuccess = true;310 bool CallbackReceived = false;311 size_t NumExpectedPairs;312 LLVMOrcCSymbolMapPair *ExpectedMapping;313};314 315static void executionSessionLookupHandlerCallback(LLVMErrorRef Err,316 LLVMOrcCSymbolMapPairs Result,317 size_t NumPairs,318 void *RawCtx) {319 auto *Ctx = static_cast<ExecutionSessionLookupHelper *>(RawCtx);320 Ctx->CallbackReceived = true;321 if (Ctx->ExpectSuccess) {322 EXPECT_THAT_ERROR(unwrap(Err), Succeeded());323 EXPECT_EQ(NumPairs, Ctx->NumExpectedPairs)324 << "Expected " << Ctx->NumExpectedPairs << " entries in result, got "325 << NumPairs;326 auto ExpectedMappingEnd = Ctx->ExpectedMapping + Ctx->NumExpectedPairs;327 for (unsigned I = 0; I != NumPairs; ++I) {328 auto J =329 std::find_if(Ctx->ExpectedMapping, ExpectedMappingEnd,330 [N = Result[I].Name](const LLVMOrcCSymbolMapPair &Val) {331 return Val.Name == N;332 });333 EXPECT_NE(J, ExpectedMappingEnd)334 << "Missing symbol \""335 << LLVMOrcSymbolStringPoolEntryStr(Result[I].Name) << "\"";336 if (J != ExpectedMappingEnd) {337 EXPECT_EQ(Result[I].Sym.Address, J->Sym.Address)338 << "Result map for \"" << Result[I].Name339 << "\" differs from expected value: "340 << formatv("{0:x} vs {1:x}", Result[I].Sym.Address, J->Sym.Address);341 }342 }343 } else344 EXPECT_THAT_ERROR(unwrap(Err), Failed());345}346 347TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Success) {348 // Test a successful generic lookup. We will look up three symbols over two349 // JITDylibs: { "Foo" (Required), "Bar" (Weakly-ref), "Baz" (Required) } over350 // { MainJITDylib (Exported-only), ExtraJD (All symbols) }.351 //352 // Foo will be defined as exported in MainJD.353 // Bar will be defined as non-exported in MainJD.354 // Baz will be defined as non-exported in ExtraJD.355 //356 // This will require (1) that we find the regular exported symbol Foo in357 // MainJD, (2) that we *don't* find the non-exported symbol Bar in MainJD358 // but also don't error (since it's weakly referenced), and (3) that we359 // find the non-exported symbol Baz in ExtraJD (since we're searching all360 // symbols in ExtraJD).361 362 ExecutionSessionLookupHelper H;363 LLVMOrcSymbolStringPoolEntryRef Foo = LLVMOrcLLJITMangleAndIntern(Jit, "Foo");364 LLVMOrcSymbolStringPoolEntryRef Bar = LLVMOrcLLJITMangleAndIntern(Jit, "Bar");365 LLVMOrcSymbolStringPoolEntryRef Baz = LLVMOrcLLJITMangleAndIntern(Jit, "Baz");366 367 // Create ExtraJD.368 LLVMOrcJITDylibRef ExtraJD = nullptr;369 if (auto E = LLVMOrcExecutionSessionCreateJITDylib(ExecutionSession, &ExtraJD,370 "ExtraJD")) {371 FAIL() << "Unexpected error while creating JITDylib \"ExtraJD\" (triple = "372 << TargetTriple << "): " << toString(E);373 return;374 }375 376 // Add exported symbols "Foo" and "Bar" to Main JITDylib.377 LLVMOrcRetainSymbolStringPoolEntry(Foo);378 LLVMOrcRetainSymbolStringPoolEntry(Bar);379 LLVMOrcCSymbolMapPair MainJDPairs[] = {380 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}},381 {Bar, {0x2, {LLVMJITSymbolGenericFlagsNone, 0}}}};382 LLVMOrcMaterializationUnitRef MainJDMU =383 LLVMOrcAbsoluteSymbols(MainJDPairs, 2);384 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(MainDylib, MainJDMU))385 FAIL() << "Unexpected error while adding MainDylib symbols (triple = "386 << TargetTriple << "): " << toString(E);387 388 // Add non-exported symbol "Baz" to ExtraJD.389 LLVMOrcRetainSymbolStringPoolEntry(Baz);390 LLVMOrcCSymbolMapPair ExtraJDPairs[] = {391 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}};392 LLVMOrcMaterializationUnitRef ExtraJDMU =393 LLVMOrcAbsoluteSymbols(ExtraJDPairs, 1);394 if (LLVMErrorRef E = LLVMOrcJITDylibDefine(ExtraJD, ExtraJDMU))395 FAIL() << "Unexpected error while adding ExtraJD symbols (triple = "396 << TargetTriple << "): " << toString(E);397 398 // Create expected mapping for result:399 LLVMOrcCSymbolMapPair ExpectedMapping[] = {400 {Foo, {0x1, {LLVMJITSymbolGenericFlagsExported, 0}}},401 {Baz, {0x3, {LLVMJITSymbolGenericFlagsNone, 0}}}};402 H.ExpectedMapping = ExpectedMapping;403 H.NumExpectedPairs = 2;404 405 // Issue the lookup. We're using the default same-thread dispatch, so the406 // handler should have run by the time we return from this call.407 LLVMOrcCJITDylibSearchOrderElement SO[] = {408 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly},409 {ExtraJD, LLVMOrcJITDylibLookupFlagsMatchAllSymbols}};410 411 LLVMOrcRetainSymbolStringPoolEntry(Foo);412 LLVMOrcRetainSymbolStringPoolEntry(Bar);413 LLVMOrcRetainSymbolStringPoolEntry(Baz);414 LLVMOrcCLookupSetElement LS[] = {415 {Foo, LLVMOrcSymbolLookupFlagsRequiredSymbol},416 {Bar, LLVMOrcSymbolLookupFlagsWeaklyReferencedSymbol},417 {Baz, LLVMOrcSymbolLookupFlagsRequiredSymbol}};418 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,419 2, LS, 3, executionSessionLookupHandlerCallback,420 &H);421 422 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received";423 424 // Release our local string ptrs.425 LLVMOrcReleaseSymbolStringPoolEntry(Baz);426 LLVMOrcReleaseSymbolStringPoolEntry(Bar);427 LLVMOrcReleaseSymbolStringPoolEntry(Foo);428}429 430TEST_F(OrcCAPITestBase, ExecutionSessionLookup_Failure) {431 // Test generic lookup failure case. We will look up a symbol in MainDylib432 // without defining it. We expect this to result in a symbol-not-found error.433 434 ExecutionSessionLookupHelper H;435 H.ExpectSuccess = false;436 437 LLVMOrcCJITDylibSearchOrderElement SO[] = {438 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}};439 LLVMOrcCLookupSetElement LS[] = {{LLVMOrcLLJITMangleAndIntern(Jit, "Foo"),440 LLVMOrcSymbolLookupFlagsRequiredSymbol}};441 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,442 1, LS, 1, executionSessionLookupHandlerCallback,443 &H);444 445 EXPECT_TRUE(H.CallbackReceived) << "Lookup callback never received";446}447 448TEST_F(OrcCAPITestBase, DefinitionGenerators) {449 LLVMOrcDefinitionGeneratorRef Gen =450 LLVMOrcCreateCustomCAPIDefinitionGenerator(&definitionGeneratorFn,451 nullptr, nullptr);452 LLVMOrcJITDylibAddGenerator(MainDylib, Gen);453 LLVMOrcJITTargetAddress OutAddr;454 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &OutAddr, "test"))455 FAIL() << "The DefinitionGenerator did not create symbol \"test\" "456 << "(triple = " << TargetTriple << "): " << toString(E);457 LLVMOrcJITTargetAddress ExpectedAddr =458 (LLVMOrcJITTargetAddress)(&materializationUnitFn);459 ASSERT_EQ(ExpectedAddr, OutAddr);460}461 462#if defined(_AIX)463TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerDefinitionLifetime) {464#else465TEST_F(OrcCAPITestBase, ResourceTrackerDefinitionLifetime) {466#endif467 // This test case ensures that all symbols loaded into a JITDylib with a468 // ResourceTracker attached are cleared from the JITDylib once the RT is469 // removed.470 LLVMOrcResourceTrackerRef RT =471 LLVMOrcJITDylibCreateResourceTracker(MainDylib);472 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");473 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, RT, TSM))474 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple475 << "): " << toString(E);476 LLVMOrcJITTargetAddress TestFnAddr;477 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))478 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple479 << "): " << toString(E);480 ASSERT_TRUE(!!TestFnAddr);481 LLVMOrcResourceTrackerRemove(RT);482 LLVMOrcJITTargetAddress OutAddr;483 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &OutAddr, "sum");484 ASSERT_TRUE(Err);485 LLVMConsumeError(Err);486 487 ASSERT_FALSE(OutAddr);488 LLVMOrcReleaseResourceTracker(RT);489}490 491#if defined(_AIX)492TEST_F(OrcCAPITestBase, DISABLED_ResourceTrackerTransfer) {493#else494TEST_F(OrcCAPITestBase, ResourceTrackerTransfer) {495#endif496 LLVMOrcResourceTrackerRef DefaultRT =497 LLVMOrcJITDylibGetDefaultResourceTracker(MainDylib);498 LLVMOrcResourceTrackerRef RT2 =499 LLVMOrcJITDylibCreateResourceTracker(MainDylib);500 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");501 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModuleWithRT(Jit, DefaultRT, TSM))502 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple503 << "): " << toString(E);504 LLVMOrcJITTargetAddress Addr;505 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &Addr, "sum"))506 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple507 << "): " << toString(E);508 LLVMOrcResourceTrackerTransferTo(DefaultRT, RT2);509 LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "sum");510 ASSERT_FALSE(Err);511 LLVMOrcReleaseResourceTracker(RT2);512}513 514#if defined(_AIX)515TEST_F(OrcCAPITestBase, DISABLED_AddObjectBuffer) {516#else517TEST_F(OrcCAPITestBase, AddObjectBuffer) {518#endif519 LLVMOrcObjectLayerRef ObjLinkingLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);520 LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll");521 522 if (LLVMErrorRef E = LLVMOrcObjectLayerAddObjectFile(ObjLinkingLayer,523 MainDylib, ObjBuffer))524 FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "525 << TargetTriple << "): " << toString(E);526 527 LLVMOrcJITTargetAddress SumAddr;528 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))529 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple530 << "): " << toString(E);531 ASSERT_TRUE(!!SumAddr);532}533 534// JITLink debug support plugins put information about JITed code in this GDB535// JIT Interface global from OrcTargetProcess.536extern "C" LLVM_ABI struct jit_descriptor __jit_debug_descriptor;537 538static void *findLastDebugDescriptorEntryPtr() {539 struct jit_code_entry *Last = __jit_debug_descriptor.first_entry;540 while (Last && Last->next_entry)541 Last = Last->next_entry;542 return Last;543}544 545#if defined(_AIX) or not(defined(__ELF__) or defined(__MACH__))546TEST_F(OrcCAPITestBase, DISABLED_EnableDebugSupport) {547#else548static LLVM_ATTRIBUTE_USED void linkComponents() {549 errs() << "Linking in runtime functions\n"550 << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n';551}552TEST_F(OrcCAPITestBase, EnableDebugSupport) {553#endif554 void *Before = findLastDebugDescriptorEntryPtr();555 LLVMMemoryBufferRef ObjBuffer = createTestObject(SumDebugExample, "sum.ll");556 LLVMOrcObjectLayerRef ObjLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);557 558 if (LLVMErrorRef E = LLVMOrcLLJITEnableDebugSupport(Jit)) {559 EXPECT_FALSE(isa<ObjectLinkingLayer>(unwrap(ObjLayer)))560 << "Error testing LLJIT debug support "561 << "(triple = " << TargetTriple << "): " << toString(E);562 GTEST_SKIP() << "LLJIT C bindings provide debug support only for JITLink";563 }564 565 if (LLVMErrorRef E =566 LLVMOrcObjectLayerAddObjectFile(ObjLayer, MainDylib, ObjBuffer))567 FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "568 << TargetTriple << "): " << toString(E);569 570 LLVMOrcJITTargetAddress SumAddr;571 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))572 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple573 << "): " << toString(E);574 575 void *After = findLastDebugDescriptorEntryPtr();576 ASSERT_NE(Before, After);577}578 579#if defined(_AIX)580TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) {581#else582TEST_F(OrcCAPITestBase, ExecutionTest) {583#endif584 using SumFunctionType = int32_t (*)(int32_t, int32_t);585 586 // This test performs OrcJIT compilation of a simple sum module587 LLVMInitializeNativeAsmPrinter();588 LLVMOrcThreadSafeModuleRef TSM = createTestModule(SumExample, "sum.ll");589 if (LLVMErrorRef E = LLVMOrcLLJITAddLLVMIRModule(Jit, MainDylib, TSM))590 FAIL() << "Failed to add LLVM IR module to LLJIT (triple = " << TargetTriple591 << ")" << toString(E);592 LLVMOrcJITTargetAddress TestFnAddr;593 if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &TestFnAddr, "sum"))594 FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple595 << "): " << toString(E);596 auto *SumFn = (SumFunctionType)(TestFnAddr);597 int32_t Result = SumFn(1, 1);598 ASSERT_EQ(2, Result);599}600 601void Destroy(void *Ctx) {}602 603void TargetFn() {}604 605void Materialize(void *Ctx, LLVMOrcMaterializationResponsibilityRef MR) {606 LLVMOrcJITDylibRef JD =607 LLVMOrcMaterializationResponsibilityGetTargetDylib(MR);608 ASSERT_TRUE(!!JD);609 610 LLVMOrcExecutionSessionRef ES =611 LLVMOrcMaterializationResponsibilityGetExecutionSession(MR);612 ASSERT_TRUE(!!ES);613 614 LLVMOrcSymbolStringPoolEntryRef InitSym =615 LLVMOrcMaterializationResponsibilityGetInitializerSymbol(MR);616 ASSERT_TRUE(!InitSym);617 618 size_t NumSymbols;619 LLVMOrcCSymbolFlagsMapPairs Symbols =620 LLVMOrcMaterializationResponsibilityGetSymbols(MR, &NumSymbols);621 622 ASSERT_TRUE(!!Symbols);623 ASSERT_EQ(NumSymbols, (size_t)1);624 625 LLVMOrcSymbolStringPoolEntryRef *RequestedSymbols =626 LLVMOrcMaterializationResponsibilityGetRequestedSymbols(MR, &NumSymbols);627 628 ASSERT_TRUE(!!RequestedSymbols);629 ASSERT_EQ(NumSymbols, (size_t)1);630 631 LLVMOrcCSymbolFlagsMapPair TargetSym = Symbols[0];632 633 ASSERT_EQ(RequestedSymbols[0], TargetSym.Name);634 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);635 636 LLVMOrcDisposeCSymbolFlagsMap(Symbols);637 LLVMOrcDisposeSymbols(RequestedSymbols);638 639 LLVMOrcJITTargetAddress Addr = (LLVMOrcJITTargetAddress)(&TargetFn);640 641 LLVMJITSymbolFlags Flags = {642 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};643 ASSERT_EQ(TargetSym.Flags.GenericFlags, Flags.GenericFlags);644 ASSERT_EQ(TargetSym.Flags.TargetFlags, Flags.TargetFlags);645 646 LLVMJITEvaluatedSymbol Sym = {Addr, Flags};647 648 LLVMOrcLLJITRef J = (LLVMOrcLLJITRef)Ctx;649 650 LLVMOrcSymbolStringPoolEntryRef OtherSymbol =651 LLVMOrcLLJITMangleAndIntern(J, "other");652 LLVMOrcSymbolStringPoolEntryRef DependencySymbol =653 LLVMOrcLLJITMangleAndIntern(J, "dependency");654 655 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);656 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);657 LLVMOrcCSymbolFlagsMapPair NewSymbols[] = {658 {OtherSymbol, Flags},659 {DependencySymbol, Flags},660 };661 LLVMOrcMaterializationResponsibilityDefineMaterializing(MR, NewSymbols, 2);662 663 LLVMOrcRetainSymbolStringPoolEntry(OtherSymbol);664 LLVMOrcMaterializationResponsibilityRef OtherMR = NULL;665 {666 LLVMErrorRef Err = LLVMOrcMaterializationResponsibilityDelegate(667 MR, &OtherSymbol, 1, &OtherMR);668 if (Err) {669 char *ErrMsg = LLVMGetErrorMessage(Err);670 fprintf(stderr, "Error: %s\n", ErrMsg);671 LLVMDisposeErrorMessage(ErrMsg);672 LLVMOrcMaterializationResponsibilityFailMaterialization(MR);673 LLVMOrcDisposeMaterializationResponsibility(MR);674 return;675 }676 }677 assert(OtherMR);678 679 LLVMOrcCSymbolMapPair OtherPair = {OtherSymbol, Sym};680 LLVMOrcMaterializationUnitRef OtherMU = LLVMOrcAbsoluteSymbols(&OtherPair, 1);681 // OtherSymbol is no longer owned by us682 {683 LLVMErrorRef Err =684 LLVMOrcMaterializationResponsibilityReplace(OtherMR, OtherMU);685 if (Err) {686 char *ErrMsg = LLVMGetErrorMessage(Err);687 fprintf(stderr, "Error: %s\n", ErrMsg);688 LLVMDisposeErrorMessage(ErrMsg);689 690 LLVMOrcMaterializationResponsibilityFailMaterialization(OtherMR);691 LLVMOrcMaterializationResponsibilityFailMaterialization(MR);692 693 LLVMOrcDisposeMaterializationResponsibility(OtherMR);694 LLVMOrcDisposeMaterializationResponsibility(MR);695 LLVMOrcDisposeMaterializationUnit(OtherMU);696 return;697 }698 }699 LLVMOrcDisposeMaterializationResponsibility(OtherMR);700 701 // FIXME: Implement async lookup702 LLVMOrcRetainSymbolStringPoolEntry(DependencySymbol);703 LLVMOrcCSymbolMapPair Pair = {DependencySymbol, Sym};704 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);705 // DependencySymbol no longer owned by us706 707 Pair = {TargetSym.Name, Sym};708 LLVMOrcMaterializationResponsibilityNotifyResolved(MR, &Pair, 1);709 710 LLVMOrcRetainSymbolStringPoolEntry(TargetSym.Name);711 LLVMOrcCDependenceMapPair Dependency = {JD, {&DependencySymbol, 1}};712 LLVMOrcCSymbolDependenceGroup DependenceSet = {713 /*.Symbols = */ {/*.Symbols = */ &TargetSym.Name, /* .Length = */ 1},714 /* .Dependencies = */ &Dependency,715 /* .NumDependencies = */ 1};716 717 LLVMOrcMaterializationResponsibilityNotifyEmitted(MR, &DependenceSet, 1);718 LLVMOrcDisposeMaterializationResponsibility(MR);719}720 721TEST_F(OrcCAPITestBase, MaterializationResponsibility) {722 LLVMJITSymbolFlags Flags = {723 LLVMJITSymbolGenericFlagsExported | LLVMJITSymbolGenericFlagsCallable, 0};724 LLVMOrcCSymbolFlagsMapPair Sym = {LLVMOrcLLJITMangleAndIntern(Jit, "foo"),725 Flags};726 727 LLVMOrcMaterializationUnitRef MU = LLVMOrcCreateCustomMaterializationUnit(728 "MU", (void *)Jit, &Sym, 1, NULL, &Materialize, NULL, &Destroy);729 LLVMOrcJITDylibRef JD = LLVMOrcLLJITGetMainJITDylib(Jit);730 LLVMOrcJITDylibDefine(JD, MU);731 732 LLVMOrcJITTargetAddress Addr;733 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "foo")) {734 FAIL() << "foo was not materialized " << toString(Err);735 }736 ASSERT_TRUE(!!Addr);737 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);738 739 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "other")) {740 FAIL() << "other was not materialized " << toString(Err);741 }742 ASSERT_TRUE(!!Addr);743 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);744 745 if (LLVMErrorRef Err = LLVMOrcLLJITLookup(Jit, &Addr, "dependency")) {746 FAIL() << "dependency was not materialized " << toString(Err);747 }748 ASSERT_TRUE(!!Addr);749 ASSERT_EQ(Addr, (LLVMOrcJITTargetAddress)&TargetFn);750}751 752struct SuspendedLookupContext {753 std::function<void()> AsyncWork;754 LLVMOrcSymbolStringPoolEntryRef NameToGenerate;755 JITTargetAddress AddrToGenerate;756 757 bool Disposed = false;758 bool QueryCompleted = true;759};760 761static LLVMErrorRef TryToGenerateWithSuspendedLookup(762 LLVMOrcDefinitionGeneratorRef GeneratorObj, void *RawCtx,763 LLVMOrcLookupStateRef *LookupState, LLVMOrcLookupKind Kind,764 LLVMOrcJITDylibRef JD, LLVMOrcJITDylibLookupFlags JDLookupFlags,765 LLVMOrcCLookupSet LookupSet, size_t LookupSetSize) {766 767 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx);768 769 assert(LookupSetSize == 1);770 assert(LookupSet[0].Name == Ctx->NameToGenerate);771 772 LLVMJITEvaluatedSymbol Sym = {0x1234, {LLVMJITSymbolGenericFlagsExported, 0}};773 LLVMOrcRetainSymbolStringPoolEntry(LookupSet[0].Name);774 LLVMOrcCSymbolMapPair Pair = {LookupSet[0].Name, Sym};775 LLVMOrcCSymbolMapPair Pairs[] = {Pair};776 LLVMOrcMaterializationUnitRef MU = LLVMOrcAbsoluteSymbols(Pairs, 1);777 778 // Capture and reset LookupState to suspend the lookup. We'll continue it in779 // the SuspendedLookup testcase below.780 Ctx->AsyncWork = [LS = *LookupState, JD, MU]() {781 LLVMErrorRef Err = LLVMOrcJITDylibDefine(JD, MU);782 LLVMOrcLookupStateContinueLookup(LS, Err);783 };784 *LookupState = nullptr;785 return LLVMErrorSuccess;786}787 788static void DisposeSuspendedLookupContext(void *Ctx) {789 static_cast<SuspendedLookupContext *>(Ctx)->Disposed = true;790}791 792static void793suspendLookupTestLookupHandlerCallback(LLVMErrorRef Err,794 LLVMOrcCSymbolMapPairs Result,795 size_t NumPairs, void *RawCtx) {796 if (Err) {797 FAIL() << "Suspended DefinitionGenerator did not create symbol \"foo\": "798 << toString(Err);799 return;800 }801 802 EXPECT_EQ(NumPairs, 1U)803 << "Unexpected number of result entries: expected 1, got " << NumPairs;804 805 auto *Ctx = static_cast<SuspendedLookupContext *>(RawCtx);806 EXPECT_EQ(Result[0].Name, Ctx->NameToGenerate);807 EXPECT_EQ(Result[0].Sym.Address, Ctx->AddrToGenerate);808 809 Ctx->QueryCompleted = true;810}811 812TEST_F(OrcCAPITestBase, SuspendedLookup) {813 // Test that we can suspend lookup in a custom generator.814 SuspendedLookupContext Ctx;815 Ctx.NameToGenerate = LLVMOrcLLJITMangleAndIntern(Jit, "foo");816 Ctx.AddrToGenerate = 0x1234;817 818 // Add generator.819 LLVMOrcJITDylibAddGenerator(MainDylib,820 LLVMOrcCreateCustomCAPIDefinitionGenerator(821 &TryToGenerateWithSuspendedLookup, &Ctx,822 DisposeSuspendedLookupContext));823 824 // Expect no work to do before the lookup.825 EXPECT_FALSE(Ctx.AsyncWork) << "Unexpected generator work before lookup";826 827 // Issue lookup. This should trigger the generator, but generation should828 // be suspended.829 LLVMOrcCJITDylibSearchOrderElement SO[] = {830 {MainDylib, LLVMOrcJITDylibLookupFlagsMatchExportedSymbolsOnly}};831 LLVMOrcRetainSymbolStringPoolEntry(Ctx.NameToGenerate);832 LLVMOrcCLookupSetElement LS[] = {833 {Ctx.NameToGenerate, LLVMOrcSymbolLookupFlagsRequiredSymbol}};834 LLVMOrcExecutionSessionLookup(ExecutionSession, LLVMOrcLookupKindStatic, SO,835 1, LS, 1,836 suspendLookupTestLookupHandlerCallback, &Ctx);837 838 // Expect that we now have generator work to do.839 EXPECT_TRUE(Ctx.AsyncWork)840 << "Failed to generator (or failed to suspend generator)";841 842 // Do the work. This should allow the query to complete.843 Ctx.AsyncWork();844 845 // Check that the query completed.846 EXPECT_TRUE(Ctx.QueryCompleted);847 848 // Release our local copy of the string.849 LLVMOrcReleaseSymbolStringPoolEntry(Ctx.NameToGenerate);850 851 // Explicitly tear down the JIT.852 LLVMOrcDisposeLLJIT(Jit);853 Jit = nullptr;854 855 // Check that the generator context was "destroyed".856 EXPECT_TRUE(Ctx.Disposed);857}858