Return a std::unique_ptr when creating a new MemoryBuffer.
[oota-llvm.git] / unittests / ExecutionEngine / MCJIT / MCJITCAPITest.cpp
index a56d9c7b9c054bd0b843ca33ea3200c16fb17036..c80b88b8c2b137ca0586d21390c09881331ab36e 100644 (file)
 #include "llvm-c/Core.h"
 #include "llvm-c/ExecutionEngine.h"
 #include "llvm-c/Target.h"
+#include "llvm-c/Transforms/PassManagerBuilder.h"
 #include "llvm-c/Transforms/Scalar.h"
 #include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/Support/Debug.h"
 #include "llvm/Support/Host.h"
 #include "gtest/gtest.h"
-#include "llvm/Support/Debug.h"
 
 using namespace llvm;
 
 static bool didCallAllocateCodeSection;
+static bool didAllocateCompactUnwindSection;
+static bool didCallYield;
 
 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,
                                              unsigned alignment,
@@ -41,6 +44,8 @@ static uint8_t *roundTripAllocateDataSection(void *object, uintptr_t size,
                                              unsigned sectionID,
                                              const char *sectionName,
                                              LLVMBool isReadOnly) {
+  if (!strcmp(sectionName, "__compact_unwind"))
+    didAllocateCompactUnwindSection = true;
   return static_cast<SectionMemoryManager*>(object)->allocateDataSection(
     size, alignment, sectionID, sectionName, isReadOnly);
 }
@@ -60,6 +65,10 @@ static void roundTripDestroy(void *object) {
   delete static_cast<SectionMemoryManager*>(object);
 }
 
