This is an archive of the discontinued LLVM Phabricator instance.

[LV] Wrap LV illegality reporting in a function. NFC.
ClosedPublic

Authored by psamolysov on May 27 2019, 3:36 AM.

Details

Summary
A function for loop vectorization illegality reporting has been
introduced:

```
void LoopVectorizationLegality::reportVectorizationFailure(
    const StringRef DebugMsg, const StringRef OREMsg,
    const StringRef ORETag, Instruction * const I) const;
```

The function prints a debug message when the debug for the compilation
unit is enabled as well as invokes the optimization report emitter to
generate a message with a specified tag. The function doesn't cover any
complicated logic when a custom lambda should be passed to the emitter,
only generating a message with a tag is supported.

The function always prints the instruction `I` after the debug message
whenever the instruction is specified, otherwise the debug message
ends with a dot: 'LV: Not vectorizing: Disabled/already vectorized.'

The idea was present by @hsaito. The patch depends on D62311 and should be land after D62311 is applied.

Diff Detail

Event Timeline

psamolysov created this revision.May 27 2019, 3:36 AM

Looks nice, thanks! Though, does it need to be a member function? Why not just a local static function?

@rengolin It is because the function uses OptimizationRemarkEmitter *ORE, a member of the LoopVectorizationLegality class.

@rengolin It is because the function uses OptimizationRemarkEmitter *ORE, a member of the LoopVectorizationLegality class.

I see. Given the function has a lot of arguments already and it really isn't used elsewhere, I'd rather just add ORE to the args list.

Unless @hsaito or @fhahn think this could be used elsewhere in the vectorizer, then it shouldn't be in that class anyway.

psamolysov added a comment.EditedMay 27 2019, 8:02 PM

I don't understand why having a function with a lot of arguments is better than a private method getting access to the class' members. Why are private methods in C++ at all, they also are used only from class methods and can be replaced with static util functions getting required class members as arguments.

I believe the LoopVectorize class also should use this function since there are a number of occurrences of the same pattern: to report about a problem into dbgs() and emit an ORE (i.e. see the LoopVectorizationCostModel::computeMaxVF, LoopVectorizationCostModel::selectVectorizationFactor methods). So, if we don't want to duplicate the code, the method reportVectorizationFailure can't be a static function available only in a single translation unit. It could be a public method of LoopVectorizationLegality and be invoked via the Legal pointer, be a static method of the LoopVectorizationLegality, or be a non-static function defined there and taking ORE as a parameter, or just be duplicated in LoopVectorizationLegality.cpp and LoopVectorize.cpp but obviously this is not a good idea.

By the way, I'm a bit confused: in LoopVectorizationLegality.cpp the createMissedAnalysis function is used to emit an ORE while in LoopVectorize.cpp the creatingLVMissedAnalysis, which takes the pass name argument, is. I believe a PassName parameter (const char * with default value = nullptr) should be introduced for the reportVectorizationFailure function.

@rengolin It is because the function uses OptimizationRemarkEmitter *ORE, a member of the LoopVectorizationLegality class.

I see. Given the function has a lot of arguments already and it really isn't used elsewhere, I'd rather just add ORE to the args list.

Unless @hsaito or @fhahn think this could be used elsewhere in the vectorizer, then it shouldn't be in that class anyway.

@psamolysov, thanks for working on this.

Possible (and most likely recommended, if feasible) usage outside of Legal: Bail out due to cost and bail out before LV driver code hits legal (but after LV's runOnFunction() starts).
If we include those usage, emitting the message through "Legal" utility (be it member function or a utility function residing in Legal code) looks odd. Should be more like a LV level
utility. Else, what @rengolin says makes sense.

I think this is already a nice improvement. I'm fine for this patch landing as a local static function and then think about promoting this idea further into a LV level utility separately.

I believe the LoopVectorize class also should use this function since there are a number of occurrences of the same pattern

I agree, this could be higher up and clean up a lot of error reporting infrastructure.

I don't understand why having a function with a lot of arguments is better than a private method getting access to the class' members. Why are private methods in C++ at all, they also are used only from class methods and can be replaced with static util functions getting required class members as arguments.

For reference, this is not about access or class size, but bloat in the header for functionality that is internal to the cpp file. This is a common pattern in LLVM and developers know what to expect.

It's a pattern which conveys the idea that the functionality is orthogonal to the class' intention (which this is, just error reporting) and so not really belongs to the class itself.

Furthermore, the method already has a lot of arguments, this would only be adding one new one, so not a great difference.

--renato

@rengolin thank you for the comment, you are right, a private method also has an implicit parter this so the number of parameters will be the same.

@hsaito well, I will update the patch, but unfortunately we have no header for LoopVectorize.cpp so I'm thinking about moving the definition of the reportVectorizationFailure to LoopVectorize.cpp and add the external declaration to LoopVectorizationLegality.cpp but, as you have mentioned, in a different commit.

psamolysov added a comment.EditedMay 28 2019, 12:52 PM

@rengolin @hsaito Hm... I'm about to removing the private method createMissedAnalysis from LoopVectorizationLegality.h but since it was a method an had access to TheLoop and Hints class members, the pass name and Loop also must be passes to reportVectorizationFailure as parameters and instead of only additional parameter: ORE, the utility function should take three. The signature is the following:

cpp
/// Reports a vectorization illegality: print \p DebugMsg for debugging
/// purposes along with the corresponding optimization remark.
static void reportVectorizationFailure(const StringRef DebugMsg,
    const StringRef OREMsg, const StringRef ORETag, const char * PassName,
    OptimizationRemarkEmitter *ORE, Loop *Loop, Instruction *I = nullptr);

I think it doesn't look nice. But if you accepted this signature, I'll update the diff to using it.

psamolysov updated this revision to Diff 203123.Jun 5 2019, 5:16 AM

I've updated the diff in the following way:

    • The method reportVectorizationFailure was broken into two, the helper function 'debugVectorizationFailure` that writes a message to dbgs() and prints the instruction that prevents vectorization if any.
  • The method reportVectorizationFailure is saved, but the method createMissedAnalysis was removed from the LoopVectorizationLegality class, so reportVectorizationFailure just replaces the createMissedAnalysis one.

Because the number of method declared in the LoopVectorizationLegality class has not been changed, I think the solution can be accepted: the main objection - we not require additional private methods in class' header - could be considered as handled. Having a private method with access to the class' members: TheLoop, ORE, and Hints looks better than a helper method with a lot of parameters (the same loop, ORE, Hints).

@fhahn @hsaito @rengolin What are your opinions?

rengolin accepted this revision.Jun 5 2019, 1:17 PM

Much cleaner, thanks! I think we should deal with extending the functionality in a separate patch, since that's already a good localized improvement.

LGTM. Thanks!

This revision is now accepted and ready to land.Jun 5 2019, 1:17 PM

@rengolin could you land the patch, please.

rengolin closed this revision.Jun 6 2019, 12:13 PM

Committed as r362736