This is an archive of the discontinued LLVM Phabricator instance.

[LowerTypeTests] Support generating Armv6-M jump tables.
ClosedPublic

Authored by simon_tatham on Feb 8 2023, 5:46 AM.

Details

Summary

The LowerTypeTests pass emits a jump table in the form of an
inlineasm IR node containing a string representation of some
assembly. It tests the target triple to see what architecture it
should be generating assembly for. But that's not good enough for
Triple::thumb, because the 32-bit PC-relative b.w branch
instruction isn't available in all supported architecture versions. In
particular, Armv6-M doesn't support that instruction (although the
similar Armv8-M Baseline does).

Most of this patch is concerned with working out whether the
compilation target is Armv6-M or not, which I'm doing by going through
all the functions in the module, retrieving a TargetTransformInfo for
each one, and querying it via a new method I've added to check its
SubtargetInfo. If any function's TTI indicates that it's targeting an
architecture supporting B.W, then we assume we're also allowed to use
B.W in the jump table.

The Armv6-M compatible jump table format requires a temporary
register, and therefore also has to use the stack in order to restore
that register.

Another consequence of this change is that jump tables on Arm/Thumb
are no longer always the same size. In particular, on an architecture
that supports Arm and Thumb-1 but not Thumb-2, the Arm and Thumb
tables are different sizes from each other. As a consequence,
`getJumpTableEntrySize` can no longer base its answer on the target
triple's architecture: it has to take into account the decision that
`selectJumpTableArmEncoding` made, which meant I had to move that
function to an earlier point in the code and store its answer in the
`LowerTypeTestsModule` class.

Diff Detail

Event Timeline

simon_tatham created this revision.Feb 8 2023, 5:46 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 8 2023, 5:46 AM
simon_tatham requested review of this revision.Feb 8 2023, 5:46 AM
lenary added a comment.Feb 8 2023, 6:05 AM

I dislike adding this to the target-independent API - is there a way we can express this with a downcast to an arm-backend-specific class and query on it, rather than adding it globally?

I don't see how. TargetTransformInfo isn't a base class with target-specific descendants. It wraps an Impl class which you can't get out of it, and even if you could, there's no LLVM-style dyn_cast setup to allow detecting its concrete type.

(I mean, I could try adding both those facilities, but surely the result would be just as ugly, if not worse!)

I agree this is an unusual thing to be doing in TargetTransformInfo, because mostly its query methods return quantitative data to inform IR transformations that don't directly use target-specific facilities. But LowerTypeTests is a very unusual IR pass already for its use of inlineasm, so it's not surprising that it has unusual needs in this area.

Could we move the whole of createJumpTableEntry (and getJumpTableEntrySize, maybe others) into TargetTransformInfo? That would move all of the existing target-specific code here into the respective backends, and avoid adding target-specific things to the interface of TargetTransformInfo`.

I see what you mean, but in that case, how do we deal with the fact that there are multiple TargetTransformInfos involved? If there was just one for the whole module then that would make sense, but there's one per function. In the current version of the patch I'm iterating over all of them asking about b.w support, and making a single decision about the jump table format based on the results of all those queries.

Maybe a silly question, but can you mix ARM and Thumb entries in the table? You can switch between ARM and Thumb mode using assembler directives. And I don't see any obvious reason the entries need to agree on Thumb-ness; they just need to be independently callable.

Maybe a silly question, but can you mix ARM and Thumb entries in the table? You can switch between ARM and Thumb mode using assembler directives. And I don't see any obvious reason the entries need to agree on Thumb-ness; they just need to be independently callable.

Nevermind, this doesn't actually help what you're doing; the Thumbv6m thunks are a different size.

Nevermind, this doesn't actually help what you're doing; the Thumbv6m thunks are a different size.

And I was going to add that if you're in a v6-M environment then Thumb is all you have anyway – that architecture has no Arm state at all.

But now I write that, you've made me think of something else: architectures earlier still, like v5 and v4, support both Arm and Thumb but don't have b.w. In those, it's probably a better idea to use Arm-state jump tables unconditionally, precisely to avoid having to do this cumbersome stack-based branch!

lenary added a comment.Feb 9 2023, 4:07 AM

Offline, I suggested to Simon that the info about whether you have thumb2 is available in two places: in the subtarget, and also in the target triple's subarch, and that maybe he could use the latter instead of adding an arm-architecture-specific hook to TTI (which would be better to avoid). He reported that the final subarch during LTO depends on the object order during the link, rather than on something more determinstic, and therefore using the triple feels to me less reliable than the current approach in this patch.

On that basis, it seems the arm-architecture-specific TTI hook is the least worst approach.

simon_tatham edited the summary of this revision. (Show Details)

Revised the patch to make the right decision on Armv6 and before, where Arm and Thumb-1 jump tables are both available, and we always want to pick Arm because it's smaller and faster. This also exposed a bug in which `getJumpTableEntrySize was ignoring the fact that selectJumpTableArmEncoding` might have swapped to the other one of Arm and Thumb (and until now it didn't matter because the table entries were always the same size for both).

Ping? @lenary agreed that this is the least bad option to fix the codegen fault, and a week ago I fixed the only problem I knew of with the patch.

lenary accepted this revision.Feb 16 2023, 7:32 AM
This revision is now accepted and ready to land.Feb 16 2023, 7:32 AM