@@ -197,12 +197,32 @@ class VecUtils {
197197 // / \Returns the first integer power of 2 that is <= Num.
198198 static unsigned getFloorPowerOf2 (unsigned Num);
199199
200- // / If \p I is the last instruction of a pack pattern, then this function
201- // / returns the instructions in the pack and the operands in the pack, else
202- // / returns nullopt.
203- static std::optional<
204- std::pair<SmallVector<Instruction *>, SmallVector<Value *>>>
205- matchPack (Instruction *I) {
200+ // / Helper struct for `matchPack()`. Describes the instructions and operands
201+ // / of a pack pattern.
202+ struct PackPattern {
203+ // / The insertelement instructions that form the pack pattern in bottom-up
204+ // / order, i.e., the first instruction in `Instrs` is the bottom-most
205+ // / InsertElement instruction of the pack pattern.
206+ // / For example in this simple pack pattern:
207+ // / %Pack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
208+ // / %Pack1 = insertelement <2 x i8> %Pack0, i8 %v1, i64 1
209+ // / this is [ %Pack1, %Pack0 ].
210+ SmallVector<Instruction *> Instrs;
211+ // / The "external" operands of the pack pattern, i.e., the values that get
212+ // / packed into a vector, skipping the ones in `Instrs`. The operands are in
213+ // / bottom-up order, starting from the operands of the bottom-most insert.
214+ // / So in our example this would be [ %v1, %v0 ].
215+ SmallVector<Value *> Operands;
216+ };
217+
218+ // / If \p I is the last instruction of a pack pattern (i.e., an InsertElement
219+ // / into a vector), then this function returns the instructions in the pack
220+ // / and the operands in the pack, else returns nullopt.
221+ // / Here is an example of a matched pattern:
222+ // / %PackA0 = insertelement <2 x i8> poison, i8 %v0, i64 0
223+ // / %PackA1 = insertelement <2 x i8> %PackA0, i8 %v1, i64 1
224+ // / TODO: this currently detects only simple canonicalized patterns.
225+ static std::optional<PackPattern> matchPack (Instruction *I) {
206226 // TODO: Support vector pack patterns.
207227 // TODO: Support out-of-order inserts.
208228
@@ -213,34 +233,32 @@ class VecUtils {
213233 // The pack contains as many instrs as the lanes of the bottom-most Insert
214234 unsigned ExpectedNumInserts = VecUtils::getNumLanes (I);
215235 assert (ExpectedNumInserts >= 2 && " Expected at least 2 inserts!" );
216- SmallVector<Instruction *> PackInstrs;
217- SmallVector<Value *> PackOperands;
218- PackOperands.resize (ExpectedNumInserts);
236+ PackPattern Pack;
237+ Pack.Operands .resize (ExpectedNumInserts);
219238 // Collect the inserts by walking up the use-def chain.
220239 Instruction *InsertI = I;
221- for ([[maybe_unused]] auto Cnt : seq<unsigned >(ExpectedNumInserts)) {
240+ for (auto ExpectedLane : reverse ( seq<unsigned >(ExpectedNumInserts) )) {
222241 if (InsertI == nullptr )
223242 return std::nullopt ;
224243 if (InsertI->getParent () != BB0)
225244 return std::nullopt ;
226245 // Check the lane.
227246 auto *LaneC = dyn_cast<ConstantInt>(InsertI->getOperand (2 ));
228- unsigned ExpectedLane = ExpectedNumInserts - Cnt - 1 ;
229247 if (LaneC == nullptr || LaneC->getSExtValue () != ExpectedLane)
230248 return std::nullopt ;
231- PackInstrs .push_back (InsertI);
232- PackOperands [ExpectedLane] = InsertI->getOperand (1 );
249+ Pack. Instrs .push_back (InsertI);
250+ Pack. Operands [ExpectedLane] = InsertI->getOperand (1 );
233251
234252 Value *Op = InsertI->getOperand (0 );
235- if (Cnt == ExpectedNumInserts - 1 ) {
253+ if (ExpectedLane == 0 ) {
254+ // Check the topmost insert. The operand should be a Poison.
236255 if (!isa<PoisonValue>(Op))
237256 return std::nullopt ;
238257 } else {
239258 InsertI = dyn_cast<InsertElementInst>(Op);
240259 }
241260 }
242- // Check the topmost insert. The operand should be a Poison.
243- return std::make_pair (PackInstrs, PackOperands);
261+ return Pack;
244262 }
245263
246264#ifndef NDEBUG
0 commit comments