Dr. Marcus Hoffmann via llvm-dev
2019-Jan-02 17:44 UTC
[llvm-dev] JIT compiler, Windows, external functions like cos
Hello LLVM team, our software FluidSIM (www.fluidsim.de) simulates pneumatic, hydraulic and electric circuits. For the mathematical models we use the language Modelica (www.modelica.org). We developed our own Modelica simulator which solves the dynamical created algebraic differential equation systems. One tool is our small JIT compiler, which compiles mathematical expressions like “2*x0 + sin(x1)” at runtime. In the future we want to compile more complex expressions, especially entire blocks, like X1 = 2*x0 +4 X2 = 3*sin(x1) X3 = x1 + x2 At the moment, we are evaluating the LLVM suite to replace our JIT compiler. Our software runs under the Windows platform (32 and 64 Bit). We are using the Microsoft Visual Studio 2017 Version 15.9.4. For our evaluation we use LLVM 7.0.1. We created the LLVM suite for 32 Bit with the cmake tools. We wrote a small parser and took the LLVM tutorials as starting point to implement our LLVM JIT compiler. All arithmetic expressions work fine. But we failed to integrate external functions like “cos” and “sin”. Only “sqrt” worked. After many trials and errors we found out that no LLVM example works (“4. Kaleidoscope: Adding JIT and Optimizer Support”, “The Fibonacci project“). It seems that the LLVM JIT compiler cannot find external functions like “sin” and “cos” nor intrinsic functions under Windows. Every (tutorial) example crashes using them. Is there any solution for this problem (compiler switches, libraries to include, a simple Visual Studio project)? The following code works for “sqrt” but not for “cos”. It just encapsulates an external call. We use Microsoft Visual Studio 2017 Version 15.9.4. LLVM 7.0.1 Solution Configuration: Debug, 32 Bit, Switch: /MTd using namespace llvm; typedef double(__cdecl *JitCompiledFn)(double); int main() { // "sqrt" works. //const char externalFnName[] = "sqrt"; // "cos", "sin", etc. fails. const char externalFnName[] = "cos"; InitializeNativeTarget(); InitializeNativeTargetAsmPrinter(); InitializeNativeTargetAsmParser(); LLVMContext context; IRBuilder<> builder(context); std::unique_ptr<llvm::Module> module(new Module("TestModule", context)); Module* pModule = module.get(); auto externalFn_IR = cast<Function>(pModule->getOrInsertFunction("externalFn", Type::getDoubleTy(context), Type::getDoubleTy(context))); Value* x = externalFn_IR->arg_begin(); x->setName("x"); BasicBlock *entryBlock = BasicBlock::Create(context, "EntryBlock", externalFn_IR); builder.SetInsertPoint(entryBlock); std::vector<Type *> args(1, Type::getDoubleTy(context)); FunctionType *FT = FunctionType::get(Type::getDoubleTy(context), args, false); auto externalFn_llvm = Function::Create(FT, Function::ExternalLinkage, externalFnName, pModule); auto ret = builder.CreateCall(externalFn_llvm, x); builder.CreateRet(ret); errs() << "Created Module:\n\n" << *pModule; auto jitCompiler = EngineBuilder(std::move(module)).setOptLevel(CodeGenOpt::Level::Default).create(); JitCompiledFn externalFn = (JitCompiledFn)jitCompiler->getFunctionAddress(externalFn_IR->getName()); errs() << "\n\nexternalFn(9.0) = "; double y = externalFn(9.0); errs() << y << "\n\n"; return 0; } Kind regards Marcus Hoffmann -- Dr. Marcus Hoffmann Art Systems Software GmbH Hudeweg 13, 33102 Paderborn Registergericht: Amtsgericht Paderborn, HRB 2776 Geschäftsführer: Dr. Daniel Curatolo, Dr. Marcus Hoffmann Prof. Dr. Benno Stein http://www.artsystems.de
Stefan Gränitz via llvm-dev
2019-Jan-02 20:18 UTC
[llvm-dev] JIT compiler, Windows, external functions like cos
Hi Marcus If I understand correctly, you are creating a module with a declaration for an external function. Then you compile and load the module with the ExecutionEngine JIT interface. The loader is supposed to resolve your declaration to an existing definition in the host program, right? Do you get the error message "Program used external function '...' which could not be resolved!"? There is a variety of potential reasons here. The mystery that it works for sqrt, but not for cos or sin, may be that something in your host program exposes a definition with its unmangled name only for sqrt, while the others are mangled or not exposed at all. After all, your host program links to the C++ stdlib, which provides multiple versions of all these functions with different signatures! In general, using host-process symbols directly can be dangerous and hard to debug. Basically, you are relying on details of your host compiler and linker. The correct way may be adding another module with the stdlib implementation that your JITed code should use. The simplest way may be keeping the host-process calls, but expose your own wrappers explicitly by address. Using the Orc JIT interface directly, a QND implementation with LLVM 5.0 looked like this: https://github.com/weliveindetail/JitFromScratch/commit/e9988a834dd6c35c93268da6ece73a7cc472100a Note that on Windows you want to declare the wrappers as: extern "C" __declspec(dllexport)> After many trials and errors we found out that no LLVM example works > (“4. Kaleidoscope: Adding JIT and Optimizer Support”, “The Fibonacci > project“). [...] It seems that the LLVM JIT compiler cannot find > external functions like “sin” and “cos” nor intrinsic functions under > Windows. Every (tutorial) example crashes using them.I can imagine this doesn't get tested so much on Windows. Best Stefan Am 02.01.19 um 19:05 schrieb Dr. Marcus Hoffmann:> Hello Stefan, > > our software FluidSIM (www.fluidsim.de) simulates pneumatic, hydraulic > and electric circuits. For the mathematical models we use the language > Modelica (www.modelica.org). We developed our own Modelica simulator > which solves the dynamical created algebraic differential equation > systems. One tool is our small JIT compiler, which compiles > mathematical expressions like “2*x0 + sin(x1)” at runtime. > > In the future we want to compile more complex expressions, especially > entire blocks, like > X1 = 2*x0 +4 > X2 = 3*sin(x1) > X3 = x1 + x2 > > At the moment, we are evaluating the LLVM suite to replace our JIT > compiler. Our software runs under the Windows platform (32 and 64 > Bit). We are using the Microsoft Visual Studio 2017 Version 15.9.4. > For our evaluation we use LLVM 7.0.1. We created the LLVM suite for 32 > Bit with the cmake tools. We wrote a small parser and took the LLVM > tutorials as starting point to implement our LLVM JIT compiler. All > arithmetic expressions work fine. But we failed to integrate external > functions like “cos” and “sin”. Only “sqrt” worked. After many trials > and errors we found out that no LLVM example works (“4. Kaleidoscope: > Adding JIT and Optimizer Support”, “The Fibonacci project“). > > It seems that the LLVM JIT compiler cannot find external functions > like “sin” and “cos” nor intrinsic functions under Windows. Every > (tutorial) example crashes using them. Is there any solution for this > problem (compiler switches, libraries to include, a simple Visual > Studio project)? > > The following code works for “sqrt” but not for “cos”. It just > encapsulates an external call. We use > Microsoft Visual Studio 2017 Version 15.9.4. > LLVM 7.0.1 > Solution Configuration: Debug, 32 Bit, Switch: /MTd > > using namespace llvm; > > typedef double(__cdecl *JitCompiledFn)(double); > > int main() > { > // "sqrt" works. > //const char externalFnName[] = "sqrt"; > > // "cos", "sin", etc. fails. > const char externalFnName[] = "cos"; > > InitializeNativeTarget(); > InitializeNativeTargetAsmPrinter(); > InitializeNativeTargetAsmParser(); > > LLVMContext context; > > IRBuilder<> builder(context); > > std::unique_ptr<llvm::Module> module(new Module("TestModule", context)); > Module* pModule = module.get(); > > auto externalFn_IR > cast<Function>(pModule->getOrInsertFunction("externalFn", > Type::getDoubleTy(context), Type::getDoubleTy(context))); > Value* x = externalFn_IR->arg_begin(); > x->setName("x"); > > BasicBlock *entryBlock = BasicBlock::Create(context, "EntryBlock", > externalFn_IR); > builder.SetInsertPoint(entryBlock); > > std::vector<Type *> args(1, Type::getDoubleTy(context)); > FunctionType *FT = FunctionType::get(Type::getDoubleTy(context), args, > false); > auto externalFn_llvm = Function::Create(FT, Function::ExternalLinkage, > externalFnName, pModule); > auto ret = builder.CreateCall(externalFn_llvm, x); > > builder.CreateRet(ret); > > errs() << "Created Module:\n\n" << *pModule; > > auto jitCompiler > EngineBuilder(std::move(module)).setOptLevel(CodeGenOpt::Level::Default).create(); > > > JitCompiledFn externalFn > (JitCompiledFn)jitCompiler->getFunctionAddress(externalFn_IR->getName()); > > errs() << "\n\nexternalFn(9.0) = "; > > double y = externalFn(9.0); > > errs() << y << "\n\n"; > > return 0; > } > > > > Kind regards > Marcus Hoffmann >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190102/09533477/attachment.html>
Stefan Gränitz via llvm-dev
2019-Jan-04 22:32 UTC
[llvm-dev] JIT compiler, Windows, external functions like cos
Hi Marcus (+list)> Have you ever successfully compiled and run your project with the > current Visual Studio 2017 under Windows 10?Well, it's possible I have missed a detail like this during the LLVM 5.0 port, but I am sure it worked on Windows with LLVM 4.0 at the time of writing the examples. I do not have an archived version or anything, but the original branches are still there: https://github.com/weliveindetail/JitFromScratch/tree/master/llvm40> LLVM ERROR: Program used external function '_abs' which could not be > resolved!On Windows there should be no underscore as mangling prefix. Maybe that's the issue in the example.> Maybe I just miss the right linker or compiler options for using the > standard library?What you want is a pure C stdlib and what your host program brings is a C++ stdlib. In order to use the latter you must mangle your names, which gets complicated quickly. If you go with custom wrappers in your host program, you can declare them extern "C" and avoid the mangling headache! Let's keep the conversation on the list. Am 03.01.19 um 11:09 schrieb Dr. Marcus Hoffmann:> Hi Stefan, > > thanks a lot for your very, very quick response. I contacted you, > because I already checked out your JitFromScratch project. This > project fails, too. The cause for the failure (of all examples: 4. > Kaleidoscope, JitFromScratch , etc.) seems to be the same. > > The requirements for our software and so for the JIT compiler are: > - Operating system Windows 10 (32 and 64 Bit) > - C++ compiler Microsoft Visual Studio 2017 > > I successfully built LLVM 5.0 and your JitFromScratch project with > Visual Studio 2017 by using cmake and the instructions "Getting > Started with the LLVM System using Microsoft Visual Studio" on the > LLVM homepage. The solution configuration is Debug, 32 Bit, Switch: /MDd. > > The example projects (and our own project) run, but fail by using > standard library functions. > > Your JitFromScratch project fails with the printed message > > LLVM ERROR: Program used external function '_abs' which could not be > resolved! > > Have you ever successfully compiled and run your project with the > current Visual Studio 2017 under Windows 10? > > If so, could you please send me the solution folder as a zip file? > > Maybe I just miss the right linker or compiler options for using the > standard library? > > > Best regards > Marcus Hoffmann > > >> Hi Marcus >> >> If I understand correctly, you are creating a module with a >> declaration for an external function. Then you compile and load the >> module with the ExecutionEngine JIT interface. The loader is supposed >> to resolve your declaration to an existing definition in the host >> program, right? Do you get the error message "Program used external >> function '...' which could not be resolved!"? >> >> There is a variety of potential reasons here. The mystery that it >> works for sqrt, but not for cos or sin, may be that something in your >> host program exposes a definition with its unmangled name only for >> sqrt, while the others are mangled or not exposed at all. After all, >> your host program links to the C++ stdlib, which provides multiple >> versions of all these functions with different signatures! >> >> In general, using host-process symbols directly can be dangerous and >> hard to debug. Basically, you are relying on details of your host >> compiler and linker. The correct way may be adding another module >> with the stdlib implementation that your JITed code should use. The >> simplest way may be keeping the host-process calls, but expose your >> own wrappers explicitly by address. Using the Orc JIT interface >> directly, a QND implementation with LLVM 5.0 looked like this: >> https://github.com/weliveindetail/JitFromScratch/commit/e9988a834dd6c35c93268da6ece73a7cc472100a >> >> >> Note that on Windows you want to declare the wrappers as: extern "C" >> __declspec(dllexport) >> >>> After many trials and errors we found out that no LLVM example works >>> (“4. Kaleidoscope: Adding JIT and Optimizer Support”, “The Fibonacci >>> project“). [...] It seems that the LLVM JIT compiler cannot find >>> external functions like “sin” and “cos” nor intrinsic functions >>> under Windows. Every (tutorial) example crashes using them. >> I can imagine this doesn't get tested so much on Windows. >> >> Best >> Stefan >> >> Am 02.01.19 um 19:05 schrieb Dr. Marcus Hoffmann: >>> Hello Stefan, >>> >>> our software FluidSIM (www.fluidsim.de) simulates pneumatic, >>> hydraulic and electric circuits. For the mathematical models we use >>> the language Modelica (www.modelica.org). We developed our own >>> Modelica simulator which solves the dynamical created algebraic >>> differential equation systems. One tool is our small JIT compiler, >>> which compiles mathematical expressions like “2*x0 + sin(x1)” at >>> runtime. >>> >>> In the future we want to compile more complex expressions, >>> especially entire blocks, like >>> X1 = 2*x0 +4 >>> X2 = 3*sin(x1) >>> X3 = x1 + x2 >>> >>> At the moment, we are evaluating the LLVM suite to replace our JIT >>> compiler. Our software runs under the Windows platform (32 and 64 >>> Bit). We are using the Microsoft Visual Studio 2017 Version 15.9.4. >>> For our evaluation we use LLVM 7.0.1. We created the LLVM suite for >>> 32 Bit with the cmake tools. We wrote a small parser and took the >>> LLVM tutorials as starting point to implement our LLVM JIT compiler. >>> All arithmetic expressions work fine. But we failed to integrate >>> external functions like “cos” and “sin”. Only “sqrt” worked. After >>> many trials and errors we found out that no LLVM example works (“4. >>> Kaleidoscope: Adding JIT and Optimizer Support”, “The Fibonacci >>> project“). >>> >>> It seems that the LLVM JIT compiler cannot find external functions >>> like “sin” and “cos” nor intrinsic functions under Windows. Every >>> (tutorial) example crashes using them. Is there any solution for >>> this problem (compiler switches, libraries to include, a simple >>> Visual Studio project)? >>> >>> The following code works for “sqrt” but not for “cos”. It just >>> encapsulates an external call. We use >>> Microsoft Visual Studio 2017 Version 15.9.4. >>> LLVM 7.0.1 >>> Solution Configuration: Debug, 32 Bit, Switch: /MTd >>> >>> using namespace llvm; >>> >>> typedef double(__cdecl *JitCompiledFn)(double); >>> >>> int main() >>> { >>> // "sqrt" works. >>> //const char externalFnName[] = "sqrt"; >>> >>> // "cos", "sin", etc. fails. >>> const char externalFnName[] = "cos"; >>> >>> InitializeNativeTarget(); >>> InitializeNativeTargetAsmPrinter(); >>> InitializeNativeTargetAsmParser(); >>> >>> LLVMContext context; >>> >>> IRBuilder<> builder(context); >>> >>> std::unique_ptr<llvm::Module> module(new Module("TestModule", >>> context)); >>> Module* pModule = module.get(); >>> >>> auto externalFn_IR >>> cast<Function>(pModule->getOrInsertFunction("externalFn", >>> Type::getDoubleTy(context), Type::getDoubleTy(context))); >>> Value* x = externalFn_IR->arg_begin(); >>> x->setName("x"); >>> >>> BasicBlock *entryBlock = BasicBlock::Create(context, "EntryBlock", >>> externalFn_IR); >>> builder.SetInsertPoint(entryBlock); >>> >>> std::vector<Type *> args(1, Type::getDoubleTy(context)); >>> FunctionType *FT = FunctionType::get(Type::getDoubleTy(context), >>> args, false); >>> auto externalFn_llvm = Function::Create(FT, >>> Function::ExternalLinkage, externalFnName, pModule); >>> auto ret = builder.CreateCall(externalFn_llvm, x); >>> >>> builder.CreateRet(ret); >>> >>> errs() << "Created Module:\n\n" << *pModule; >>> >>> auto jitCompiler >>> EngineBuilder(std::move(module)).setOptLevel(CodeGenOpt::Level::Default).create(); >>> >>> >>> JitCompiledFn externalFn >>> (JitCompiledFn)jitCompiler->getFunctionAddress(externalFn_IR->getName()); >>> >>> errs() << "\n\nexternalFn(9.0) = "; >>> >>> double y = externalFn(9.0); >>> >>> errs() << y << "\n\n"; >>> >>> return 0; >>> } >>> >>> >>> >>> Kind regards >>> Marcus Hoffmann >>>