[llvm-dev] Kaleidoscope tutorial: comments, corrections and Windows support
Moritz Kroll via llvm-dev
llvm-dev at lists.llvm.org
Mon Feb 6 15:07:52 PST 2017
Hi,
I'm currently working my way through the tutorial with LLVM 3.9.1 on
Windows (finished chapter 4) and stumbled over a few things which could
be improved:
- "LLVMContext" does not exist as a variable -> "TheContext"
- Chapter 3: 5 times
- Chapter 4: 1 time
- Chapter 5: 4 times
- Chapter 6: 2 times
- Chapter 7: 2 times
3.4. Function Code Generation
- Wouldn't it make sense to have a
"Type *DoubleTy = Type::getDoubleTy(TheContext);"?
- "Function *TheFunction = TheModule->getFunction(Proto->getName());"
The new getName method is unexpected, the tutorial user has to lookup
and copy the definition from the full listing.
3.5. Driver Changes and Closing Thoughts
- "When you quit the current demo"
-> "When you quit the current demo (by sending an EOF
via CTRL+D on Linux or CTRL+Z and ENTER on Windows)"
(Windows users normally don't send EOF characters so they
usually don't know this shortcut)
4.3. LLVM Optimization Passes
- Code for InitializeModuleAndPassManager:
- Remove "Context LLVMContext;"
- "TheJIT" comes out of nowhere and thus is not defined in the code
of the tutorial user. Setting the data layout could be added in
4.4, as it is at least not required for showing the improved body
of "test"
- "createBasicAliasAnalysisPass" does not exist anymore (llvm-3.9.1).
Also requires adaption of the text
4.4. Adding a JIT Compiler
- Code for main:
- "TheJIT = llvm::make_unique<KaleidoscopeJIT>();" will cause a crash
due to an invalid read in "Datalayout::operator=" as
"EngineBuilder().selectTarget()" returns a nullptr when
"InitializeNativeTarget" has not been called yet.
Other problems occur if the other InitializeNative* functions are
not called. So you should add them here.
- The (silently added) "TheModule->print" call from chapter 3
is missing
- "The KaleidoscopeJIT class is a simple JIT built specifically for
these tutorials.":
It would be nice to mention, where to find the include file:
llvm-src/examples/Kaleidoscope/include/KaleidoscopeJIT.h
- "auto ExprSymbol = TheJIT->findSymbol("__anon_expr");":
On Windows, this will always fail as this function will search for
"ExportedSymbolsOnly" and the exported flag seems to be implemented
incorrectly for COFF in LLVM (see bug report from Russell Wallace:
http://lists.llvm.org/pipermail/llvm-dev/2016-April/097964.html ).
Applied to the current version of Kaleidoscope, he suggested to use
"CompileLayer.findSymbolIn(H, Name, false)" in
"KaleidoscopeJIT::findMangledSymbol" to also allow non-exported
symbols.
I fixed it by changing "COFFObjectFile::getSymbolFlags" in
llvm-src/lib/Object/COFFObjectFile.cpp
to additionally OR SymbolRef::SF_Exported to Result:
> uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
> COFFSymbolRef Symb = getCOFFSymbol(Ref);
> uint32_t Result = SymbolRef::SF_None;
>
> if (Symb.isExternal() || Symb.isWeakExternal())
> Result |= SymbolRef::SF_Global | SymbolRef::SF_Exported;
Works and sounds reasonable to me, but maybe you can prove me wrong.
- "ready> sin(1.0);": On Windows, this fails with "LLVM ERROR: Program
used external function '_sin' which could not be resolved!" because
"DynamicLibrary::SearchForAddressOfSymbol" iterates over all loaded
libraries and uses GetProcAddress to try getting the address.
But for the old "msvcrt.dll" as well as the newer "ucrtbased.dll",
the math functions are exported without a leading underscore.
Additionally, LLVM provides some "explicit" symbols which would
otherwise only exist in form of a macro (see comment in
llvm-src/lib/Support/Windows/DynamicLibrary.inc). These are also only
available in unmangled form, for example "sinf".
Thus I propose to add this code at the end of
"KaleidoscopeJIT::findMangledSymbol":
> #ifdef LLVM_ON_WIN32
> // For Windows retry without "_" at begining, as RTDyldMemoryManager uses
> // GetProcAddress and standard libraries like msvcrt.dll use names
> // with and without "_" (for example "_itoa" but "sin").
> if (Name.length() > 2 && Name[0] == '_')
> if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(
> Name.substr(1)))
> return JITSymbol(SymAddr, JITSymbolFlags::Exported);
> #endif
>
> return nullptr;
> }
- "ready> sin(1.0);
Read top-level expression:
define double @2() {
entry:
ret double 0x3FEAED548F090CEE
}
Evaluated to 0.841471":
Actually "sin" is not called at all, LLVM knew "sin" and just returns
the already const-folded value.
In my case, I do see a
"%calltmp = call double @sin(double 1.000000e+00)",
though, inspite of the same optimizations as in your listing...
- "ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x);
Read function definition:
define double @foo(double %x) {
entry:
%calltmp = call double @sin(double %x)
%multmp = fmul double %calltmp, %calltmp
%calltmp2 = call double @cos(double %x)
%multmp4 = fmul double %calltmp2, %calltmp2
%addtmp = fadd double %multmp, %multmp4
ret double %addtmp
}":
In my case, the CSE does not work, although it does work for the
example in 4.3:
"ready> def foo(x) sin(x)*sin(x) + cos(x)*cos(x);
ready> Read function definition:
define double @foo(double %x) {
entry:
%calltmp = call double @sin(double %x)
%calltmp1 = call double @sin(double %x)
%multmp = fmul double %calltmp, %calltmp1
%calltmp2 = call double @cos(double %x)
%calltmp3 = call double @cos(double %x)
%multmp4 = fmul double %calltmp2, %calltmp3
%addtmp = fadd double %multmp, %multmp4
ret double %addtmp
}"
- "extern putchard(x); putchard(120);":
Again, on Windows, this doesn't work. To make it work, you have to
use "extern "C" __declspec(dllexport) double putchard(double X)"
so the function will be found via GetProcAddress for the main module.
This wouldn't hurt for Linux / Mac, would it?
Best regards
Moritz Kroll
More information about the llvm-dev
mailing list