-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[VPlan] Add VPInst::getNumOperandsForOpcode, use to verify in ctor (NFC) #142284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments.
@llvm/pr-subscribers-vectorizers @llvm/pr-subscribers-llvm-transforms Author: Florian Hahn (fhahn) ChangesAdd a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments. Full diff: https://github.com/llvm/llvm-project/pull/142284.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h
index 44f0b6d964a6e..bd6a3247abd7d 100644
--- a/llvm/lib/Transforms/Vectorize/VPlan.h
+++ b/llvm/lib/Transforms/Vectorize/VPlan.h
@@ -967,6 +967,13 @@ class VPInstruction : public VPRecipeWithIRFlags,
/// value for lane \p Lane.
Value *generatePerLane(VPTransformState &State, const VPLane &Lane);
+#if !defined(NDEBUG)
+ /// Return the number of operands determined by the opcode of the
+ /// VPInstruction. Returns -1 if the number of operands cannot be determined
+ /// directly by the opcode.
+ unsigned getNumOperandsForOpcode() const;
+#endif
+
public:
VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands, DebugLoc DL = {},
const Twine &Name = "")
diff --git a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
index a4831ea7c11f7..5c6e4aeaf3cad 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp
@@ -413,8 +413,62 @@ VPInstruction::VPInstruction(unsigned Opcode, ArrayRef<VPValue *> Operands,
Opcode(Opcode), Name(Name.str()) {
assert(flagsValidForOpcode(getOpcode()) &&
"Set flags not supported for the provided opcode");
+ assert((getNumOperandsForOpcode() == -1u ||
+ getNumOperandsForOpcode() == getNumOperands()) &&
+ "number of operands does not match opcode");
}
+#ifndef NDEBUG
+unsigned VPInstruction::getNumOperandsForOpcode() const {
+ if (Instruction::isUnaryOp(getOpcode()) || Instruction::isCast(getOpcode()))
+ return 1;
+
+ if (Instruction::isBinaryOp(getOpcode()))
+ return 2;
+
+ switch (getOpcode()) {
+ case VPInstruction::StepVector:
+ return 0;
+ case Instruction::Alloca:
+ case Instruction::ExtractValue:
+ case Instruction::Freeze:
+ case Instruction::Load:
+ case VPInstruction::AnyOf:
+ case VPInstruction::BranchOnCond:
+ case VPInstruction::CalculateTripCountMinusVF:
+ case VPInstruction::CanonicalIVIncrementForPart:
+ case VPInstruction::ExplicitVectorLength:
+ case VPInstruction::ExtractLastElement:
+ case VPInstruction::ExtractPenultimateElement:
+ case VPInstruction::FirstActiveLane:
+ case VPInstruction::Not:
+ return 1;
+
+ case Instruction::ICmp:
+ case Instruction::FCmp:
+ case Instruction::Store:
+ case VPInstruction::ActiveLaneMask:
+ case VPInstruction::BranchOnCount:
+ case VPInstruction::ComputeReductionResult:
+ case VPInstruction::FirstOrderRecurrenceSplice:
+ case VPInstruction::LogicalAnd:
+ case VPInstruction::WideIVStep:
+ case VPInstruction::PtrAdd:
+ return 2;
+ case Instruction::Select:
+ case VPInstruction::ComputeFindLastIVResult:
+ return 3;
+ case Instruction::Call:
+ case Instruction::PHI:
+ case Instruction::GetElementPtr:
+ case Instruction::Switch:
+ // Cannot determine the number of operands from the opcode.
+ return -1u;
+ }
+ llvm_unreachable("all cases should be handled above");
+}
+#endif
+
bool VPInstruction::doesGeneratePerAllLanes() const {
return Opcode == VPInstruction::PtrAdd && !vputils::onlyFirstLaneUsed(this);
}
@@ -2706,7 +2760,10 @@ static void scalarizeInstruction(const Instruction *Instr,
// Replace the operands of the cloned instructions with their scalar
// equivalents in the new loop.
- for (const auto &I : enumerate(RepRecipe->operands())) {
+ auto OpRange = RepRecipe->operands();
+ if (isa<CallBase>(Cloned))
+ OpRange = drop_end(OpRange);
+ for (const auto &I : enumerate(OpRange)) {
auto InputLane = Lane;
VPValue *Operand = I.value();
if (vputils::isSingleScalar(Operand))
|
/// Return the number of operands determined by the opcode of the | ||
/// VPInstruction. Returns -1 if the number of operands cannot be determined | ||
/// directly by the opcode. | ||
unsigned getNumOperandsForOpcode() const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static or vputils getNumOperandsFor(Opcode)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done thanks!
case VPInstruction::WideIVStep: | ||
case VPInstruction::PtrAdd: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case VPInstruction::WideIVStep: | |
case VPInstruction::PtrAdd: | |
case VPInstruction::PtrAdd: | |
case VPInstruction::WideIVStep: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipped, thanks
case Instruction::PHI: | ||
case Instruction::GetElementPtr: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
case Instruction::PHI: | |
case Instruction::GetElementPtr: | |
case Instruction::GetElementPtr: | |
case Instruction::PHI: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Flipped, thanks!
@@ -967,6 +967,13 @@ class VPInstruction : public VPRecipeWithIRFlags, | |||
/// value for lane \p Lane. | |||
Value *generatePerLane(VPTransformState &State, const VPLane &Lane); | |||
|
|||
#if !defined(NDEBUG) | |||
/// Return the number of operands determined by the opcode of the | |||
/// VPInstruction. Returns -1 if the number of operands cannot be determined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// VPInstruction. Returns -1 if the number of operands cannot be determined | |
/// VPInstruction. Returns -1u if the number of operands cannot be determined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done thanks
auto OpRange = RepRecipe->operands(); | ||
if (isa<CallBase>(Cloned)) | ||
OpRange = drop_end(OpRange); | ||
for (const auto &I : enumerate(OpRange)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How/is this related to introducing getNumOperandsForOpcode()
(i.e., rest of patch)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was unrelated, removed ,thanks
BTW, masking could alternatively have an explicit API for setting and getting, possibly maintaining a pointer to a VPInstruction's mask or null when unmasked. |
Yep, the WIP patch to use this for masking provides such an API, although based on the number of operands (https://github.com/llvm/llvm-project/pull/142285/files#diff-dabd8bf9956285f5ddab712af4e0494647a106234f07283b0bd9f8b4d9b887caR1039-R1073) I think the mask operand still needs to be part of the operands of the VPInstruction, to make sure it is part of the def-use graph, to get updated automatically when the mask value gets RAUWs. |
Agreed, the mask should be a regular operand, and in addition have a setter and getter to set and retrieve it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, minor nits.
case VPInstruction::FirstActiveLane: | ||
case VPInstruction::Not: | ||
return 1; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done thanks
@@ -706,13 +706,15 @@ TEST_F(VPBasicBlockTest, reassociateBlocks) { | |||
|
|||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | |||
TEST_F(VPBasicBlockTest, print) { | |||
VPInstruction *TC = new VPInstruction(Instruction::Add, {}); | |||
VPInstruction *TC = new VPInstruction(Instruction::PHI, {}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To escape num operands check?
Considered scalar, w/o operands.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. The tests here just check the various print implementations, the actual opcodes/operands don't matter much, other than matching the print checks.
There's a chicken-egg problem here, as we need to get a VPValue before calling getPlan.
VPInstruction *I1 = new VPInstruction(Instruction::Add, {}); | ||
VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1}); | ||
VPInstruction *I1 = new VPInstruction(Instruction::Add, {Val, Val}); | ||
VPInstruction *I2 = new VPInstruction(Instruction::Sub, {I1, Val}); | ||
VPInstruction *I3 = new VPInstruction(Instruction::Br, {I1, I2}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Independent: a branch has two VPInstruction operands?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, this just creates artificial VPInstructions to test printing, the ocpodes don't really matter, other than checking.
We should probably tighten down which kinds of opcodes are supported for VPInstruction
VPInstruction *I5 = new VPInstruction(Instruction::Ret, {I4}); | ||
VPInstruction *I5 = new VPInstruction(Instruction::Br, {I4}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid checking return with a single operand? A VPInstruction with an Instruction opcode should retain the latter's number of operands, but that may require checking an underlying Instruction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, we currently never create VPInstruction for ret
instructions in LV, so it seemed better to use FNeg
as used above.
… in ctor (NFC) (#142284) Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments. PR: llvm/llvm-project#142284
…FC) (llvm#142284) Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments. PR: llvm#142284
…FC) (llvm#142284) Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction. It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call). This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments. PR: llvm#142284
Add a new getNumOperandsForOpcode helper to determine the number of operands from the opcode. For now, it is used to verify the number operands at VPInstruction construction.
It returns -1 for a few opcodes where the number of operands cannot be determined (GEP, Switch, PHI, Call).
This can also be used in a follow-up to determine if a VPInstruction is masked based on the number of arguments.