This is an archive of the discontinued LLVM Phabricator instance.

[ELF] Make TrapInstr and Filler byte arrays. NFC.
ClosedPublic

Authored by jrtc27 on Nov 7 2018, 6:20 AM.

Details

Summary

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.

Diff Detail

Repository
rL LLVM

Event Timeline

jrtc27 created this revision.Nov 7 2018, 6:20 AM
jrtc27 updated this revision to Diff 172944.Nov 7 2018, 6:34 AM

Wrap argument list for fill, and avoid any byte swapping when calculating NonZeroFiller

ruiu added inline comments.Nov 7 2018, 2:34 PM
ELF/Arch/ARM.cpp
64 ↗(On Diff #172944)

I believe clang-format wouldn't add spaces after { and before }.

ELF/OutputSections.cpp
242 ↗(On Diff #172944)

Do you need to use read32 if you only want to know whether a value is zero or not?

jrtc27 updated this revision to Diff 173101.Nov 7 2018, 5:25 PM

Remove inner spaces around initializer list braces.

jrtc27 marked an inline comment as done.Nov 7 2018, 5:28 PM
jrtc27 added inline comments.
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.

ruiu added inline comments.Nov 7 2018, 5:45 PM
ELF/OutputSections.cpp
242 ↗(On Diff #172944)

Ah, but this is not a performance critical path at all, so I'd just use read32le.

jrtc27 added inline comments.Nov 8 2018, 2:36 AM
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.

grimar added a subscriber: grimar.Nov 9 2018, 12:35 AM
grimar added inline comments.
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?
Does not seem worth to think about slow down here.)

grimar added inline comments.Nov 9 2018, 12:37 AM
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);
}
jrtc27 added inline comments.Nov 9 2018, 10:30 AM
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...).

grimar added inline comments.Nov 10 2018, 12:47 AM
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.

ruiu accepted this revision.Nov 11 2018, 10:06 PM

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.

This revision is now accepted and ready to land.Nov 11 2018, 10:06 PM
jrtc27 updated this revision to Diff 173636.Nov 12 2018, 2:33 AM

Use target-dependent read32

jrtc27 marked 9 inline comments as done.Nov 12 2018, 2:34 AM
jrtc27 added inline comments.
ELF/OutputSections.cpp
242 ↗(On Diff #172944)

Ok, I'll concede :)

jrtc27 marked 2 inline comments as done.Nov 12 2018, 2:34 AM
grimar accepted this revision.Nov 12 2018, 2:42 AM

LGTM, thanks!

Any plan on committing this change?

Any plan on committing this change?

If that's directed at me, I don't have commit rights.

Any plan on committing this change?

If that's directed at me, I don't have commit rights.

I will commit your patch soon.

This revision was automatically updated to reflect the committed changes.

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>’
ruiu added a comment.Nov 14 2018, 11:38 PM

Hmm, what does that gcc error actually mean? It seems to me that its a false error.

Hmm, what does that gcc error actually mean? It seems to me that its a false error.

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.

ruiu added a comment.Nov 15 2018, 12:04 AM

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.

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.

That does indeed seem to work, thanks!

ruiu added a comment.Nov 15 2018, 12:12 AM

I'll commit that change. Thanks!

ruiu added a comment.Nov 15 2018, 12:15 AM

You already did that. :) Thanks.