diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -735,6 +735,14 @@ return Opcode == Instruction::Store || Opcode == Instruction::Call || Opcode == Instruction::Invoke || Opcode == SLPStore; } + + bool hasResult() const { + if (const Value *UV = getUnderlyingValue()) + return !UV->getType()->isVoidTy(); + // Conservatively assume all VPInstructions without underlying values + // produce results. + return true; + } }; /// VPWidenRecipe is a recipe for producing a copy of vector type for each diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -405,7 +405,8 @@ void VPInstruction::print(raw_ostream &O, VPSlotTracker &SlotTracker) const { printAsOperand(O, SlotTracker); - O << " = "; + if (hasResult()) + O << " = "; switch (getOpcode()) { case VPInstruction::Not: @@ -814,11 +815,29 @@ } void VPValue::printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const { + if (const Value *UV = getUnderlyingValue()) { + if (UV->getType()->isVoidTy()) + return; + // Get a string of underlying value from printAsOperand, so we can also handle numbered IR values without a name. + std::string UnderlyingName; + { + raw_string_ostream StrStream(UnderlyingName); + UV->printAsOperand(StrStream, false); + StrStream.flush(); + } + if (isa(UV)) + OS << "ir constant " << UnderlyingName; + else + // Drop the % from the name. + OS << "%vp.ir." << StringRef(UnderlyingName).drop_front(1); + return; + } + unsigned Slot = Tracker.getSlot(this); if (Slot == unsigned(-1)) OS << ""; else - OS << "%vp" << Tracker.getSlot(this); + OS << "%vp." << Tracker.getSlot(this); } void VPInterleavedAccessInfo::visitRegion(VPRegionBlock *Region, @@ -869,7 +888,9 @@ void VPSlotTracker::assignSlot(const VPValue *V) { assert(Slots.find(V) == Slots.end() && "VPValue already has a slot!"); - Slots[V] = NextSlot++; + const Value *UV = V->getUnderlyingValue(); + if (!UV || !UV->hasName()) + Slots[V] = NextSlot++; } void VPSlotTracker::assignSlots(const VPBlockBase *VPBB) { diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h --- a/llvm/lib/Transforms/Vectorize/VPlanValue.h +++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h @@ -42,6 +42,7 @@ friend class VPlanTransforms; friend class VPBasicBlock; friend class VPInterleavedAccessInfo; + friend class VPSlotTracker; private: const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). @@ -64,6 +65,7 @@ /// Return the underlying Value attached to this VPValue. Value *getUnderlyingValue() { return UnderlyingVal; } + const Value *getUnderlyingValue() const { return UnderlyingVal; } // Set \p Val as the underlying Value of this VPValue. void setUnderlyingValue(Value *Val) { diff --git a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp --- a/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanHCFGTest.cpp @@ -10,6 +10,7 @@ #include "../lib/Transforms/Vectorize/VPlanTransforms.h" #include "VPlanTestBase.h" #include "gtest/gtest.h" +#include namespace llvm { namespace { @@ -88,6 +89,42 @@ EXPECT_EQ(IndvarAdd, ICmp->getOperand(0)); EXPECT_EQ(VecBB->getCondBit(), ICmp); + std::string FullDump; + raw_string_ostream(FullDump) << *Plan; + EXPECT_EQ(R"(digraph VPlan { +graph [labelloc=t, fontsize=30; label="Vectorization Plan"] +node [shape=rect, fontname=Courier, fontsize=30] +edge [fontname=Courier, fontsize=30] +compound=true + subgraph cluster_N0 { + fontname=Courier + label="\ TopRegion" + N1 [label = + "entry:\n" + ] + N1 -> N2 [ label=""] + N2 [label = + "for.body:\n" + + "EMIT %vp.ir.indvars.iv = phi ir constant 0 %vp.ir.indvars.iv.next\l" + + "EMIT %vp.ir.arr.idx = getelementptr %vp.ir.A %vp.ir.indvars.iv\l" + + "EMIT %vp.ir.l1 = load %vp.ir.arr.idx\l" + + "EMIT %vp.ir.res = add %vp.ir.l1 ir constant 10\l" + + "EMIT store %vp.ir.res %vp.ir.arr.idx\l" + + "EMIT %vp.ir.indvars.iv.next = add %vp.ir.indvars.iv ir constant 1\l" + + "EMIT %vp.ir.exitcond = icmp %vp.ir.indvars.iv.next %vp.ir.N\l" + + "CondBit: %vp.ir.exitcond (for.body)\l" + ] + N2 -> N2 [ label="T"] + N2 -> N3 [ label="F"] + N3 [label = + "for.end:\n" + + "EMIT ret\l" + ] + } +} +)", + FullDump); + LoopVectorizationLegality::InductionList Inductions; SmallPtrSet DeadInstructions; VPlanTransforms::VPInstructionsToVPRecipes(LI->getLoopFor(LoopHeader), Plan, diff --git a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp --- a/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp +++ b/llvm/unittests/Transforms/Vectorize/VPlanTest.cpp @@ -216,15 +216,15 @@ compound=true N0 [label = ":\n" + - "EMIT %vp0 = catchswitch\l" + - "EMIT %vp1 = ret %vp0\l" + - "EMIT %vp2 = br %vp0 %vp1\l" + "EMIT %vp.0 = catchswitch\l" + + "EMIT %vp.1 = ret %vp.0\l" + + "EMIT %vp.2 = br %vp.0 %vp.1\l" ] N0 -> N1 [ label=""] N1 [label = ":\n" + - "EMIT %vp3 = indirectbr %vp2 %vp1\l" + - "EMIT %vp4 = invoke %vp0\l" + "EMIT %vp.3 = indirectbr %vp.2 %vp.1\l" + + "EMIT %vp.4 = invoke %vp.0\l" ] } )", @@ -235,7 +235,7 @@ raw_string_ostream OS(I3Dump); I3->print(OS); OS.flush(); - EXPECT_EQ("%vp2 = br %vp0 %vp1", I3Dump); + EXPECT_EQ("%vp.2 = br %vp.0 %vp.1", I3Dump); } { @@ -243,7 +243,7 @@ raw_string_ostream OS(I2Dump); OS << *I2; OS.flush(); - EXPECT_EQ("%vp1 = ret %vp0", I2Dump); + EXPECT_EQ("%vp.1 = ret %vp.0", I2Dump); } }