The uint32_t type does not clearly convey that these fields are
interpreted in the target endianness. Converting them to byte arrays
should make this more obvious and less error-prone.
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
Wrap argument list for fill, and avoid any byte swapping when calculating NonZeroFiller
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | We need to know whether all four elements are zero. We could check each element individually (either in a loop or unrolled), but this seemed nicer, and I'm assuming it'll be optimised to a single 32-bit load on architectures with unaligned loads. |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Ah, but this is not a performance critical path at all, so I'd just use read32le. |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | I don't particularly like unnecessarily slowing down the code for big-endian hosts, even if it isn't a critical path. The only advantage I see is that it shortens the code a tiny bit, but that's only because there is no read32ne wrapper for this like read32[bl]e... So I would advocate for keeping it as-is, but at the end of the day I'll change it if necessary. |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Does not seem you need llvm::support::endian:: prefix here since you added the using? (And I would also just use our write32 from Target.h here. inline void write32(void *P, uint32_t V) { llvm::support::endian::write32(P, V, Config->Endianness); } This code is called once for the output section, so it's about .. 10-30 calls in average? |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | I meant 'read32' of course: inline uint32_t read32(const void *P) { return llvm::support::endian::read32(P, Config->Endianness); } |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Well, that then uses the *target* endianness instead, which doesn't seem to be an improvement over just using LE or BE unconditionally (though I guess the common case is target == host, where it wouldn't byte swap on either BE or LE...). |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Improvement here is simplicity. There is no point to use LE or BE and even think about which endianness should be used here. Because for this case it is not important and for a new code reader to see read32 is much better than to see llvm::support::endian::read32<endianness::native>, the first one does not raise questions. |
LGTM with this change.
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Yeah, read32 is just more concise than llvm::support::endian::read32<endianness::native>, that's why I like that. |
ELF/OutputSections.cpp | ||
---|---|---|
242 ↗ | (On Diff #172944) | Ok, I'll concede :) |
This broke compilation with GCC 5.3 on Ubuntu 16.04, with the following error:
In file included from ../tools/lld/ELF/Thunks.cpp:30:0: ../tools/lld/ELF/Target.h:125:49: error: array must be initialized with a brace-enclosed initializer std::array<uint8_t, 4> TrapInstr = {0, 0, 0, 0}; ^ ../tools/lld/ELF/Target.h:125:49: error: too many initializers for ‘std::array<unsigned char, 4ul>’
I guess it means that it is confused by the syntax for default initialization of a member variable, when used in combination with a braced initializer list like this.
Because we always overwrites the default {0,0,0,0} with an actual trap instruction in the ctors of the derived classes, I believe we can just remove = {0, 0, 0, 0} to tame gcc.