This is an archive of the discontinued LLVM Phabricator instance.

[MC][ARM] Correct Thumb BL instruction range
ClosedPublic

Authored by peter.smith on May 1 2018, 4:17 AM.

Details

Summary

The Thumb BL range is +- either 16 Megabytes or 4 Megabytes depending on whether the CPU supports Thumb2 or the v8-m baseline ops. The existing check for BL range is incorrectly set at +- 32 Megabytes. This change corrects the higher range and uses the lower range if the featurebits don't have the necessary support for it.

The ranges for the branch instructions can be found in https://developer.arm.com/docs/ddi0406/c/arm-architecture-reference-manual-armv7-a-and-armv7-r-edition
For version C (latest) the higher range can be found in A4.3 Branch instructions
For the shorter range search for "BL and BLX (immediate) instructions, before ARMv6T2", this also applies to ARMv6M.

I note that there isn't a range check for BLX, but as far as I can tell, the shouldForceRelocation() always generates an external relocation for this case.
There are also no range checks for B.W and Bcc.W, I have a follow up patch that adds checks for these that I'll post shortly.

Diff Detail

Event Timeline

peter.smith created this revision.May 1 2018, 4:17 AM

I'd like to see this rebased on top of https://reviews.llvm.org/D44928, I think.

Not that it's really related to this patch, but do we have some way to tell the linker whether a Thumb call supports a 4MB or 16MB offset?

Thanks for the comments. I've rebased on top of D44928, only change to the source is STI. goes to STI->. I've added .arch directives to the test to check that we can switch and keep the correct check. By the way I'd be really grateful if you could accept D44928, I've been threatening to commit it unless there are any objections, but I'd feel better if the review was accepted.

On the linker side. From the BuildAttributes, specifically Tag_CPU_arch, a static linker can work out at the object level what a file was compiled for. In general linkers follow the combination rules in the ABI so that if at least one object contains Tag_CPU_arch with an architecture that supports the longer branch range, then the linker will use the longer branch range. This model doesn't work so well when there are different attributes in different functions or sections, finer grained attributes are defined in the ABI but are deprecated/optional as most linkers don't support them. However, in the most common case, where the object architecture is lower than any local change to a higher architecture for runtime selection, the linker should use the shorter range for any relocation which is at least safe.

fhahn accepted this revision.Jun 1 2018, 6:06 AM

Thanks Peter, LGTM. It's probably best to wait with committing this a bit in case Eli has any more comments.

This revision is now accepted and ready to land.Jun 1 2018, 6:06 AM

Thanks for the review, the code here is rebased on top of D44928 (not landed yet) which passes STI in as a pointer. The existing code has STI as a member (const reference) so I'd need to change STI-> to STI. but nothing else would change.

efriedma added inline comments.Jun 1 2018, 12:33 PM
lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp
529

I think we also need to check for HasV6MOps here.

Thanks for the comments I've updated the diff to show:

  • No longer rebased on D44928
  • We now allow architecture v6m to have the long range BL (I checked in the Arm ARM and this is true for v6m)
  • Test updated for v6m
  • Removed extra tests for .arch switching as these are dependent on D44928 landing.
This revision was automatically updated to reflect the committed changes.