Mikael Lyngvig
2012-Jun-02 18:01 UTC
[LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
If I may add my two cents: I am planning to use LLVM as the backend for a compiler I am working on. And I wholeheartedly agree with Justin that it is a problem, if LLVM is allowed to freely write to stdout and stderr as it is a component which can be used in all sorts of code, be it a GUI IDE, a CLI driver, or whatever. Also, I have a number of times wondered about the somewhat unusual use of error strings in LLVM (that you pass in a string, which can be assigned a descriptive error message). Better would be, IMHO, to provide an interface along the lines of this: class ErrorHandler { public: virtual void Report(ErrorKind kind, uint code, const Position &position, const unichar *text, ...) = 0; }; And then let the client, i.e. the frontend, derive from it and handle all the output in whichever way it wants to. The above example is probably too complex for LLVM, but that's what I use in my compiler. ErrorKind is ErrorKind_Fatal, ErrorKind_Error, etc. Position is simply a filename, a line number, and a character position. unichar is either char or wchar_t, depending on the build mode and target environment. I hook it up so that I can buffer all errors encountered for later user. Cheers, Mikael -- Love Thy Frog! 2012/6/2 Justin Holewinski <justin.holewinski at gmail.com>> On Sat, Jun 2, 2012 at 8:56 AM, Chris Lattner <clattner at apple.com> wrote: > >> On Jun 1, 2012, at 11:13 PM, Justin Holewinski wrote: >> >> In a way, they are. What if I want a debug trace in a multi-threaded >>> context? Right now, all threads would just spew to the same stream and the >>> result would be unreadable. If you allow threads to setup their own outs() >>> and errs() streams (transparently to the rest of LLVM), you can intercept >>> these as you see fit, perhaps dumping each to a separate file. I >>> acknowledge that you could also enforce single-threaded execution for debug >>> runs, but what if you are in the context of a library with no valid >>> stdout/stderr buffers? >>> >>> >>> This doesn't make any sense. There is very little sense in trying to >>> use DEBUG (which gets compiled out of optimized builds) in a multithreaded >>> context. Polluting the purity of outs() and errs() because of this sort of >>> use case doesn't make any sense to me. >>> >>> outs() and errs() are useful independent of how LLVM happens to use >>> them. The extensions that you are proposing doesn't make any sense give >>> nthe design of raw_ostream. >>> >> >> Is the problem more that outs() and errs() should always point to valid >> stdout/stderr streams, regardless of how the hosting compiler is >> implemented? >> >> >> No. outs() and errs() are equivalent to stdout and stderr. Your request >> to change how they work to be thread local is like saying that we should >> change how printf works because LLVM is misusing printf somewhere. >> > > Fair enough. I've always been under the impression that outs() and errs() > were simply convenience wrappers around *some* output mechanism, not > strictly just stdout/stderr. > > >> >> If so, how do you feel about introducing a new global stream, logs()? >> This could replace all uses of outs()/errs() in the LLVM libraries, and >> default to errs(). Existing command-line tools could just use this >> default, but compilers that are hosted inside of libraries or other >> non-command line scenarios can attach a custom stream to logs() that >> captures all LLVM output, including DEBUG and any legitimate pass output. >> Command-line tools can continue to use outs()/errs() just as they do now. >> Nothing would really change in the way LLVM operates by default >> >> >> In fact, before we had raw_ostream, we had a dbgs() sort of stream, which >> was intended to be used in debug statements. I'm not strongly opposed to >> this (it would be much better than violating the sanctity of outs() :), but >> I'm still unclear why you care so much about DEBUG output. If we had a >> dbgs() again, it should *only* be used from within DEBUG macros (for >> example, the linker shouldn't use it). Would that be enough to achieve >> your goal? >> > > It's not so much DEBUG output that I care specifically about, that's just > an example of a place where the LLVM libraries assume an stderr stream > exists and is freely writable. What I really want is a way to capture > *all* LLVM library output that would normally go to stderr, similar to how > Clang has its Diagnostic functionality that allows a driver to collect all > output messages. > > There are legitimate cases where passes may output warnings or even errors > that the compiler should be able to direct to the user. errs() is fine for > this if you know you're working with a command-line tool, but that's not > always true. > > It sounds like dbgs() is not really the solution here, since I want to > capture more than just DEBUG output. If the module linker wants to output > a warning, I want to capture that. If an optimization pass wants to emit a > performance warning, I want to capture that too. Neither of these cases > are DEBUG-only. > > I see two possible solutions: > > 1. For every pass (or class) that may emit warnings/errors, provide it > a raw_ostream instance. This seems to be how some of the utility classes > work now, but this puts a burden on the compiler to know which passes > actually need a raw_ostream parameter. If you want to add a warning output > to any pass, you need to change its interface (create***Pass and > constructor) to add the raw_ostream parameter. > 2. Provide a generic mechanism through which passes and any other > utility classes can write warning/error information. This gives more > control to the compiler without introducing any interface changes. > > Option (1) is do-able, but option (2) seems more general. The specifics > of the implementation that I envision are: > > - logs() is added as another stream to raw_ostream.h > - By default, logs() forwards to errs() [no change in the way LLVM > works in the default case] > - Any pass or utility class that wants to emit warnings/errors should > write to logs() instead of errs() > - DEBUG code should use logs() instead of errs() [again, this will > default to errs()] > - An API is provided that allows a client to re-direct logs() to any > arbitrary raw_ostream, on a per-thread level > > You could also envision something along the lines of Clang's Diagnostics > functionality. You could thread a diagnostics interface through the pass > manager, and passes could output any messages as diagnostics. These > diagnostics would be collected and the compiler could query for them after > the pass manager completes. > > >> >> -Chris >> > > > > -- > > Thanks, > > Justin Holewinski > > > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20120602/48ef7ca1/attachment.html>
Hal Finkel
2012-Jun-02 18:55 UTC
[LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
On Sat, 2 Jun 2012 20:01:45 +0200 Mikael Lyngvig <mikael at lyngvig.org> wrote:> If I may add my two cents: > > I am planning to use LLVM as the backend for a compiler I am working > on. And I wholeheartedly agree with Justin that it is a problem, if > LLVM is allowed to freely write to stdout and stderr as it is a > component which can be used in all sorts of code, be it a GUI IDE, a > CLI driver, or whatever. > > Also, I have a number of times wondered about the somewhat unusual > use of error strings in LLVM (that you pass in a string, which can be > assigned a descriptive error message). Better would be, IMHO, to > provide an interface along the lines of this: > > class ErrorHandler > { > public: > virtual void Report(ErrorKind kind, uint code, const Position > &position, const unichar *text, ...) = 0; > }; > > And then let the client, i.e. the frontend, derive from it and handle > all the output in whichever way it wants to.I agree with this.> The above example is > probably too complex for LLVM, but that's what I use in my compiler. > ErrorKind is ErrorKind_Fatal, ErrorKind_Error, etc. Position is > simply a filename, a line number, and a character position.I don't agree with this. The "position" in the LLVM input will be fairly meaningless to a user. The frontend should be given as much information as possible to match the position of the error back to the originating source position and relevant source variables (if possible). LLVM has this information available if debugging metadata was provided. Even if such information was not provided, we should at least provide the function name (and module ID). The name of the generating pass should be included, and some mechanism provided to pass auxiliary metadata-like information (copies of alias sets, loop dependency info, etc.) that might be useful for the frontend to guide the user in understanding the problem. -Hal> unichar > is either char or wchar_t, depending on the build mode and target > environment. > > I hook it up so that I can buffer all errors encountered for later > user. > > > Cheers, > Mikael > -- Love Thy Frog! > > 2012/6/2 Justin Holewinski <justin.holewinski at gmail.com> > > > On Sat, Jun 2, 2012 at 8:56 AM, Chris Lattner <clattner at apple.com> > > wrote: > > > >> On Jun 1, 2012, at 11:13 PM, Justin Holewinski wrote: > >> > >> In a way, they are. What if I want a debug trace in a > >> multi-threaded > >>> context? Right now, all threads would just spew to the same > >>> stream and the result would be unreadable. If you allow threads > >>> to setup their own outs() and errs() streams (transparently to > >>> the rest of LLVM), you can intercept these as you see fit, > >>> perhaps dumping each to a separate file. I acknowledge that you > >>> could also enforce single-threaded execution for debug runs, but > >>> what if you are in the context of a library with no valid > >>> stdout/stderr buffers? > >>> > >>> > >>> This doesn't make any sense. There is very little sense in > >>> trying to use DEBUG (which gets compiled out of optimized builds) > >>> in a multithreaded context. Polluting the purity of outs() and > >>> errs() because of this sort of use case doesn't make any sense to > >>> me. > >>> > >>> outs() and errs() are useful independent of how LLVM happens to > >>> use them. The extensions that you are proposing doesn't make any > >>> sense give nthe design of raw_ostream. > >>> > >> > >> Is the problem more that outs() and errs() should always point to > >> valid stdout/stderr streams, regardless of how the hosting > >> compiler is implemented? > >> > >> > >> No. outs() and errs() are equivalent to stdout and stderr. Your > >> request to change how they work to be thread local is like saying > >> that we should change how printf works because LLVM is misusing > >> printf somewhere. > >> > > > > Fair enough. I've always been under the impression that outs() and > > errs() were simply convenience wrappers around *some* output > > mechanism, not strictly just stdout/stderr. > > > > > >> > >> If so, how do you feel about introducing a new global stream, > >> logs()? This could replace all uses of outs()/errs() in the LLVM > >> libraries, and default to errs(). Existing command-line tools > >> could just use this default, but compilers that are hosted inside > >> of libraries or other non-command line scenarios can attach a > >> custom stream to logs() that captures all LLVM output, including > >> DEBUG and any legitimate pass output. Command-line tools can > >> continue to use outs()/errs() just as they do now. Nothing would > >> really change in the way LLVM operates by default > >> > >> > >> In fact, before we had raw_ostream, we had a dbgs() sort of > >> stream, which was intended to be used in debug statements. I'm > >> not strongly opposed to this (it would be much better than > >> violating the sanctity of outs() :), but I'm still unclear why you > >> care so much about DEBUG output. If we had a dbgs() again, it > >> should *only* be used from within DEBUG macros (for example, the > >> linker shouldn't use it). Would that be enough to achieve your > >> goal? > >> > > > > It's not so much DEBUG output that I care specifically about, > > that's just an example of a place where the LLVM libraries assume > > an stderr stream exists and is freely writable. What I really want > > is a way to capture *all* LLVM library output that would normally > > go to stderr, similar to how Clang has its Diagnostic functionality > > that allows a driver to collect all output messages. > > > > There are legitimate cases where passes may output warnings or even > > errors that the compiler should be able to direct to the user. > > errs() is fine for this if you know you're working with a > > command-line tool, but that's not always true. > > > > It sounds like dbgs() is not really the solution here, since I want > > to capture more than just DEBUG output. If the module linker wants > > to output a warning, I want to capture that. If an optimization > > pass wants to emit a performance warning, I want to capture that > > too. Neither of these cases are DEBUG-only. > > > > I see two possible solutions: > > > > 1. For every pass (or class) that may emit warnings/errors, > > provide it a raw_ostream instance. This seems to be how some of > > the utility classes work now, but this puts a burden on the > > compiler to know which passes actually need a raw_ostream > > parameter. If you want to add a warning output to any pass, you > > need to change its interface (create***Pass and constructor) to add > > the raw_ostream parameter. 2. Provide a generic mechanism through > > which passes and any other utility classes can write warning/error > > information. This gives more control to the compiler without > > introducing any interface changes. > > > > Option (1) is do-able, but option (2) seems more general. The > > specifics of the implementation that I envision are: > > > > - logs() is added as another stream to raw_ostream.h > > - By default, logs() forwards to errs() [no change in the way > > LLVM works in the default case] > > - Any pass or utility class that wants to emit warnings/errors > > should write to logs() instead of errs() > > - DEBUG code should use logs() instead of errs() [again, this > > will default to errs()] > > - An API is provided that allows a client to re-direct logs() to > > any arbitrary raw_ostream, on a per-thread level > > > > You could also envision something along the lines of Clang's > > Diagnostics functionality. You could thread a diagnostics > > interface through the pass manager, and passes could output any > > messages as diagnostics. These diagnostics would be collected and > > the compiler could query for them after the pass manager completes. > > > > > >> > >> -Chris > >> > > > > > > > > -- > > > > Thanks, > > > > Justin Holewinski > > > > > > _______________________________________________ > > LLVM Developers mailing list > > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev > > > >-- Hal Finkel Postdoctoral Appointee Leadership Computing Facility Argonne National Laboratory
Chris Lattner
2012-Jun-03 19:12 UTC
[LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
On Jun 2, 2012, at 11:01 AM, Mikael Lyngvig wrote:> If I may add my two cents: > > I am planning to use LLVM as the backend for a compiler I am working on. And I wholeheartedly agree with Justin that it is a problem, if LLVM is allowed to freely write to stdout and stderr as it is a component which can be used in all sorts of code, be it a GUI IDE, a CLI driver, or whatever.LLVM should not be doing this.> Also, I have a number of times wondered about the somewhat unusual use of error strings in LLVM (that you pass in a string, which can be assigned a descriptive error message). Better would be, IMHO, to provide an interface along the lines of this: > > class ErrorHandler > { > public: > virtual void Report(ErrorKind kind, uint code, const Position &position, const unichar *text, ...) = 0; > }; > > And then let the client, i.e. the frontend, derive from it and handle all the output in whichever way it wants to. The above example is probably too complex for LLVM, but that's what I use in my compiler. ErrorKind is ErrorKind_Fatal, ErrorKind_Error, etc. Position is simply a filename, a line number, and a character position. unichar is either char or wchar_t, depending on the build mode and target environment.You're right, this would be better. We have even already have it :) llvm/Support/ErrorHandling.h -Chris
Hal Finkel
2012-Jun-03 23:15 UTC
[LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
On Sun, 03 Jun 2012 12:12:06 -0700 Chris Lattner <clattner at apple.com> wrote:> > On Jun 2, 2012, at 11:01 AM, Mikael Lyngvig wrote: > > > If I may add my two cents: > > > > I am planning to use LLVM as the backend for a compiler I am > > working on. And I wholeheartedly agree with Justin that it is a > > problem, if LLVM is allowed to freely write to stdout and stderr as > > it is a component which can be used in all sorts of code, be it a > > GUI IDE, a CLI driver, or whatever. > > LLVM should not be doing this. > > > Also, I have a number of times wondered about the somewhat unusual > > use of error strings in LLVM (that you pass in a string, which can > > be assigned a descriptive error message). Better would be, IMHO, > > to provide an interface along the lines of this: > > > > class ErrorHandler > > { > > public: > > virtual void Report(ErrorKind kind, uint code, const > > Position &position, const unichar *text, ...) = 0; }; > > > > And then let the client, i.e. the frontend, derive from it and > > handle all the output in whichever way it wants to. The above > > example is probably too complex for LLVM, but that's what I use in > > my compiler. ErrorKind is ErrorKind_Fatal, ErrorKind_Error, etc. > > Position is simply a filename, a line number, and a character > > position. unichar is either char or wchar_t, depending on the > > build mode and target environment. > > You're right, this would be better. We have even already have it :) > > llvm/Support/ErrorHandling.hThis seems to only handle fatal errors. If that's correct, it will probably need to be extended to handle non-fatal errors, warnings, suggestions, notes, etc. -Hal> > -Chris > > _______________________________________________ > llvm-commits mailing list > llvm-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits-- Hal Finkel Postdoctoral Appointee Leadership Computing Facility Argonne National Laboratory
Reasonably Related Threads
- [LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
- [LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
- [LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
- [LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()
- [LLVMdev] [llvm-commits] [PATCH] Allow per-thread re-direction of outs()/errs()