+static void yield(LLVMContextRef, void *) {
+  didCallYield = true;
+}
+
 namespace {
 
 // memory manager to test reserve allocation space callback
@@ -130,15 +139,17 @@ protected:
 
     // The operating systems below are known to be sufficiently incompatible
     // that they will fail the MCJIT C API tests.
-    UnsupportedOSs.push_back(Triple::Cygwin);
+    UnsupportedEnvironments.push_back(Triple::Cygnus);
   }
   
   virtual void SetUp() {
     didCallAllocateCodeSection = false;
-    Module = 0;
-    Function = 0;
-    Engine = 0;
-    Error = 0;
+    didAllocateCompactUnwindSection = false;
+    didCallYield = false;
+    Module = nullptr;
+    Function = nullptr;
+    Engine = nullptr;
+    Error = nullptr;
   }
   
   virtual void TearDown() {
@@ -153,8 +164,8 @@ protected:
     
     LLVMSetTarget(Module, HostTriple.c_str());
     
-    Function = LLVMAddFunction(
-      Module, "simple_function", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
+    Function = LLVMAddFunction(Module, "simple_function",
+                               LLVMFunctionType(LLVMInt32Type(), nullptr,0, 0));
     LLVMSetFunctionCallConv(Function, LLVMCCallConv);
     
     LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
@@ -168,6 +179,36 @@ protected:
     LLVMDisposeBuilder(builder);
   }
   
+  void buildFunctionThatUsesStackmap() {
+    Module = LLVMModuleCreateWithName("simple_module");
+    
+    LLVMSetTarget(Module, HostTriple.c_str());
+    
+    LLVMTypeRef stackmapParamTypes[] = { LLVMInt64Type(), LLVMInt32Type() };
+    LLVMValueRef stackmap = LLVMAddFunction(
+      Module, "llvm.experimental.stackmap",
+      LLVMFunctionType(LLVMVoidType(), stackmapParamTypes, 2, 1));
+    LLVMSetLinkage(stackmap, LLVMExternalLinkage);
+    
+    Function = LLVMAddFunction(Module, "simple_function",
+                              LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
+    
+    LLVMBasicBlockRef entry = LLVMAppendBasicBlock(Function, "entry");
+    LLVMBuilderRef builder = LLVMCreateBuilder();
+    LLVMPositionBuilderAtEnd(builder, entry);
+    LLVMValueRef stackmapArgs[] = {
+      LLVMConstInt(LLVMInt64Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 5, 0),
+      LLVMConstInt(LLVMInt32Type(), 42, 0)
+    };
+    LLVMBuildCall(builder, stackmap, stackmapArgs, 3, "");
+    LLVMBuildRet(builder, LLVMConstInt(LLVMInt32Type(), 42, 0));
+    
+    LLVMVerifyModule(Module, LLVMAbortProcessAction, &Error);
+    LLVMDisposeMessage(Error);
+    
+    LLVMDisposeBuilder(builder);
+  }
+  
   void buildModuleWithCodeAndData() {
     Module = LLVMModuleCreateWithName("simple_module");
     
@@ -178,8 +219,8 @@ protected:
     LLVMSetInitializer(GlobalVar, LLVMConstInt(LLVMInt32Type(), 42, 0));
     
     {
-        Function = LLVMAddFunction(
-          Module, "getGlobal", LLVMFunctionType(LLVMInt32Type(), 0, 0, 0));
+        Function = LLVMAddFunction(Module, "getGlobal",
+                              LLVMFunctionType(LLVMInt32Type(), nullptr, 0, 0));
         LLVMSetFunctionCallConv(Function, LLVMCCallConv);
         
         LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry");
@@ -248,6 +289,38 @@ protected:
     LLVMDisposePassManager(pass);
   }
   
+  void buildAndRunOptPasses() {
+    LLVMPassManagerBuilderRef passBuilder;
+    
+    passBuilder = LLVMPassManagerBuilderCreate();
+    LLVMPassManagerBuilderSetOptLevel(passBuilder, 2);
+    LLVMPassManagerBuilderSetSizeLevel(passBuilder, 0);
+    
+    LLVMPassManagerRef functionPasses =
+      LLVMCreateFunctionPassManagerForModule(Module);
+    LLVMPassManagerRef modulePasses =
+      LLVMCreatePassManager();
+    
+    LLVMAddTargetData(LLVMGetExecutionEngineTargetData(Engine), modulePasses);
+    
+    LLVMPassManagerBuilderPopulateFunctionPassManager(passBuilder,
+                                                      functionPasses);
+    LLVMPassManagerBuilderPopulateModulePassManager(passBuilder, modulePasses);
+    
+    LLVMPassManagerBuilderDispose(passBuilder);
+    
+    LLVMInitializeFunctionPassManager(functionPasses);
+    for (LLVMValueRef value = LLVMGetFirstFunction(Module);
+         value; value = LLVMGetNextFunction(value))
+      LLVMRunFunctionPassManager(functionPasses, value);
+    LLVMFinalizeFunctionPassManager(functionPasses);
+    
+    LLVMRunPassManager(modulePasses, Module);
+    
+    LLVMDisposePassManager(functionPasses);
+    LLVMDisposePassManager(modulePasses);
+  }
+  
   LLVMModuleRef Module;
   LLVMValueRef Function;
   LLVMValueRef Function2;
@@ -293,6 +366,42 @@ TEST_F(MCJITCAPITest, custom_memory_manager) {
   EXPECT_TRUE(didCallAllocateCodeSection);
 }
 
+TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) {
+  SKIP_UNSUPPORTED_PLATFORM;
+  
+  // This test is also not supported on non-x86 platforms.
+  if (Triple(HostTriple).getArch() != Triple::x86_64)
+    return;
+  
+  buildFunctionThatUsesStackmap();
+  buildMCJITOptions();
+  useRoundTripSectionMemoryManager();
+  buildMCJITEngine();
+  buildAndRunOptPasses();
+  
+  union {
+    void *raw;
+    int (*usable)();
+  } functionPointer;
+  functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
+  
+  EXPECT_EQ(42, functionPointer.usable());
+  EXPECT_TRUE(didCallAllocateCodeSection);
+  
+  // Up to this point, the test is specific only to X86-64. But this next
+  // expectation is only valid on Darwin because it assumes that unwind
+  // data is made available only through compact_unwind. It would be
+  // worthwhile to extend this to handle non-Darwin platforms, in which
+  // case you'd want to look for an eh_frame or something.
+  //
+  // FIXME: Currently, MCJIT relies on a configure-time check to determine which
+  // sections to emit. The JIT client should have runtime control over this.
+  EXPECT_TRUE(
+    Triple(HostTriple).getOS() != Triple::Darwin ||
+    Triple(HostTriple).isMacOSXVersionLT(10, 7) ||
+    didAllocateCompactUnwindSection);
+}
+
 TEST_F(MCJITCAPITest, reserve_allocation_space) {
   SKIP_UNSUPPORTED_PLATFORM;
   
@@ -324,3 +433,24 @@ TEST_F(MCJITCAPITest, reserve_allocation_space) {
   EXPECT_TRUE(MM->UsedCodeSize > 0); 
   EXPECT_TRUE(MM->UsedDataSizeRW > 0);
 }
+
+TEST_F(MCJITCAPITest, yield) {
+  SKIP_UNSUPPORTED_PLATFORM;
+
+  buildSimpleFunction();
+  buildMCJITOptions();
+  buildMCJITEngine();
+  LLVMContextRef C = LLVMGetGlobalContext();
+  LLVMContextSetYieldCallback(C, yield, nullptr);
+  buildAndRunPasses();
+
+  union {
+    void *raw;
+    int (*usable)();
+  } functionPointer;
+  functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);
+
+  EXPECT_EQ(42, functionPointer.usable());
+  EXPECT_TRUE(didCallYield);
+}
+