This is an archive of the discontinued LLVM Phabricator instance.

[Inliner] Don't inline functions with incompatible vscale_range attributes
AbandonedPublic

Authored by c-rhodes on Oct 8 2021, 5:35 AM.

Details

Summary

Inlining a function with a vscale_range attribute that is more
restrictive than the caller's vscale_range could lead to incorrect
results, prevent it in the inliner.

Inlining a function with a less restrictive vscale_range into a function
with a more restrictive vscale_range is ok, and potentially profitable
since the compiler has more opportunity to optimise.

Diff Detail

Event Timeline

c-rhodes created this revision.Oct 8 2021, 5:35 AM
c-rhodes requested review of this revision.Oct 8 2021, 5:35 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 8 2021, 5:35 AM
sdesmalen added inline comments.Oct 11 2021, 3:52 AM
llvm/lib/Transforms/Utils/InlineFunction.cpp
1747–1761

nit: the code below says as much, so the comment is a bit redundant?

1764

nit: you can query the attribute even if it is not set, since it returns a invalid/empty Attribute. This way you can write:

Attribute CallerRange = Caller.getFnAttribute(Attribute::VScaleRange);
Attribute CalleeRange = Callee.getFnAttribute(Attribute::VScaleRange);

unsigned CallerMinVScale, CallerMaxVScale;
std::tie(CallerMinVScale, CallerMaxVScale) = CallerRange.getValueAsBool()
        ? CallerRange.getVScaleRangeArgs()
        : {0, 0};
unsigned CalleeMinVScale, CalleeMaxVScale;
std::tie(CalleeMinVScale, CalleeMaxVScale) = CalleeRange.getValueAsBool()
        ? CalleeRange.getVScaleRangeArgs()
        : {0, 0};

And then do all the tests on the individual min and max ranges, rather than having to discard the 'has no attribute' cases first.

1773

I'm wondering if this is overly restrictive. If the caller has vscale_range(4, 4) and the callee has no vscale_range (i.e. is unbounded, meaning the code runs on machine with any vscale), then I think it can still be inlined because if it can run on a machine with any vscale, it can also run on a machine with vscale_range(4, 4)

1794

Currently this code would avoid inlining a function with

`vscale_range(0, 16)` into a function with `vscale_range(4, 16)`

which we should probably allow.

For the 'unbounded' minimum I think we can interpret this as '1' (i.e. the minimally required vscale could be anything, it means it (also) has to run on a vscale of 1, so we can assume 1).
For the unbounded maximum we can interpret this as UINT_MAX (i.e. the length of the vector is unknown, so assume worst-case)

And then do the individual comparisons on those newly interpreted values.

david-arm added inline comments.Oct 11 2021, 4:00 AM
llvm/lib/Transforms/Utils/InlineFunction.cpp
1794

I wonder what the point is of having a 0 for the minimum here then? It feels like we should just never allow a 0 minimum for vscale_range as I don't think the LangRef is particularly clear. The way I read the LangRef it sounds like min could be anything, like 8 or 3. If min could be >4 then it's not safe to inline, right? At the moment it feels like we're tightening the meaning of the vscale_range attribute without changing the documentation, which feels a bit dangerous that's all.

sdesmalen added inline comments.Oct 11 2021, 5:50 AM
llvm/lib/Transforms/Utils/InlineFunction.cpp
1794

You're right that 'unbounded' is a strange value for the minimum and I recall conversations where we'd like to see this fixed because it doesn't really have any other meaning than '1'.

What it means is that if the minimally required vscale is unbounded, the program with attribute vscale_range(0, xx) has to run on a machine with a value of vscale that's at least 1, or 2, or ... , or K. The lowest requirement for the minimum here is for vscale to be at least '1', so we can assume 1.

c-rhodes updated this revision to Diff 379089.Oct 12 2021, 9:55 AM

Address comments

c-rhodes added inline comments.Oct 12 2021, 9:59 AM
llvm/lib/Transforms/Utils/InlineFunction.cpp
1747–1761

nit: the code below says as much, so the comment is a bit redundant?

I've removed the comment.

1764

nit: you can query the attribute even if it is not set, since it returns a invalid/empty Attribute. This way you can write:

Attribute CallerRange = Caller.getFnAttribute(Attribute::VScaleRange);
Attribute CalleeRange = Callee.getFnAttribute(Attribute::VScaleRange);

