[ExceptionDemo] Transition example from MCJIT to ORC and fix errors (#92504)

ExceptionDemo has been broken for some time. This patch fixes the
compilation errors and moves the example from MCJIT to ORC.
This commit is contained in:
epitavy
2025-01-23 02:40:38 +01:00
committed by GitHub
parent a9d2834508
commit 847acbbc52
2 changed files with 76 additions and 111 deletions

View File

@@ -1,9 +1,7 @@
set(LLVM_LINK_COMPONENTS set(LLVM_LINK_COMPONENTS
Core Core
ExecutionEngine ExecutionEngine
MC ORCJIT
MCJIT
RuntimeDyld
Support Support
Target Target
nativecodegen nativecodegen

View File

@@ -49,8 +49,9 @@
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/Orc/Core.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/DataLayout.h" #include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h" #include "llvm/IR/IRBuilder.h"
@@ -84,6 +85,8 @@
#define USE_GLOBAL_STR_CONSTS true #define USE_GLOBAL_STR_CONSTS true
#endif #endif
llvm::ExitOnError ExitOnErr;
// //
// Example types // Example types
// //
@@ -142,6 +145,7 @@ static llvm::ConstantInt *ourExceptionCaughtState;
typedef std::vector<std::string> ArgNames; typedef std::vector<std::string> ArgNames;
typedef std::vector<llvm::Type*> ArgTypes; typedef std::vector<llvm::Type*> ArgTypes;
typedef llvm::ArrayRef<llvm::Type *> TypeArray;
// //
// Code Generation Utilities // Code Generation Utilities
@@ -891,13 +895,10 @@ void generateStringPrint(llvm::LLVMContext &context,
/// generated, and is used to hold the constant string. A value of /// generated, and is used to hold the constant string. A value of
/// false indicates that the constant string will be stored on the /// false indicates that the constant string will be stored on the
/// stack. /// stack.
void generateIntegerPrint(llvm::LLVMContext &context, void generateIntegerPrint(llvm::LLVMContext &context, llvm::Module &module,
llvm::Module &module,
llvm::IRBuilder<> &builder, llvm::IRBuilder<> &builder,
llvm::Function &printFunct, llvm::Function &printFunct, llvm::Value *toPrint,
llvm::Value &toPrint, std::string format, bool useGlobal = true) {
std::string format,
bool useGlobal = true) {
llvm::Constant *stringConstant = llvm::Constant *stringConstant =
llvm::ConstantDataArray::getString(context, format); llvm::ConstantDataArray::getString(context, format);
llvm::Value *stringVar; llvm::Value *stringVar;
@@ -919,10 +920,9 @@ void generateIntegerPrint(llvm::LLVMContext &context,
llvm::Value *cast = builder.CreateBitCast(stringVar, llvm::Value *cast = builder.CreateBitCast(stringVar,
builder.getPtrTy()); builder.getPtrTy());
builder.CreateCall(&printFunct, {&toPrint, cast}); builder.CreateCall(&printFunct, {toPrint, cast});
} }
/// Generates code to handle finally block type semantics: always runs /// Generates code to handle finally block type semantics: always runs
/// regardless of whether a thrown exception is passing through or the /// regardless of whether a thrown exception is passing through or the
/// parent function is simply exiting. In addition to printing some state /// parent function is simply exiting. In addition to printing some state
@@ -996,10 +996,10 @@ static llvm::BasicBlock *createFinallyBlock(llvm::LLVMContext &context,
bufferToPrint.str(), bufferToPrint.str(),
USE_GLOBAL_STR_CONSTS); USE_GLOBAL_STR_CONSTS);
llvm::SwitchInst *theSwitch = builder.CreateSwitch(builder.CreateLoad( llvm::SwitchInst *theSwitch = builder.CreateSwitch(
*exceptionCaughtFlag), builder.CreateLoad(ourExceptionNotThrownState->getType(),
&terminatorBlock, *exceptionCaughtFlag),
2); &terminatorBlock, 2);
theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock); theSwitch->addCase(ourExceptionCaughtState, &terminatorBlock);
theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock); theSwitch->addCase(ourExceptionThrownState, &unwindResumeBlock);
@@ -1185,7 +1185,7 @@ static llvm::Function *createCatchWrappedInvokeFunction(
// Note: function handles NULL exceptions // Note: function handles NULL exceptions
builder.CreateCall(deleteOurException, builder.CreateCall(deleteOurException,
builder.CreateLoad(exceptionStorage)); builder.CreateLoad(builder.getPtrTy(), exceptionStorage));
builder.CreateRetVoid(); builder.CreateRetVoid();
// Normal Block // Normal Block
@@ -1205,7 +1205,8 @@ static llvm::Function *createCatchWrappedInvokeFunction(
builder.SetInsertPoint(unwindResumeBlock); builder.SetInsertPoint(unwindResumeBlock);
builder.CreateResume(builder.CreateLoad(caughtResultStorage)); builder.CreateResume(
builder.CreateLoad(ourCaughtResultType, caughtResultStorage));
// Exception Block // Exception Block
@@ -1240,11 +1241,9 @@ static llvm::Function *createCatchWrappedInvokeFunction(
// Retrieve exception_class member from thrown exception // Retrieve exception_class member from thrown exception
// (_Unwind_Exception instance). This member tells us whether or not // (_Unwind_Exception instance). This member tells us whether or not
// the exception is foreign. // the exception is foreign.
llvm::Value *unwindExceptionClass = llvm::Value *unwindExceptionClass = builder.CreateLoad(
builder.CreateLoad(builder.CreateStructGEP( builder.getInt64Ty(),
ourUnwindExceptionType, builder.CreateStructGEP(ourUnwindExceptionType, unwindException, 0));
unwindException,
0));
// Branch to the externalExceptionBlock if the exception is foreign or // Branch to the externalExceptionBlock if the exception is foreign or
// to a catch router if not. Either way the finally block will be run. // to a catch router if not. Either way the finally block will be run.
@@ -1275,8 +1274,8 @@ static llvm::Function *createCatchWrappedInvokeFunction(
// (OurException instance). // (OurException instance).
// //
// Note: ourBaseFromUnwindOffset is usually negative // Note: ourBaseFromUnwindOffset is usually negative
llvm::Value *typeInfoThrown = builder.CreateConstGEP1_64(unwindException, llvm::Value *typeInfoThrown = builder.CreateConstGEP1_64(
ourBaseFromUnwindOffset)); builder.getInt8Ty(), unwindException, ourBaseFromUnwindOffset);
// Retrieve thrown exception type info type // Retrieve thrown exception type info type
// //
@@ -1285,17 +1284,14 @@ static llvm::Function *createCatchWrappedInvokeFunction(
typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0); typeInfoThrown = builder.CreateStructGEP(ourExceptionType, typeInfoThrown, 0);
llvm::Value *typeInfoThrownType = llvm::Value *typeInfoThrownType =
builder.CreateStructGEP(builder.getPtrTy(), typeInfoThrown, 0); builder.CreateStructGEP(ourTypeInfoType, typeInfoThrown, 0);
generateIntegerPrint(context, llvm::Value *ti32 =
module, builder.CreateLoad(builder.getInt32Ty(), typeInfoThrownType);
builder, generateIntegerPrint(context, module, builder, *toPrint32Int, ti32,
*toPrint32Int,
*(builder.CreateLoad(typeInfoThrownType)),
"Gen: Exception type <%d> received (stack unwound) " "Gen: Exception type <%d> received (stack unwound) "
" in " + " in " +
ourId + ourId + ".\n",
".\n",
USE_GLOBAL_STR_CONSTS); USE_GLOBAL_STR_CONSTS);
// Route to matched type info catch block or run cleanup finally block // Route to matched type info catch block or run cleanup finally block
@@ -1307,8 +1303,7 @@ static llvm::Function *createCatchWrappedInvokeFunction(
for (unsigned i = 1; i <= numExceptionsToCatch; ++i) { for (unsigned i = 1; i <= numExceptionsToCatch; ++i) {
nextTypeToCatch = i - 1; nextTypeToCatch = i - 1;
switchToCatchBlock->addCase(llvm::ConstantInt::get( switchToCatchBlock->addCase(llvm::ConstantInt::get(builder.getInt32Ty(), i),
llvm::Type::getInt32Ty(context), i),
catchBlocks[nextTypeToCatch]); catchBlocks[nextTypeToCatch]);
} }
@@ -1383,14 +1378,10 @@ createThrowExceptionFunction(llvm::Module &module, llvm::IRBuilder<> &builder,
builder.SetInsertPoint(entryBlock); builder.SetInsertPoint(entryBlock);
llvm::Function *toPrint32Int = module.getFunction("print32Int"); llvm::Function *toPrint32Int = module.getFunction("print32Int");
generateIntegerPrint(context, generateIntegerPrint(context, module, builder, *toPrint32Int,
module, builder.CreateZExt(exceptionType, builder.getInt32Ty()),
builder, "\nGen: About to throw exception type <%d> in " + ourId +
*toPrint32Int, ".\n",
*exceptionType,
"\nGen: About to throw exception type <%d> in " +
ourId +
".\n",
USE_GLOBAL_STR_CONSTS); USE_GLOBAL_STR_CONSTS);
// Switches on runtime type info type value to determine whether or not // Switches on runtime type info type value to determine whether or not
@@ -1542,15 +1533,12 @@ typedef void (*OurExceptionThrowFunctType) (int32_t typeToThrow);
/// @param function generated test function to run /// @param function generated test function to run
/// @param typeToThrow type info type of generated exception to throw, or /// @param typeToThrow type info type of generated exception to throw, or
/// indicator to cause foreign exception to be thrown. /// indicator to cause foreign exception to be thrown.
static static void runExceptionThrow(llvm::orc::LLJIT *JIT, std::string function,
void runExceptionThrow(llvm::ExecutionEngine *engine, int32_t typeToThrow) {
llvm::Function *function,
int32_t typeToThrow) {
// Find test's function pointer // Find test's function pointer
OurExceptionThrowFunctType functPtr = OurExceptionThrowFunctType functPtr =
reinterpret_cast<OurExceptionThrowFunctType>( ExitOnErr(JIT->lookup(function)).toPtr<OurExceptionThrowFunctType>();
reinterpret_cast<intptr_t>(engine->getPointerToFunction(function)));
try { try {
// Run test // Run test
@@ -1579,8 +1567,6 @@ void runExceptionThrow(llvm::ExecutionEngine *engine,
// End test functions // End test functions
// //
typedef llvm::ArrayRef<llvm::Type*> TypeArray;
/// This initialization routine creates type info globals and /// This initialization routine creates type info globals and
/// adds external function declarations to module. /// adds external function declarations to module.
/// @param numTypeInfos number of linear type info associated type info types /// @param numTypeInfos number of linear type info associated type info types
@@ -1861,7 +1847,8 @@ static void createStandardUtilityFunctions(unsigned numTypeInfos,
// llvm.eh.typeid.for intrinsic // llvm.eh.typeid.for intrinsic
getDeclaration(&module, llvm::Intrinsic::eh_typeid_for, builder.getPtrTy()); getOrInsertDeclaration(&module, llvm::Intrinsic::eh_typeid_for,
builder.getPtrTy());
} }
@@ -1890,93 +1877,73 @@ int main(int argc, char *argv[]) {
return(0); return(0);
} }
// If not set, exception handling will not be turned on
llvm::TargetOptions Opts;
llvm::InitializeNativeTarget(); llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter(); llvm::InitializeNativeTargetAsmPrinter();
llvm::LLVMContext Context; auto Context = std::make_unique<llvm::LLVMContext>();
llvm::IRBuilder<> theBuilder(Context); llvm::IRBuilder<> theBuilder(*Context);
// Make the module, which holds all the code. // Make the module, which holds all the code.
std::unique_ptr<llvm::Module> Owner = std::unique_ptr<llvm::Module> Owner =
std::make_unique<llvm::Module>("my cool jit", Context); std::make_unique<llvm::Module>("my cool jit", *Context);
llvm::Module *module = Owner.get(); llvm::Module *module = Owner.get();
std::unique_ptr<llvm::RTDyldMemoryManager> MemMgr(new llvm::SectionMemoryManager()); // Build LLJIT
std::unique_ptr<llvm::orc::LLJIT> JIT =
ExitOnErr(llvm::orc::LLJITBuilder().create());
// Build engine with JIT // Set up the optimizer pipeline.
llvm::EngineBuilder factory(std::move(Owner)); llvm::legacy::FunctionPassManager fpm(module);
factory.setEngineKind(llvm::EngineKind::JIT);
factory.setTargetOptions(Opts);
factory.setMCJITMemoryManager(std::move(MemMgr));
llvm::ExecutionEngine *executionEngine = factory.create();
{ // Optimizations turned on
llvm::legacy::FunctionPassManager fpm(module);
// Set up the optimizer pipeline.
// Start with registering info about how the
// target lays out data structures.
module->setDataLayout(executionEngine->getDataLayout());
// Optimizations turned on
#ifdef ADD_OPT_PASSES #ifdef ADD_OPT_PASSES
// Basic AliasAnslysis support for GVN. // Basic AliasAnslysis support for GVN.
fpm.add(llvm::createBasicAliasAnalysisPass()); fpm.add(llvm::createBasicAliasAnalysisPass());
// Promote allocas to registers. // Promote allocas to registers.
fpm.add(llvm::createPromoteMemoryToRegisterPass()); fpm.add(llvm::createPromoteMemoryToRegisterPass());
// Do simple "peephole" optimizations and bit-twiddling optzns. // Do simple "peephole" optimizations and bit-twiddling optzns.
fpm.add(llvm::createInstructionCombiningPass()); fpm.add(llvm::createInstructionCombiningPass());
// Reassociate expressions. // Reassociate expressions.
fpm.add(llvm::createReassociatePass()); fpm.add(llvm::createReassociatePass());
// Eliminate Common SubExpressions. // Eliminate Common SubExpressions.
fpm.add(llvm::createGVNPass()); fpm.add(llvm::createGVNPass());
// Simplify the control flow graph (deleting unreachable // Simplify the control flow graph (deleting unreachable
// blocks, etc). // blocks, etc).
fpm.add(llvm::createCFGSimplificationPass()); fpm.add(llvm::createCFGSimplificationPass());
#endif // ADD_OPT_PASSES #endif // ADD_OPT_PASSES
fpm.doInitialization(); fpm.doInitialization();
// Generate test code using function throwCppException(...) as // Generate test code using function throwCppException(...) as
// the function which throws foreign exceptions. // the function which throws foreign exceptions.
llvm::Function *toRun = createUnwindExceptionTest(*module, theBuilder, fpm, "throwCppException");
createUnwindExceptionTest(*module,
theBuilder,
fpm,
"throwCppException");
executionEngine->finalizeObject(); ExitOnErr(JIT->addIRModule(
llvm::orc::ThreadSafeModule(std::move(Owner), std::move(Context))));
#ifndef NDEBUG #ifndef NDEBUG
fprintf(stderr, "\nBegin module dump:\n\n"); fprintf(stderr, "\nBegin module dump:\n\n");
module->dump(); module->print(llvm::errs(), nullptr);
fprintf(stderr, "\nEnd module dump:\n"); fprintf(stderr, "\nEnd module dump:\n");
#endif #endif
fprintf(stderr, "\n\nBegin Test:\n"); fprintf(stderr, "\n\nBegin Test:\n");
std::string toRun = "outerCatchFunct";
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
// Run test for each argument whose value is the exception // Run test for each argument whose value is the exception
// type to throw. // type to throw.
runExceptionThrow(executionEngine, runExceptionThrow(JIT.get(), toRun, (unsigned)strtoul(argv[i], NULL, 10));
toRun,
(unsigned) strtoul(argv[i], NULL, 10));
}
fprintf(stderr, "\nEnd Test:\n\n");
} }
delete executionEngine; fprintf(stderr, "\nEnd Test:\n\n");
return 0; return 0;
} }