1 /*========================== begin_copyright_notice ============================
2
3 Copyright (C) 2017-2021 Intel Corporation
4
5 SPDX-License-Identifier: MIT
6
7 ============================= end_copyright_notice ===========================*/
8
9 //
10 // Implementation of methods for Region class
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "GenXAlignmentInfo.h"
15 #include "GenXBaling.h"
16 #include "GenXSubtarget.h"
17 #include "GenXUtil.h"
18 #include "vc/GenXOpts/GenXAnalysis.h"
19
20 #include "llvm/ADT/SmallBitVector.h"
21 #include "llvm/Analysis/ConstantFolding.h"
22 #include "llvm/Analysis/TargetLibraryInfo.h"
23 #include "llvm/Analysis/ValueTracking.h"
24 #include "llvm/IR/Constants.h"
25 #include "llvm/IR/DerivedTypes.h"
26 #include "llvm/IR/Function.h"
27 #include "llvm/IR/Instructions.h"
28 #include "llvm/Support/Debug.h"
29 #include <unordered_map>
30 #include "Probe/Assertion.h"
31
32 #include "llvmWrapper/IR/DerivedTypes.h"
33 #include "llvmWrapper/Support/TypeSize.h"
34
35 using namespace llvm;
36 using namespace genx;
37
38 namespace {
39
40 /***********************************************************************
41 * Local function for testing one assertion statement.
42 * It returns true if all is ok.
43 * If region index is a vector it should has given number of elements.
44 */
testRegionIndexForSizeMismatch(const llvm::Value * const V,const unsigned & Width,const unsigned & NumElements)45 bool testRegionIndexForSizeMismatch(const llvm::Value *const V,
46 const unsigned& Width, const unsigned& NumElements) {
47
48 bool Result = true;
49
50 auto *const VT = dyn_cast<IGCLLVM::FixedVectorType>(V->getType());
51
52 if (VT) {
53 const unsigned VectorElements = (VT->getNumElements() * Width);
54 Result = (VectorElements == NumElements);
55 IGC_ASSERT_MESSAGE(Result, "vector region index size mismatch");
56 }
57
58 return Result;
59 }
60
61 /***********************************************************************
62 * Local function for testing one assertion statement.
63 * It returns true if all is ok.
64 * Instruction 'or' should be changed to 'add' without any errors.
65 */
testOperator(const llvm::Instruction * const Operator)66 bool testOperator(const llvm::Instruction *const Operator) {
67
68 IGC_ASSERT(Operator);
69 IGC_ASSERT(Operator->getModule());
70
71 const unsigned Opcode = Operator->getOpcode();
72 const bool IsAdd = (Instruction::Add == Opcode);
73 const bool IsSub = (Instruction::Sub == Opcode);
74 const bool IsOr = (Instruction::Or == Opcode);
75 const bool IsAddAddr =
76 (GenXIntrinsic::genx_add_addr == GenXIntrinsic::getGenXIntrinsicID(Operator));
77
78 bool Result = (IsAdd || IsSub || IsOr || IsAddAddr);
79 IGC_ASSERT_MESSAGE(Result,
80 "your offset seems to be calculated not through ADD or OR");
81
82 // check if instruction 'or' could be changed to 'add'
83 if (Result && IsOr) {
84 const llvm::Value *const Op0 = Operator->getOperand(0);
85 const llvm::Value *const Op1 = Operator->getOperand(1);
86 const DataLayout &DL = Operator->getModule()->getDataLayout();
87
88 Result = llvm::haveNoCommonBitsSet(Op0, Op1, DL);
89 IGC_ASSERT_MESSAGE(Result, "OR should be changed to ADD with no errors");
90 }
91
92 return Result;
93 }
94
95 } // namespace
96
97
98 /***********************************************************************
99 * makeRegionWithOffset: get a Region given a rdregion/wrregion, baling in
100 * constant add of offset
101 *
102 * This constructs the Region with a variable index that is a constant add
103 * baled in (i.e. Region::Indirect and Region::Offset both set to the
104 * operands of the add). It is for use when baling information is not
105 * available, but the caller wants the constant offset separated out like
106 * that.
107 */
makeRegionWithOffset(Instruction * Inst,bool WantParentWidth)108 Region genx::makeRegionWithOffset(Instruction *Inst, bool WantParentWidth) {
109 unsigned OperandNum = 0;
110 switch (GenXIntrinsic::getGenXIntrinsicID(Inst)) {
111 case GenXIntrinsic::genx_rdregioni:
112 case GenXIntrinsic::genx_rdregionf:
113 OperandNum = GenXIntrinsic::GenXRegion::RdIndexOperandNum;
114 break;
115 case GenXIntrinsic::genx_wrregioni:
116 case GenXIntrinsic::genx_wrregionf:
117 case GenXIntrinsic::genx_wrconstregion:
118 OperandNum = GenXIntrinsic::GenXRegion::WrIndexOperandNum;
119 break;
120 default:
121 IGC_ASSERT_EXIT_MESSAGE(0, "not rdregion or wrregion");
122 break;
123 }
124 BaleInfo BI;
125 if (GenXBaling::isBalableIndexAdd(Inst->getOperand(OperandNum)))
126 BI.setOperandBaled(OperandNum);
127 return makeRegionFromBaleInfo(Inst, BI, WantParentWidth);
128 }
129
130 /***********************************************************************
131 * Region constructor from a rd/wr region and its BaleInfo
132 * This also works with rdpredregion and wrpredregion, with Offset in
133 * bits rather than bytes, and with ElementBytes set to 1.
134 */
makeRegionFromBaleInfo(Instruction * Inst,const BaleInfo & BI,bool WantParentWidth)135 Region genx::makeRegionFromBaleInfo(Instruction *Inst, const BaleInfo &BI,
136 bool WantParentWidth) {
137 Region Result;
138 // Determine where to get the subregion value from and which arg index
139 // the region parameters start at.
140 unsigned ArgIdx = 0;
141 Value *Subregion = 0;
142 IGC_ASSERT(isa<CallInst>(Inst));
143 auto CallI = cast<CallInst>(Inst);
144 IGC_ASSERT(CallI->getCalledFunction());
145 switch (GenXIntrinsic::getGenXIntrinsicID(CallI->getCalledFunction())) {
146 case GenXIntrinsic::genx_rdpredregion:
147 Result.NumElements =
148 cast<IGCLLVM::FixedVectorType>(Inst->getType())->getNumElements();
149 Result.Width = Result.NumElements;
150 Result.Offset = cast<ConstantInt>(Inst->getOperand(1))->getZExtValue();
151 Result.ElementBytes = 1;
152 return Result;
153 case GenXIntrinsic::genx_wrpredregion:
154 Result.NumElements =
155 cast<IGCLLVM::FixedVectorType>(Inst->getOperand(1)->getType())
156 ->getNumElements();
157 Result.Width = Result.NumElements;
158 Result.Offset = cast<ConstantInt>(Inst->getOperand(2))->getZExtValue();
159 Result.ElementBytes = 1;
160 return Result;
161 case GenXIntrinsic::genx_rdregioni:
162 case GenXIntrinsic::genx_rdregionf:
163 ArgIdx = 1;
164 // The size/type of the region is given by the return value:
165 Subregion = Inst;
166 break;
167 case GenXIntrinsic::genx_wrregioni:
168 case GenXIntrinsic::genx_wrregionf:
169 case GenXIntrinsic::genx_wrconstregion:
170 ArgIdx = 2;
171 // The size/type of the region is given by the "subregion value to
172 // write" operand:
173 Subregion = Inst->getOperand(1);
174 // For wrregion, while we're here, also get the mask. We set mask to NULL
175 // if the mask operand is constant 1 (i.e. not predicated).
176 Result.Mask =
177 Inst->getOperand(GenXIntrinsic::GenXRegion::PredicateOperandNum);
178 if (auto C = dyn_cast<Constant>(Result.Mask))
179 if (C->isAllOnesValue())
180 Result.Mask = 0;
181 break;
182 default:
183 IGC_ASSERT(0);
184 }
185 // Get the region parameters.
186 IGC_ASSERT(Subregion);
187 Result.ElementTy = Subregion->getType();
188 if (auto *VT = dyn_cast<IGCLLVM::FixedVectorType>(Result.ElementTy)) {
189 Result.ElementTy = VT->getElementType();
190 Result.NumElements = VT->getNumElements();
191 }
192 const DataLayout &DL = Inst->getModule()->getDataLayout();
193 static_assert(genx::ByteBits);
194 IGC_ASSERT(DL.getTypeSizeInBits(Result.ElementTy) % genx::ByteBits == 0);
195 Result.ElementBytes = DL.getTypeSizeInBits(Result.ElementTy) / genx::ByteBits;
196 Result.VStride = cast<ConstantInt>(Inst->getOperand(ArgIdx))->getSExtValue();
197 Result.Width =
198 cast<ConstantInt>(Inst->getOperand(ArgIdx + 1))->getSExtValue();
199 Result.Stride =
200 cast<ConstantInt>(Inst->getOperand(ArgIdx + 2))->getSExtValue();
201 ArgIdx += 3;
202 // Get the start index.
203 Value *V = Inst->getOperand(ArgIdx);
204 IGC_ASSERT_MESSAGE(V->getType()->getScalarType()->isIntegerTy(16),
205 "region index must be i16 or vXi16 type");
206 IGC_ASSERT(
207 testRegionIndexForSizeMismatch(V, Result.Width, Result.NumElements));
208
209 if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
210 Result.Offset = CI->getSExtValue(); // Constant index.
211 else {
212 Result.Indirect = V; // Index is variable; assume no baled in add.
213 if (BI.isOperandBaled(ArgIdx)) {
214 Instruction *Operator = cast<Instruction>(V);
215 // The index is variable and has something baled in. We want to process
216 // a baled in add or add_addr, and ignore a baled in rdregion.
217 if(!GenXIntrinsic::isRdRegion(Operator)) {
218 // The index is variable and has a baled in or/add/sub/add_addr.
219 // offset is calculated through 'add' or 'or'
220 IGC_ASSERT(testOperator(Operator));
221
222 Constant *C = cast<Constant>(Operator->getOperand(1));
223 ConstantInt *CI = dyn_cast<ConstantInt>(C);
224 if (!CI)
225 CI = cast<ConstantInt>(C->getSplatValue());
226
227 Result.Offset = CI->getSExtValue();
228
229 if (Operator->getOpcode() == Instruction::Sub)
230 Result.Offset = -Result.Offset;
231
232 Result.Indirect = Operator->getOperand(0);
233 }
234 }
235 // For a variable index, get the parent width arg.
236 ConstantInt *PW = dyn_cast<ConstantInt>(Inst->getOperand(ArgIdx + 1));
237 if (PW)
238 Result.ParentWidth = PW->getZExtValue();
239 }
240 // We do some trivial legalization here. The legalization pass does not
241 // make these changes; instead we do them here so they are not permanently
242 // written back into the IR but are made on the fly each time some other
243 // pass uses this code to get the region info.
244 if (Result.NumElements == 1) {
245 Result.Width = Result.Stride = 1;
246 Result.VStride = 0;
247 } else {
248 if (Result.NumElements <= Result.Width) {
249 Result.Width = Result.NumElements;
250 Result.VStride = 0;
251 } else if ((unsigned)Result.VStride == Result.Width * Result.Stride) {
252 // VStride == Width * Stride, so we can canonicalize to a 1D region,
253 // but only if not indirect or not asked to preserve parentwidth,
254 // and never if multi-indirect.
255 if (!Result.Indirect ||
256 (!isa<VectorType>(Result.Indirect->getType()) && !WantParentWidth)) {
257 Result.Width = Result.NumElements;
258 Result.VStride = 0;
259 Result.ParentWidth = 0;
260 }
261 } else if (Result.Width == 1) {
262 // We can turn a 2D width 1 region into a 1D region, but if it is
263 // indirect it invalidates ParentWidth. So only do it if not asked
264 // to keep ParentWidth. Also we cannot do it if it is multi-indirect.
265 if (!Result.Indirect ||
266 (!isa<VectorType>(Result.Indirect->getType()) && !WantParentWidth)) {
267 Result.Width = Result.NumElements;
268 Result.Stride = Result.VStride;
269 Result.VStride = 0;
270 Result.ParentWidth = 0;
271 }
272 }
273 if (Result.Stride == 0 && Result.Width == Result.NumElements) {
274 // Canonical scalar region.
275 Result.Width = 1;
276 Result.VStride = 0;
277 }
278 }
279 return Result;
280 }
281
282 /***********************************************************************
283 * Region::getLegalRegionSizeForTarget: get the max legal size of a region
284 *
285 * Enter: Idx = start index into the subregion
286 * Allow2D = whether to allow 2D region
287 * InputNumElements = number of elements in whole input vector (so
288 * we can tell if it is small enough that it cannot possibly
289 * cross a GRF boundary)
290 * ST = GenXSubtarget (so we can get gen specific crossing rules)
291 * AI = 0 else AlignmentInfo (to determine alignment of indirect index)
292 */
getLegalRegionSizeForTarget(const GenXSubtarget & ST,const Region & R,unsigned Idx,bool Allow2D,unsigned InputNumElements,AlignmentInfo * AI)293 unsigned genx::getLegalRegionSizeForTarget(const GenXSubtarget &ST,
294 const Region &R, unsigned Idx,
295 bool Allow2D,
296 unsigned InputNumElements,
297 AlignmentInfo *AI) {
298 Alignment Align;
299 if (R.Indirect) {
300 Align = Alignment::getUnknown();
301 if (AI)
302 Align = AI->get(R.Indirect);
303 }
304 return getLegalRegionSizeForTarget(ST, R, Idx, Allow2D, InputNumElements,
305 Align);
306 }
307
308 /***********************************************************************
309 * Region::getLegalRegionSizeForTarget : get the max legal size of a region
310 *
311 * Enter: Idx = start index into the subregion
312 * Allow2D = whether to allow 2D region
313 * InputNumElements = number of elements in whole input vector (so
314 * we can tell if it is small enough that it cannot possibly
315 * cross a GRF boundary)
316 * ST = GenXSubtarget (so we can get gen specific crossing rules)
317 * Align = alignment of indirect index if any
318 *
319 * The setting of Indirect is used as follows:
320 *
321 * 0: not indirect
322 * anything of scalar type: single indirect
323 * anything of vector type: multi indirect
324 */
getLegalRegionSizeForTarget(const GenXSubtarget & ST,const Region & R,unsigned Idx,bool Allow2D,unsigned InputNumElements,Alignment Align)325 unsigned genx::getLegalRegionSizeForTarget(const GenXSubtarget &ST,
326 const Region &R, unsigned Idx,
327 bool Allow2D,
328 unsigned InputNumElements,
329 Alignment Align) {
330 // Determine the max valid width.
331 unsigned ValidWidth = 1;
332 unsigned GRFByteSize = ST.getGRFByteSize();
333 int MaxStride = 4;
334 unsigned LogGRFWidth = genx::log2(GRFByteSize);
335 if ((!R.Stride || exactLog2(R.Stride) >= 0) &&
336 (Allow2D || R.Stride <= MaxStride)) {
337 // The stride is legal, so we can potentially do more than one element at a
338 // time.
339 // Disallow 2D if the stride is too large for a real Gen region. For a
340 // source operand (Allow2D is true), we allow a 1D region with stride too
341 // large, because the vISA writer turns it into a 2D region with width 1.
342 bool StrideValid = (R.Stride <= MaxStride);
343
344 if (R.Indirect && isa<VectorType>(R.Indirect->getType())) {
345 // Multi indirect.
346 if (!Allow2D) {
347 // Multi indirect not allowed in wrregion.
348 if (!R.Stride)
349 ValidWidth = 1 << genx::log2(R.Width);
350 } else if (R.Width == 1 || !R.Stride) {
351 // Multi indirect with width 1 or stride 0.
352 // Return the max power of two number of elements that:
353 // 1. fit in 2 GRFs; and
354 // 2. fit in the whole region; and
355 // 3. fit in a row if the width is not legal
356 // 4. no more than 8 elements in multi indirect (because there
357 // are only 8 elements in an address register).
358 unsigned LogWidth = genx::log2(Width);
359 if (1U << LogWidth == Width)
360 LogWidth = genx::log2(R.NumElements); // legal width
361 unsigned LogElementBytes = genx::log2(R.ElementBytes);
362 if (LogWidth + LogElementBytes > (LogGRFWidth + 1))
363 LogWidth = LogGRFWidth + 1 - LogElementBytes;
364 ValidWidth = 1 << LogWidth;
365 if (ValidWidth > 8)
366 ValidWidth = 8;
367 }
368 // Other multi indirect can only do one element.
369 } else {
370 // Calculate number of elements up to the boundary imposed by GRF
371 // crossing rules.
372 unsigned ElementsPerGRF = GRFByteSize / R.ElementBytes;
373 unsigned OffsetElements = R.Offset / R.ElementBytes;
374 unsigned ElementsToBoundary = 1;
375 unsigned RealIdx = Idx / R.Width * R.VStride + Idx % R.Width * R.Stride;
376 if (!R.Indirect) {
377 // For a direct operand, just use the constant offset of the
378 // region and the index so far to calculate how far into a GRF this
379 // subregion starts, and set the boundary at the next-but-one GRF
380 // boundary.
381 unsigned NumGRF = 2;
382 ElementsToBoundary = (NumGRF * ElementsPerGRF) -
383 ((RealIdx + OffsetElements) % ElementsPerGRF);
384 } else if (InputNumElements <= ElementsPerGRF) {
385 // Indirect region but the whole vector is no bigger than a GRF, so
386 // there is no limit imposed by GRF crossing.
387 ElementsToBoundary = ElementsPerGRF;
388 } else {
389 // For an indirect region, calculate the min and max index (including
390 // offset) from the region parameters, and add on the current start
391 // index to both.
392 // For <= BDW:
393 // 1. If the min and max then are in the same GRF, then the distance
394 // from max to the next GRF boundary is the allowed size.
395 // For >= SKL:
396 // 1. If the min and max then are in the same GRF, then the distance
397 // from max to the next-but-one GRF boundary is the allowed size.
398 // 2. If the max is in the next GRF after min, then the distance
399 // from max to the next GRF boundary is the allowed size.
400 // However vISA imposes the restriction that, in a source indirect
401 // region, a row cannot cross a GRF, unless the region is contiguous.
402 // Pending a proper fix, we have a temporary fix here that we disallow
403 // GRF crossing completely unless the original region is a destination
404 // operand or is a 1D source operand (so GenXCisaBuilder can turn it
405 // into Nx1 instead of 1xN). We use Allow2D as a proxy for "is source
406 // operand".
407 unsigned GRFsPerIndirect =
408 genx::getNumGRFsPerIndirectForRegion(R, &ST, Allow2D);
409 unsigned Last = (R.NumElements / R.Width - 1) * R.VStride +
410 (R.Width - 1) * R.Stride;
411 unsigned Max = InputNumElements - Last - 1 + RealIdx;
412 unsigned Min = RealIdx;
413 unsigned MinMaxGRFDiff = (Max & -ElementsPerGRF) - (Min & -ElementsPerGRF);
414 if (!MinMaxGRFDiff) // min and max in same GRF
415 ElementsToBoundary = ElementsPerGRF * GRFsPerIndirect
416 - (Max & (ElementsPerGRF - 1));
417 else if (MinMaxGRFDiff == 1 && GRFsPerIndirect > 1)
418 ElementsToBoundary = ElementsPerGRF - (Max & (ElementsPerGRF - 1));
419 // We may be able to refine an indirect region legal width further...
420 if (exactLog2(R.ParentWidth) >= 0 &&
421 R.ParentWidth <= GRFsPerIndirect * ElementsPerGRF) {
422 // ParentWidth tells us that a row of our region cannot cross a
423 // possible number of elements addressed by indirect region. Say that
424 // the boundary is at the next multiple of ParentWidth.
425 ElementsToBoundary = std::max(R.ParentWidth - RealIdx % R.ParentWidth,
426 ElementsToBoundary);
427 } else if (!isa<VectorType>(R.Indirect->getType())) {
428 // Use the alignment+offset of the single indirect index, with alignment
429 // limited to one GRF.
430 if (!Align.isUnknown()) {
431 unsigned LogAlign = Align.getLogAlign();
432 unsigned ExtraBits = Align.getExtraBits();
433 ExtraBits += (R.Offset + RealIdx * R.ElementBytes);
434 ExtraBits &= ((1 << LogAlign) - 1);
435 if (LogAlign >= LogGRFWidth && !ExtraBits) {
436 // Start is GRF aligned, so legal width is 1 GRF for <=BDW or
437 // 2 GRFs for >=SKL.
438 ElementsToBoundary = ElementsPerGRF * GRFsPerIndirect;
439 } else if (LogAlign > (unsigned)genx::log2(R.ElementBytes) ||
440 (LogAlign == (unsigned)genx::log2(R.ElementBytes) &&
441 ExtraBits == 0)) {
442 LogAlign =
443 std::min(LogGRFWidth, LogAlign) - genx::log2(R.ElementBytes);
444 ExtraBits =
445 (ExtraBits & (GRFByteSize - 1)) >> genx::log2(R.ElementBytes);
446 // We have some alignment, so we can say that the next GRF boundary
447 // is (at least) that many elements away, minus the offset from that
448 // alignment.
449 // For SKL+, we can cross one GRF boundary, so add on one GRF's
450 // worth.
451 unsigned ElementsToBoundaryFromAlign = (1U << LogAlign) - ExtraBits;
452 ElementsToBoundaryFromAlign += (GRFsPerIndirect - 1) * ElementsPerGRF;
453 ElementsToBoundary = std::max(ElementsToBoundaryFromAlign,
454 ElementsToBoundary);
455 }
456 }
457 }
458 }
459
460 // Now calculate what subregion we can fit in before the boundary
461 // calculated above.
462 if (Allow2D && StrideValid) {
463 if ((!R.VStride || exactLog2(R.VStride) >= 0) &&
464 exactLog2(R.Width) >= 0 && R.Width <= 16 && !(Idx % R.Width) &&
465 ElementsToBoundary >= (R.Width - 1) * R.Stride + 1) {
466 // The vstride and width are legal, and we're at the start of a
467 // row, and ElementsToBoundary is big enough for at least one
468 // whole row, so we can potentially do more than one whole row at a
469 // time. See how many we can fit, without including the "slack"
470 // at the end of the last row.
471 unsigned NumRows = 0;
472 if (R.VStride == 0) // Avoid divide by 0
473 NumRows = (R.NumElements - Idx) / R.Width;
474 else {
475 unsigned LastElementOfRow = (R.Width - 1) * R.Stride;
476 unsigned Slack = R.VStride - (LastElementOfRow + 1);
477 NumRows = (ElementsToBoundary + Slack) / R.VStride;
478 if (NumRows) {
479 if (NumRows * R.Width + Idx > R.NumElements)
480 NumRows = (R.NumElements - Idx) / R.Width;
481 }
482 }
483 ValidWidth = (1 << genx::log2(NumRows)) * R.Width;
484 }
485 if (ValidWidth == 1 && Idx % R.Width) {
486 // That failed. See if we can legally get to the end of the row then
487 // the same number of elements again at the start of the next row.
488 unsigned ToEndOfRow = R.Width - Idx % R.Width;
489 if (exactLog2(ToEndOfRow) >= 0 && ToEndOfRow <= 16) {
490 unsigned NewVStride = R.VStride + (ToEndOfRow - R.Width) * R.Stride;
491 if (exactLog2(NewVStride) >= 0 &&
492 NewVStride + (ToEndOfRow - 1) * R.Stride < ElementsToBoundary) {
493 // Yes, we can do the end of one row and the same size start of
494 // the next row.
495 ValidWidth = 2 * ToEndOfRow;
496 }
497 }
498 }
499 }
500 if (ValidWidth == 1) {
501 // That failed. See how many elements we can get, no further than the
502 // next end of row.
503 ValidWidth = R.Width - Idx % R.Width;
504 if (ValidWidth * R.Stride - (R.Stride - 1) > ElementsToBoundary)
505 ValidWidth = (ElementsToBoundary + R.Stride - 1) / R.Stride;
506 ValidWidth = 1 << genx::log2(ValidWidth);
507 }
508 // If the RStride is 0 (which is seen in splat operations) then the
509 // above logic tends to determine that all of the elements can fit,
510 // irrespective of vector size and type. This is usually incorrect
511 // in the wider context, so clamp it here to whatever fits in 2GRF if
512 // necessary
513 if (ValidWidth > (2 * ElementsPerGRF))
514 ValidWidth = 2 * ElementsPerGRF;
515
516 }
517 }
518 return ValidWidth;
519 }
520
521 /***********************************************************************
522 * RdWrRegionSequence::buildFromStartWr: detect a split (legalized)
523 * sequence rdregion-wrregion from the start, and populate the
524 * RdWrRegionSequence object with its details
525 *
526 * This fails if there is any predication. It succeeds with a sequence length
527 * of one (i.e. a single rdregion-wrregion pair).
528 *
529 * On success, if the WaitingFor field matches one of the wrregions in the
530 * sequence, then WaitingFor is reset to 0. This is used by buildFromWr to
531 * check that the sequence includes the wrregion originally passed to it.
532 *
533 * On failure, EndWr is left as is, which means that isNull() continues to
534 * be true.
535 */
buildFromStartWr(Instruction * ArgStartWr,GenXBaling * Baling)536 bool RdWrRegionSequence::buildFromStartWr(Instruction *ArgStartWr,
537 GenXBaling *Baling) {
538 StartWr = ArgStartWr;
539 auto Wr = StartWr;
540 IGC_ASSERT(GenXIntrinsic::isWrRegion(Wr));
541 IGC_ASSERT(Baling);
542 Region TotalWrR = genx::makeRegionFromBaleInfo(Wr, Baling->getBaleInfo(Wr));
543 WrR = TotalWrR;
544 if (TotalWrR.Mask)
545 return false;
546 OldVal = Wr->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
547 auto RdVal = Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
548 if (auto Rd = dyn_cast<Instruction>(RdVal)) {
549 // Handle the case that the start wrregion has a rdregion, so we look for
550 // a sequence of rd-wr pairs.
551 if (!GenXIntrinsic::isRdRegion(Rd))
552 return false;
553 Region TotalRdR = makeRegionFromBaleInfo(Rd, Baling->getBaleInfo(Rd));
554 RdR = TotalRdR;
555 Input = Rd->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
556 EndWr = Wr;
557 if (Wr == WaitingFor)
558 WaitingFor = nullptr;
559 bool SeenWaitingFor = false;
560 for (;;) {
561 if (!Wr->hasOneUse() || Wr->use_begin()->getOperandNo()
562 != GenXIntrinsic::GenXRegion::OldValueOperandNum)
563 break;
564 Wr = cast<Instruction>(Wr->use_begin()->getUser());
565 if (!GenXIntrinsic::isWrRegion(Wr))
566 break;
567 Value *In = Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
568 if (!GenXIntrinsic::isRdRegion(In))
569 break;
570 auto Rd = cast<Instruction>(In);
571 if (Rd->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum) != Input)
572 break;
573 // Append to the regions. Give up if either fails.
574 if (!TotalRdR.append(
575 makeRegionFromBaleInfo(Rd, Baling->getBaleInfo(Rd))) ||
576 !TotalWrR.append(makeRegionFromBaleInfo(Wr, Baling->getBaleInfo(Wr))))
577 break;
578 SeenWaitingFor |= Wr == WaitingFor;
579 // If both regions are now legal (have a whole number of rows), then
580 // save the current position.
581 if (TotalRdR.isWholeNumRows() && TotalWrR.isWholeNumRows()) {
582 RdR = TotalRdR;
583 WrR = TotalWrR;
584 EndWr = Wr;
585 if (SeenWaitingFor)
586 WaitingFor = nullptr;
587 }
588 }
589 return true;
590 }
591 if (!isa<UndefValue>(Wr->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum)))
592 return false;
593 auto TotalC = dyn_cast<Constant>(RdVal);
594 if (!TotalC)
595 return false;
596 // Handle the case that the start wrregion has a constant "new value" operand
597 // and an undef "old value" operand.
598 // We look for a sequence of wrregions where the "new value" operands are all
599 // constant and we derive the overall constant.
600 Region TotalRdR(TotalC);
601 RdR = TotalRdR;
602 Input = TotalC;
603 EndWr = Wr;
604 if (Wr == WaitingFor)
605 WaitingFor = nullptr;
606 bool SeenWaitingFor = false;
607 for (;;) {
608 if (!Wr->hasOneUse() || Wr->use_begin()->getOperandNo()
609 != GenXIntrinsic::GenXRegion::OldValueOperandNum)
610 break;
611 Wr = cast<Instruction>(Wr->use_begin()->getUser());
612 if (!GenXIntrinsic::isWrRegion(Wr))
613 break;
614 auto In = dyn_cast<Constant>(Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum));
615 if (!In)
616 break;
617 // Append to the regions. Give up if either fails.
618 Region InR(In);
619 InR.Offset = TotalRdR.NumElements * TotalRdR.ElementBytes;
620 if (!TotalRdR.append(InR) ||
621 !TotalWrR.append(makeRegionFromBaleInfo(Wr, Baling->getBaleInfo(Wr))))
622 break;
623 SeenWaitingFor |= Wr == WaitingFor;
624 // Append the constant.
625 TotalC = concatConstants(TotalC, In);
626 // If both regions are now legal (have a whole number of rows), then save
627 // the current position.
628 if (TotalRdR.isWholeNumRows() && TotalWrR.isWholeNumRows()) {
629 RdR = TotalRdR;
630 WrR = TotalWrR;
631 EndWr = Wr;
632 Input = TotalC;
633 if (SeenWaitingFor)
634 WaitingFor = nullptr;
635 }
636 }
637 return true;
638 }
639
640 /***********************************************************************
641 * RdWrRegionSequence::buildFromWr: detect a split (legalized) rdregion-wrregion
642 * sequence starting from any wrregion within it, and populate the
643 * RdWrRegionSequence object with its details
644 *
645 * This fails if there is any predication. It succeeds with a sequence length
646 * of one (i.e. a single rdregion-wrregion pair).
647 *
648 * On failure, EndWr is left as is, which means that isNull() continues to
649 * be true.
650 */
buildFromWr(Instruction * Wr,GenXBaling * Baling)651 bool RdWrRegionSequence::buildFromWr(Instruction *Wr, GenXBaling *Baling)
652 {
653 // Remember that our sequence needs to contain Wr.
654 WaitingFor = Wr;
655 // Scan back to what looks like the start of the sequence.
656 IGC_ASSERT(GenXIntrinsic::isWrRegion(Wr));
657 StartWr = Wr;
658 auto RdVal = Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
659 auto Rd = dyn_cast<Instruction>(RdVal);
660 bool ConstSequence = false;
661 if (!Rd) {
662 if (!isa<Constant>(RdVal))
663 return 0;
664 ConstSequence = true;
665 } else
666 Input = Rd->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
667 for (;;) {
668 Wr = dyn_cast<Instruction>(
669 Wr->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum));
670 if (!GenXIntrinsic::isWrRegion(Wr))
671 break;
672 IGC_ASSERT(Wr);
673 if (!Wr->hasOneUse())
674 break;
675 RdVal = Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
676 if (ConstSequence) {
677 if (!isa<Constant>(RdVal))
678 break;
679 } else {
680 Rd = dyn_cast<Instruction>(
681 Wr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum));
682 if (!Rd)
683 break;
684 if (Input != Rd->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum))
685 break;
686 }
687 StartWr = Wr;
688 }
689 // Try detecting a split rdregion-wrregion starting at StartWr.
690 for (;;) {
691 if (!buildFromStartWr(StartWr, Baling)) {
692 EndWr = nullptr;
693 return false;
694 }
695 if (!WaitingFor)
696 return true; // success
697 // The detected sequence did not include the wrregion this function
698 // started with. Retry with the following sequence.
699 StartWr = cast<Instruction>(EndWr->use_begin()->getUser());
700 if (GenXIntrinsic::isWrRegion(StartWr))
701 return false;
702 }
703 }
704
705 /***********************************************************************
706 * RdWrRegionSequence::buildFromRd: detect a split (legalized) rdregion-wrregion
707 * sequence starting from any rdregion within it, and populate the
708 * RdWrRegionSequence object with its details
709 *
710 * This fails if there is any predication. It succeeds with a sequence length
711 * of one (i.e. a single rdregion-wrregion pair).
712 */
buildFromRd(Instruction * Rd,GenXBaling * Baling)713 bool RdWrRegionSequence::buildFromRd(Instruction *Rd, GenXBaling *Baling)
714 {
715 IGC_ASSERT(GenXIntrinsic::isRdRegion(Rd));
716 if (!Rd->hasOneUse())
717 return false;
718 if (Rd->use_begin()->getOperandNo() != GenXIntrinsic::GenXRegion::NewValueOperandNum)
719 return false;
720 auto Wr = cast<Instruction>(Rd->use_begin()->getUser());
721 if (!GenXIntrinsic::isWrRegion(Wr))
722 return false;
723 return buildFromWr(Wr, Baling);
724 }
725
726 /***********************************************************************
727 * RdWrRegionSequence::size : get number of rdregion-wrregion pairs in the
728 * sequence
729 */
size() const730 unsigned RdWrRegionSequence::size() const
731 {
732 unsigned Size = 1;
733 Instruction *Wr = EndWr;
734 for ( ; Wr != StartWr; ++Size)
735 Wr = cast<Instruction>(
736 Wr->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum));
737 return Size;
738 }
739
740 /***********************************************************************
741 * RdWrRegionSequence::isOnlyUseOfInput : check whether the sequence is the
742 * only use of its input
743 */
isOnlyUseOfInput() const744 bool RdWrRegionSequence::isOnlyUseOfInput() const
745 {
746 unsigned Count = 0;
747 for (auto ui = Input->use_begin(), ue = Input->use_end();
748 ui != ue; ++ui)
749 ++Count;
750 return Count == size();
751 }
752
753 /***********************************************************************
754 * RdWrRegionSequence::getRdIndex : get the index of the legalized rdregion
755 */
getRdIndex() const756 Value *RdWrRegionSequence::getRdIndex() const
757 {
758 if (isa<Constant>(Input))
759 return ConstantInt::get(Type::getInt16Ty(StartWr->getContext()), 0);
760 auto Rd = cast<Instruction>(
761 StartWr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum));
762 IGC_ASSERT(GenXIntrinsic::isRdRegion(Rd));
763 return Rd->getOperand(GenXIntrinsic::GenXRegion::RdIndexOperandNum);
764 }
765
766 /***********************************************************************
767 * RdWrRegionSequence::getWrIndex : get the index of the legalized wrregion
768 */
getWrIndex() const769 Value *RdWrRegionSequence::getWrIndex() const
770 {
771 return StartWr->getOperand(GenXIntrinsic::GenXRegion::WrIndexOperandNum);
772 }
773
774 /***********************************************************************
775 * RdWrRegionSequence::getInputUse : get some use of Input in the sequence
776 *
777 * This only works if the RdWrRegionSequence is a sequence of rd-wr pairs,
778 * rather than a sequence of wrregions with constant input. In the latter
779 * case, this returns 0.
780 */
getInputUse() const781 Use *RdWrRegionSequence::getInputUse() const
782 {
783 auto Rd = dyn_cast<Instruction>(
784 StartWr->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum));
785 if (!GenXIntrinsic::isRdRegion(Rd))
786 return nullptr;
787 const unsigned OpIdx = GenXIntrinsic::GenXRegion::OldValueOperandNum;
788 IGC_ASSERT(Rd);
789 IGC_ASSERT(Rd->getOperand(OpIdx) == Input);
790 return &Rd->getOperandUse(OpIdx);
791 }
792
793 /***********************************************************************
794 * RdWrRegionSequence::print : debug dump/print
795 */
print(raw_ostream & OS) const796 void RdWrRegionSequence::print(raw_ostream &OS) const
797 {
798 if (isNull())
799 OS << "null";
800 else {
801 OS << "sequence";
802 if (OldVal)
803 dbgs() << " OldVal=" << OldVal->getName();
804 dbgs() << " Input=" << Input->getName()
805 << " StartWr=" << StartWr->getName()
806 << " EndWr=" << EndWr->getName()
807 << " RdR=" << RdR
808 << " WrR=" << WrR;
809 }
810 }
811
simplifyConstIndirectRegion(Instruction * Inst)812 static Instruction* simplifyConstIndirectRegion(Instruction* Inst) {
813 // if a region has a constant-vector as its indirect offsets,
814 // try to recognize the pattern, and replace it with
815 // a direct region with v-stride, h-stride, h-width
816 Region R = makeRegionFromBaleInfo(Inst, BaleInfo());
817 if (R.Indirect == nullptr)
818 return Inst;
819
820 auto cv = dyn_cast<ConstantDataVector>(R.Indirect);
821 if (!cv)
822 return Inst;
823 // Flatten the vector out into the elements array
824 llvm::SmallVector<llvm::Constant*, 16> elements;
825 auto vectorLength =
826 cast<IGCLLVM::FixedVectorType>(cv->getType())->getNumElements();
827 for (unsigned i = 0; i < vectorLength; ++i)
828 elements.push_back(cv->getElementAsConstant(i));
829
830 llvm::ConstantInt* ci = llvm::dyn_cast<llvm::ConstantInt>(elements[0]);
831 if (ci == NULL)
832 return Inst; // Not a vector of integers
833
834 int VStride = 1;
835 unsigned Width = 1;
836 int Stride = 1;
837 int Offset = (-1);
838
839 int64_t val0 = ci->getSExtValue();
840 if (vectorLength == 1) {
841 R.Indirect = nullptr;
842 R.Offset = val0 + R.Offset;
843 R.Stride = 0;
844 R.Width = 1;
845 R.VStride = 0;
846 if (GenXIntrinsic::isRdRegion(Inst))
847 return R.createRdRegion(Inst->getOperand(0),
848 Inst->getName(), Inst, Inst->getDebugLoc());
849 else if (GenXIntrinsic::isWrRegion(Inst))
850 return R.createWrRegion(Inst->getOperand(0), Inst->getOperand(1),
851 Inst->getName(), Inst, Inst->getDebugLoc());
852 return Inst;
853 }
854 ci = llvm::dyn_cast<llvm::ConstantInt>(elements[1]);
855 if (ci == NULL)
856 return Inst; // Not a vector of integers
857
858 int64_t prevVal = ci->getSExtValue();
859 int64_t diff = prevVal - val0;
860 if (diff < 0)
861 return Inst; // cannot have negative stride
862 int i0 = 0;
863 Offset = val0 + R.Offset;
864 // check if this is a 1d simple-stride region
865 for (int i = 2; i < (int)vectorLength; ++i) {
866 ci = llvm::dyn_cast<llvm::ConstantInt>(elements[i]);
867 if (ci == NULL)
868 return Inst;
869
870 int64_t nextVal = ci->getSExtValue();
871 if (prevVal + diff != nextVal) {
872 if (Width == 1) {
873 Width = i - i0;
874 VStride = nextVal - val0;
875 val0 = nextVal;
876 i0 = i;
877 }
878 else if (nextVal != val0 + VStride || i != i0 + Width)
879 return Inst;
880 else {
881 val0 = nextVal;
882 i0 = i;
883 }
884 if (VStride < 0)
885 return Inst; // cannot have negative stride
886 }
887 prevVal = nextVal;
888 }
889 Stride = diff*8 / R.ElementTy->getPrimitiveSizeInBits();
890 VStride = VStride*8 / R.ElementTy->getPrimitiveSizeInBits();
891 // rewrite the region inst
892 R.Indirect = nullptr;
893 R.Offset = Offset;
894 R.Stride = Stride;
895 R.Width = (Width == 1) ? R.NumElements : Width;
896 R.VStride = VStride;
897 if (GenXIntrinsic::isRdRegion(Inst))
898 return R.createRdRegion(Inst->getOperand(0),
899 Inst->getName(), Inst, Inst->getDebugLoc());
900 else if (GenXIntrinsic::isWrRegion(Inst))
901 return R.createWrRegion(Inst->getOperand(0), Inst->getOperand(1),
902 Inst->getName(), Inst, Inst->getDebugLoc());
903 return Inst;
904 }
905
simplifyRegionWrite(Instruction * Inst)906 static Value *simplifyRegionWrite(Instruction *Inst) {
907 IGC_ASSERT(GenXIntrinsic::isWrRegion(Inst));
908 Value *NewVal = Inst->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
909
910 // Replace C with A
911 // C = wrregion(A, undef, R)
912 if (isa<UndefValue>(NewVal))
913 return Inst->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
914
915 // When A and undef have the same type, replace C with A
916 // B = rdregion(A, R)
917 // C = wrregion(undef, B, R)
918 //
919 // or replace C by A
920 //
921 // B = rdregion(A, R)
922 // C = wrregion(A, B, R)
923 //
924 if (GenXIntrinsic::isRdRegion(NewVal)) {
925 Instruction *B = cast<Instruction>(NewVal);
926 Region InnerR = makeRegionFromBaleInfo(B, BaleInfo());
927 Region OuterR = makeRegionFromBaleInfo(Inst, BaleInfo());
928 if (OuterR != InnerR)
929 return nullptr;
930
931 auto OldValB = B->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
932 if (GenXIntrinsic::isReadPredefReg(OldValB))
933 return nullptr;
934 auto OldValC = Inst->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
935 if ((isa<UndefValue>(OldValC) &&
936 OldValB->getType() == OldValC->getType()) ||
937 OldValB == OldValC)
938 return OldValB;
939 }
940
941 return nullptr;
942 }
943
simplifyRegionRead(Instruction * Inst)944 static Value *simplifyRegionRead(Instruction *Inst) {
945 IGC_ASSERT(GenXIntrinsic::isRdRegion(Inst));
946 Value *Input = Inst->getOperand(GenXIntrinsic::GenXRegion::OldValueOperandNum);
947 if (isa<UndefValue>(Input))
948 return UndefValue::get(Inst->getType());
949 else if (auto C = dyn_cast<Constant>(Input)) {
950 if (auto Splat = C->getSplatValue()) {
951 if (auto *Ty = dyn_cast<IGCLLVM::FixedVectorType>(Inst->getType()))
952 Splat = ConstantVector::getSplat(
953 IGCLLVM::getElementCount(Ty->getNumElements()), Splat);
954 return Splat;
955 }
956 } else if (GenXIntrinsic::isWrRegion(Input) && Input->hasOneUse()) {
957 // W = wrr(A, B, R)
958 // C = rdr(W, R)
959 // =>
960 // replace C by B
961 Instruction *WI = cast<Instruction>(Input);
962 Region R1 = makeRegionFromBaleInfo(WI, BaleInfo());
963 Region R2 = makeRegionFromBaleInfo(Inst, BaleInfo());
964 if (R1 == R2) {
965 Value *B = WI->getOperand(GenXIntrinsic::GenXRegion::NewValueOperandNum);
966 if (B->getType() == Inst->getType())
967 return B;
968 }
969 }
970 return nullptr;
971 }
972
973 // Simplify a region read or write.
simplifyRegionInst(Instruction * Inst,const DataLayout * DL)974 Value *llvm::genx::simplifyRegionInst(Instruction *Inst, const DataLayout *DL) {
975 if (Inst->use_empty())
976 return nullptr;
977
978 unsigned ID = GenXIntrinsic::getGenXIntrinsicID(Inst);
979 switch (ID) {
980 case GenXIntrinsic::genx_wrregionf:
981 case GenXIntrinsic::genx_wrregioni:
982 case GenXIntrinsic::genx_rdregionf:
983 case GenXIntrinsic::genx_rdregioni: {
984 auto replace = simplifyConstIndirectRegion(Inst);
985 if (replace != Inst) {
986 Inst->replaceAllUsesWith(replace);
987 Inst = replace;
988 }
989 break;
990 }
991 default:
992 break;
993 }
994 if (Constant *C = ConstantFoldGenX(Inst, *DL))
995 return C;
996
997 ID = GenXIntrinsic::getGenXIntrinsicID(Inst);
998 switch (ID) {
999 case GenXIntrinsic::genx_wrregionf:
1000 case GenXIntrinsic::genx_wrregioni:
1001 return simplifyRegionWrite(Inst);
1002 case GenXIntrinsic::genx_rdregionf:
1003 case GenXIntrinsic::genx_rdregioni:
1004 return simplifyRegionRead(Inst);
1005 default:
1006 break;
1007 }
1008 return nullptr;
1009 }
1010
simplifyRegionInsts(Function * F,const DataLayout * DL)1011 bool llvm::genx::simplifyRegionInsts(Function *F, const DataLayout *DL) {
1012 bool Changed = false;
1013 for (auto &BB : F->getBasicBlockList()) {
1014 for (auto I = BB.begin(); I != BB.end();) {
1015 Instruction *Inst = &*I++;
1016 if (auto V = simplifyRegionInst(Inst, DL)) {
1017 Inst->replaceAllUsesWith(V);
1018 Inst->eraseFromParent();
1019 Changed = true;
1020 }
1021 }
1022 }
1023 return Changed;
1024 }
1025
1026 // Cleanup loads.
1027 // %load1 = load *m
1028 // %load2 = load *m
1029 // no store to m
1030 // use(load1, load2)
1031 //
cleanupLoads(Function * F)1032 bool llvm::genx::cleanupLoads(Function *F) {
1033 bool Changed = false;
1034 for (auto &BB : F->getBasicBlockList()) {
1035 // The dominating loads (may have different types) for each variable.
1036 std::unordered_map<GlobalVariable *, std::vector<LoadInst *>> DomLoads;
1037 for (auto I = BB.begin(); I != BB.end();) {
1038 Instruction *Inst = &*I++;
1039 if (auto SI = dyn_cast<StoreInst>(Inst)) {
1040 auto GV = getUnderlyingGlobalVariable(SI->getPointerOperand());
1041 if (!GV)
1042 continue;
1043 // Kill all live loads on this variable.
1044 DomLoads[GV].clear();
1045 } else if (auto LI = dyn_cast<LoadInst>(Inst)) {
1046 auto GV = getUnderlyingGlobalVariable(LI->getPointerOperand());
1047 if (!GV)
1048 continue;
1049 auto &Loads = DomLoads[GV];
1050 LoadInst *DomLI = nullptr;
1051 for (auto LI1 : Loads) {
1052 if (LI1->getType() == LI->getType()) {
1053 DomLI = LI1;
1054 break;
1055 }
1056 }
1057 if (DomLI == nullptr)
1058 Loads.push_back(LI);
1059 else {
1060 LI->replaceAllUsesWith(DomLI);
1061 LI->eraseFromParent();
1062 Changed = true;
1063 }
1064 }
1065 }
1066 }
1067 return Changed;
1068 }
1069
1070 bool
IsLinearVectorConstantInts(Value * v,int64_t & start,int64_t & stride)1071 llvm::genx::IsLinearVectorConstantInts(Value* v, int64_t& start, int64_t& stride) {
1072 auto cv = dyn_cast<ConstantDataVector>(v);
1073 if (!cv)
1074 return false;
1075 // Flatten the vector out into the elements array
1076 llvm::SmallVector<llvm::Constant*, 16> elements;
1077 auto vectorLength =
1078 cast<IGCLLVM::FixedVectorType>(cv->getType())->getNumElements();
1079 for (unsigned i = 0; i < vectorLength; ++i)
1080 elements.push_back(cv->getElementAsConstant(i));
1081
1082 llvm::ConstantInt* ci = llvm::dyn_cast<llvm::ConstantInt>(elements[0]);
1083 if (ci == NULL)
1084 return false; // Not a vector of integers
1085
1086 int64_t val0 = ci->getSExtValue();
1087 if (vectorLength == 1) {
1088 start = val0;
1089 stride = 0;
1090 return true;
1091 }
1092 ci = llvm::dyn_cast<llvm::ConstantInt>(elements[1]);
1093 if (ci == NULL)
1094 return false; // Not a vector of integers
1095 int64_t prevVal = ci->getSExtValue();
1096 int64_t diff = prevVal - val0;
1097
1098 // For each element in the array, see if it is both a ConstantInt and
1099 // if the difference between it and the value of the previous element
1100 // is stride. If not, fail.
1101 for (int i = 2; i < (int)vectorLength; ++i) {
1102 ci = llvm::dyn_cast<llvm::ConstantInt>(elements[i]);
1103 if (ci == NULL)
1104 return false;
1105
1106 int64_t nextVal = ci->getSExtValue();
1107 if (prevVal + diff != nextVal)
1108 return false;
1109
1110 prevVal = nextVal;
1111 }
1112 start = val0;
1113 stride = diff;
1114 return true;
1115 }
1116