unsigned CallerMinVScale, CallerMaxVScale;
std::tie(CallerMinVScale, CallerMaxVScale) = CallerRange.getValueAsBool()
        ? CallerRange.getVScaleRangeArgs()
        : {0, 0};
unsigned CalleeMinVScale, CalleeMaxVScale;
std::tie(CalleeMinVScale, CalleeMaxVScale) = CalleeRange.getValueAsBool()
        ? CalleeRange.getVScaleRangeArgs()
        : {0, 0};

And then do all the tests on the individual min and max ranges, rather than having to discard the 'has no attribute' cases first.

getValueAsBool expects the attribute value to be a string so I couldn't use that, I've opted to check .isValid() instead.

1794

Currently this code would avoid inlining a function with

`vscale_range(0, 16)` into a function with `vscale_range(4, 16)`

which we should probably allow.

For the 'unbounded' minimum I think we can interpret this as '1' (i.e. the minimally required vscale could be anything, it means it (also) has to run on a vscale of 1, so we can assume 1).

Thanks for pointing this out, should be fixed now. I've added tests for unbounded min.

For the unbounded maximum we can interpret this as UINT_MAX (i.e. the length of the vector is unknown, so assume worst-case)

And then do the individual comparisons on those newly interpreted values.

I've mapped unbounded max to UINT_MAX.

Thanks, that looks a lot simpler now!

llvm/test/Transforms/Inline/inline-vscale-range.ll
5

It may be easier to read the tests if you move the CHECK: remark:'s to the caller definitions.
Can you also enable -pass-remarks=inline and have CHECK lines to check that a function has been inlined (for the positive cases) ?

21

why are these CHECK lines here?

c-rhodes added inline comments.Oct 13 2021, 5:31 AM
llvm/test/Transforms/Inline/inline-vscale-range.ll
5

It may be easier to read the tests if you move the CHECK: remark:'s to the caller definitions.

All the remarks are emitted at the top, I don't think this will work with the CHECK-LABELs but I'll try.

Can you also enable -pass-remarks=inline and have CHECK lines to check that a function has been inlined (for the positive cases) ?

Sure

21

why are these CHECK lines here?

Because it's not inlined, these are auto-generated

c-rhodes updated this revision to Diff 379356.Oct 13 2021, 5:44 AM

add checks for -pass-remarks=inline

c-rhodes added inline comments.Oct 13 2021, 5:47 AM
llvm/test/Transforms/Inline/inline-vscale-range.ll
5

I've added positive tests. I agree it would be nice to have the remark CHECKs beside the relevant functions but it doesn't like that. I looked at some loop vectorizer test (scalable-vf-hint.ll) I recalled from a while back and there we have 2 run lines so the remarks are inline, bit I'm not sure if that's worth doing here.

c-rhodes updated this revision to Diff 379362.Oct 13 2021, 6:38 AM
  • Drop internal from callee functions, CHECK lines are now generated for all callees.
  • Add a separate run line for remarks and move checks beside relevant callers.
sdesmalen accepted this revision.Oct 13 2021, 6:49 AM

LGTM, cheers for the changes @c-rhodes!

This revision is now accepted and ready to land.Oct 13 2021, 6:49 AM

Hi @c-rhodes , sorry for not getting to this until after you've spent time fixing up review comments but I'm struggling to see what bug this patch is trying to fix and how preventing function inlining fixes it. From what I can see we're basically saying that when function A calls function B and function A's vscale_range is incompatible with function B's then we should not allow B to be inlined into A. But if the two functions have incompatible vscale_range attributes then the actual bug is that A should not be calling B (i.e. it's a bug in user code) and preventing inline will not fix that. What do you think? Have I misunderstood something?

c-rhodes abandoned this revision.Oct 14 2021, 6:34 AM

Hi @c-rhodes , sorry for not getting to this until after you've spent time fixing up review comments but I'm struggling to see what bug this patch is trying to fix and how preventing function inlining fixes it. From what I can see we're basically saying that when function A calls function B and function A's vscale_range is incompatible with function B's then we should not allow B to be inlined into A. But if the two functions have incompatible vscale_range attributes then the actual bug is that A should not be calling B (i.e. it's a bug in user code) and preventing inline will not fix that. What do you think? Have I misunderstood something?

Thanks for raising this Paul, it seems you're right this isn't actually necessary. It was thought this type of inlining with incompatible vscale_range attributes could occur when using function multi-versioning, but that seems unlikely.