Variadic arguments of float type are automatically promoted to double.
This commit makes the __builtin_dump_struct to convert float arguments
to double before passing them to the printf-style function, fixing this
bug https://bugs.llvm.org/show_bug.cgi?id=45143.
Details
- Reviewers
rjmccall aaron.ballman paulsemel
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
I have added John McCall to the reviewers as the CODE_OWNERS.txt file says he's responsible for LLVM IR generation. Also Aaron Ballman, as he wrote the function per git-blame output.
Adding @paulsemel to the reviewer list as he was the original author of this functionality (I commit on his behalf which is how I showed up on the git blame).
clang/lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
2090–2094 | This change is an improvement as far as it goes, but I think we might be missing other floating-point promotions here. For example, __fp16 fields also seem to be unusable: https://godbolt.org/z/z3a45f9YE Also, we don't seem to handle the integer promotions at all (but still get correct results there), so I think we're getting the correct behavior there by chance rather than by design. Oh, yeah, note the differences here: https://godbolt.org/z/f13eq3668 foo: ... %7 = load i8, i8* %4, align 1, !dbg !217 %8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @2, i32 0, i32 0), i8 %7), !dbg !217 ... bar: ... %2 = load i8, i8* %1, align 1, !dbg !222 %3 = zext i8 %2 to i32, !dbg !222 %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0), i32 %3), !dbg !223 ... I think we should probably fix all of the promotion problems at once rather than piecemeal. |
clang/lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
2090–2094 | It's actually really annoying that this logic has to be duplicated in IRGen instead of being able to take advantage of the existing promotion logic in Sema. Can we just generate a helper function in Sema and somehow link it to the builtin call? Um. Also, the static local DenseMap in the code above this is totally unacceptable and should not have been committed. Clang is supposed to be embeddable as a library and should not be using global mutable variables. |
clang/lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
2090–2094 |
That seems worth a shot but I think it is not something that needs to happen for this patch (that could be a rather heavy lift to ask someone who just joined the community) unless the basic fix starts getting out of hand.
We do that with some degree of frequency already (command line arguments using llvm::cl::opt are all global mutable variables, such as https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/CoverageMappingGen.cpp#L34), but yeah, fixing that up would also not be a bad idea, but orthogonal to this patch IMO. |
clang/lib/CodeGen/CGBuiltin.cpp | ||
---|---|---|
2090–2094 |
That should also not have been committed, but more importantly, it's not actually mutated during normal operation — IIUC, you have to tell the cl library to process a command line for any of the cl::opts to be mutated, and otherwise they remain constant. In contrast, this code may segfault if you have two threads in a process running IR-generation that happen to use this builtin, and the only saving grace is that approximately nobody uses this builtin. | |
2090–2094 |
In addition to its need to reproduce all the logic of default argument conversion, this code is doing manual lowering of calls with arbitrary arguments instead of using the target ABI call-emission code. It also, as mentioned in the FIXME, doesn't properly handle bit-fields. It's just the wrong basic approach for implementing this feature, and I don't think we should be trying to clean it up around the edges; we should revert and ask for an acceptable implementation. |
Hey all! Thanks for taking the time to review my patch and writing the Compiler Explorer examples and everything. I had no idea this was the essentially the wrong approach to this, I'd be happy to do a bigger overhaul of the whole builtin if that would make it more correct, but as Aaron points out I'm very new to this project (and C++ too) and essentially clueless as to how to do that, I submitted this patch because it looked like it was simple enough to issue the fpext to get the float promoted.
If you give me some pointers I'd be more than happy to give it a shot, I should have time in the coming weeks. As a seasoned printf debugger 😄 this builtin is pretty useful to me and I'd like to fix it rather than deprecating or otherwise removing it.
As for the static map, it looks to me like it would be fairly straightforward to replace it with a simple helper function?
Thanks for this. I'd be happy to help you through it. And yeah, I'm definitely not arguing for deprecating/removing the builtin long-term; I just want the implementation to be on a sound technical footing.
As for the static map, it looks to me like it would be fairly straightforward to replace it with a simple helper function?
Yeah, a helper function that just returns a format specifier for a type seems like the way to go, and that would be a reasonable short-term patch. When this code moves into Sema, hopefully we can find a way to merge that with the logic we already have for printf checking.
This change is an improvement as far as it goes, but I think we might be missing other floating-point promotions here. For example, __fp16 fields also seem to be unusable: https://godbolt.org/z/z3a45f9YE
Also, we don't seem to handle the integer promotions at all (but still get correct results there), so I think we're getting the correct behavior there by chance rather than by design. Oh, yeah, note the differences here: https://godbolt.org/z/f13eq3668
I think we should probably fix all of the promotion problems at once rather than piecemeal.