From 23ffb3ea10530e36f8b779570f8e1cc686708051 Mon Sep 17 00:00:00 2001 From: Filip Pizlo Date: Thu, 20 Feb 2014 23:57:31 +0000 Subject: [PATCH] Stackmaps are used for OSR exits, which is a custom kind of unwinding. Hence, they should not be marked nounwind. Marking them nounwind caused crashes in the WebKit FTL JIT, because if we enable sufficient optimizations, LLVM starts eliding compact_unwind sections (or any unwind data for that matter), making deoptimization via stackmaps impossible. This changes the stackmap intrinsic to be may-throw, adds a test for exactly the sympton that WebKit saw, and fixes TableGen to handle un-attributed intrinsics. Thanks to atrick and philipreames for reviewing this. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@201826 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/IR/Intrinsics.td | 3 +- .../ExecutionEngine/MCJIT/CMakeLists.txt | 1 + .../ExecutionEngine/MCJIT/MCJITCAPITest.cpp | 90 +++++++++++++++++++ unittests/ExecutionEngine/MCJIT/Makefile | 2 +- utils/TableGen/IntrinsicEmitter.cpp | 1 + 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td index ca05db4982a..f8d8e79c9af 100644 --- a/include/llvm/IR/Intrinsics.td +++ b/include/llvm/IR/Intrinsics.td @@ -458,7 +458,8 @@ def int_invariant_end : Intrinsic<[], //===------------------------ Stackmap Intrinsics -------------------------===// // def int_experimental_stackmap : Intrinsic<[], - [llvm_i64_ty, llvm_i32_ty, llvm_vararg_ty]>; + [llvm_i64_ty, llvm_i32_ty, llvm_vararg_ty], + [Throws]>; def int_experimental_patchpoint_void : Intrinsic<[], [llvm_i64_ty, llvm_i32_ty, llvm_ptr_ty, llvm_i32_ty, diff --git a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt index a425b2478ac..afa3f2a6f66 100644 --- a/unittests/ExecutionEngine/MCJIT/CMakeLists.txt +++ b/unittests/ExecutionEngine/MCJIT/CMakeLists.txt @@ -2,6 +2,7 @@ set(LLVM_LINK_COMPONENTS Analysis Core ExecutionEngine + IPO JIT MCJIT ScalarOpts diff --git a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp index a56d9c7b9c0..7a7d178623d 100644 --- a/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp +++ b/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp @@ -18,6 +18,7 @@ #include "llvm-c/ExecutionEngine.h" #include "llvm-c/Target.h" #include "llvm-c/Transforms/Scalar.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/Support/Host.h" #include "gtest/gtest.h" @@ -26,6 +27,7 @@ using namespace llvm; static bool didCallAllocateCodeSection; +static bool didAllocateCompactUnwindSection; static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size, unsigned alignment, @@ -41,6 +43,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(object)->allocateDataSection( size, alignment, sectionID, sectionName, isReadOnly); } @@ -135,6 +139,7 @@ protected: virtual void SetUp() { didCallAllocateCodeSection = false; + didAllocateCompactUnwindSection = false; Module = 0; Function = 0; Engine = 0; @@ -168,6 +173,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(), 0, 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"); @@ -248,6 +283,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 +360,29 @@ TEST_F(MCJITCAPITest, custom_memory_manager) { EXPECT_TRUE(didCallAllocateCodeSection); } +TEST_F(MCJITCAPITest, stackmap_creates_compact_unwind_on_darwin) { + SKIP_UNSUPPORTED_PLATFORM; + + buildFunctionThatUsesStackmap(); + buildMCJITOptions(); + useRoundTripSectionMemoryManager(); + buildMCJITEngine(); + buildAndRunOptPasses(); + + union { + void *raw; + int (*usable)(); + } functionPointer; + functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function); + + EXPECT_EQ(42, functionPointer.usable()); + EXPECT_TRUE(didCallAllocateCodeSection); + + EXPECT_TRUE( + Triple(HostTriple).getOS() != Triple::Darwin || + didAllocateCompactUnwindSection); +} + TEST_F(MCJITCAPITest, reserve_allocation_space) { SKIP_UNSUPPORTED_PLATFORM; diff --git a/unittests/ExecutionEngine/MCJIT/Makefile b/unittests/ExecutionEngine/MCJIT/Makefile index 454f83099d4..c4dd740e057 100644 --- a/unittests/ExecutionEngine/MCJIT/Makefile +++ b/unittests/ExecutionEngine/MCJIT/Makefile @@ -9,7 +9,7 @@ LEVEL = ../../.. TESTNAME = MCJIT -LINK_COMPONENTS := core jit mcjit native support +LINK_COMPONENTS := core ipo jit mcjit native support include $(LEVEL)/Makefile.config include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest diff --git a/utils/TableGen/IntrinsicEmitter.cpp b/utils/TableGen/IntrinsicEmitter.cpp index 173e5065327..d366861992d 100644 --- a/utils/TableGen/IntrinsicEmitter.cpp +++ b/utils/TableGen/IntrinsicEmitter.cpp @@ -666,6 +666,7 @@ EmitAttributes(const std::vector &Ints, raw_ostream &OS) { OS << " }\n"; } else { OS << " return AttributeSet();\n"; + OS << " }\n"; } }