On 2/18/2013 8:08 PM, Chris Lattner wrote:> > That code is presumably compiled by someone. If whoever compiles it specifies -fno-builtin, the attribute would be added to it. It doesn't affect its clients.After reading the description quoted by Bill, I'm not sure what you mean by attaching the attribute to the function body. Suppose I have my own version of strlen, written in whatever language and present in an .o file, and a function foo in C which calls strlen, which is compiled with clang. It makes sense to put the "nobuiltin" attribute on the prototype of "strlen", since this way all the callers of the strlen would know what they are dealing with. -Krzysztof -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
On Feb 19, 2013, at 6:50 AM, Krzysztof Parzyszek <kparzysz at codeaurora.org> wrote:> On 2/18/2013 8:08 PM, Chris Lattner wrote: >> >> That code is presumably compiled by someone. If whoever compiles it specifies -fno-builtin, the attribute would be added to it. It doesn't affect its clients. > > After reading the description quoted by Bill, I'm not sure what you mean by attaching the attribute to the function body. Suppose I have my own version of strlen, written in whatever language and present in an .o file, and a function foo in C which calls strlen, which is compiled with clang. It makes sense to put the "nobuiltin" attribute on the prototype of "strlen", since this way all the callers of the strlen would know what they are dealing with.I think that there is general confusion here about what -fno-builtin does. It is *not* an attribute that affects the definition of builtin functions, it is a statement that the code being compiled in the current translation unit should change behavior. Consider two translation units, A.c and B.c: --- A.c, compiled with -fno-builtin-puts void foo() { printf("hello world\n"); } --- B.c, compiled *without* -fno-builtin. void bar() { printf("goodbye world\n"); } After LTO, we need to know that it is safe to optimize goodbye world into a call to puts, even though: 1) there is no prototype at all in the IR for puts, 2) two different functions (foo and bar) have different builtin-optimization-allowedness. There are only two correct ways to model this: 1) an IR attribute on the function *bodies* being compiled in a translation unit, or 2) as an IR attribute on each *call* in the code being compiled in a translation unit. If we want to be pedantically correct, #2 is really the right way to go, because then differences in this attribute would not affect inlining. For example, if we had: --- C.c void x() { foo(); bar(); } Then we should be able to inline both calls to printf into x(), then know that only one could be optimized. -Chris
On 2/19/2013 12:23 PM, Chris Lattner wrote:> > I think that there is general confusion here about what -fno-builtin does. It is *not* an attribute that affects the definition of builtin functions, it is a statement that the code being compiled in the current translation unit should change behavior.Here are the cases that I see: (1) Nobuiltin attribute on printf, telling the compiler that the printf that can appear in a call may not be the printf from libc, meaning that the compiler cannot do anything to any such call that would take advantage of knowing what printf would normally do. (2) Nobuiltin attribute on some user function foo, telling the compiler that we don't want it to perform any optimizations related to the knowledge about builtins (or printf in particular, if it's nobuiltin-printf) in function foo. Case (1) would imply (2), and not only for foo, but for all functions. On the other hand, (2) does not imply (1). In case (1) it may be considered an error to have conflicting attribute for printf in different compilation units, if the attribute is associated with the prototype of printf. However, it doesn't have to be an error if the attribute is actually present at every function call (instead of being attached to the prototype). Case (2) would only have the attribute on calls that are originally in the body of foo. Otherwise we would run into trouble with inlining even without LTO. This seems to agree with what you wrote (here and in other replies), and I suspect that the difference may be in some details of how we look at it. I would suggest using separate compiler options to denote the two cases, something like: (1) -fno-builtin-printf (2) -fno-builtins-in-foo (or something of that nature). There is also the problem of function overload in C++, templates, namespaces, etc. and I have no idea how to differentiate between different foos in a compiler option (without using mangled names). (This is not so much a problem for the real builtins, as they are mostly unmangled.) -Krzysztof -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation