I’m trying to create something like an LLVM pass fairly low in my compiler (a variant of swift).
I have an llvm::Function and llvm::Instruction where I want to emit diagnostics, using swift’s built in diagnostics system. That means I think I need an SMLoc.
I’ve used getDebugLoc().get(); to get the DILocation and can getLine(), getColumn() etc. from there to get the source location as a filename, line and column, which seems accurate enough.
I’m trying to figure out how to then create an SMLoc from that. The SMLoc class only seems to take a pointer in the constructor, which I don’t understand.
Sorry I couldn’t figure this out by googling!
To my best understanding, you want to emit diagnostic that shows the line, column, and the input source code (in your case the swift-alike language) whenever you encounter an error while processing the LLVM IR inside the middle-end. I’m afraid this is difficult to fit into SMLoc / SourceMgr’s original design.
SMLoc is just a pointer into a buffer, which contains the source code, maintained by llvm::SourceMgr, that’s why you cannot print out full diagnostic string without the help of SourceMgr. Thus if you want to leverage SMLoc / SourceMgr, the buffer needs to carry the source code of your input language. However, LLVM’s compilation pipeline does not assume the input source code to be available inside the middle-end. The frontend and the middle-end are two separated entities communicated only by the IR.
So unless you load your input code into SourceMgr inside the middle-end, there is no way to use SMLoc for diagnosing the input code. But then I guess another (much more difficult) question will be: How do you map from high-level code to low level LLVM IR (after the input code is loaded into SourceMgr)?
The debug info you mentioned _might_ be a way, but currently there is no way to use the DebugInfo infrastructure with SMLoc.
And just a FYI, SMLoc is primarily used in emitting diagnostic info while parsing textual LLVM IR (e.g. Pop an error when there is an ill-form LLVM IR syntax)
Thanks for the information. That makes sense.
In my case, the “llvm pass” isn’t really a middle end pass. I moved it slightly higher up the call stack, so it’s being done within front end code that still has things like `swift::ASTContext`, which has the full source code available in buffers. There’s a class called `swift::DiagnosticsEngine` that has all the things I require, if I put together a bit of plumbing.
I can get an llvm::SourceMgr that has all the source files loaded into it.
I feel like if I go through the buffers in that, looking for a buffer that has an identifier matching the filename I get from llvm::DILocation, then use some functions to get an SMLoc from the line and column (again from DILocation), I should be able to get something I can use?
p.s. Swift actually uses wrappers around both llvm::SourceMgr and llvm::SMLoc, which are called swift::SourceManager and swift::SourceLoc, I think!