LLVM 24.0.0git
AArch64TargetTransformInfo.cpp
Go to the documentation of this file.
1//===-- AArch64TargetTransformInfo.cpp - AArch64 specific TTI -------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "AArch64ExpandImm.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/bit.h"
23#include "llvm/IR/Intrinsics.h"
24#include "llvm/IR/IntrinsicsAArch64.h"
26#include "llvm/Support/Debug.h"
31#include <algorithm>
32#include <optional>
33using namespace llvm;
34using namespace llvm::PatternMatch;
35
36#define DEBUG_TYPE "aarch64tti"
37
38static cl::opt<bool> EnableFalkorHWPFUnrollFix("enable-falkor-hwpf-unroll-fix",
39 cl::init(true), cl::Hidden);
40
42 "sve-prefer-fixed-over-scalable-if-equal", cl::Hidden);
43
44static cl::opt<unsigned> SVEGatherOverhead("sve-gather-overhead", cl::init(10),
46
47static cl::opt<unsigned> SVEScatterOverhead("sve-scatter-overhead",
48 cl::init(10), cl::Hidden);
49
50static cl::opt<unsigned> SVETailFoldInsnThreshold("sve-tail-folding-insn-threshold",
51 cl::init(15), cl::Hidden);
52
54 NeonNonConstStrideOverhead("neon-nonconst-stride-overhead", cl::init(10),
56
58 "call-penalty-sm-change", cl::init(5), cl::Hidden,
60 "Penalty of calling a function that requires a change to PSTATE.SM"));
61
63 "inline-call-penalty-sm-change", cl::init(10), cl::Hidden,
64 cl::desc("Penalty of inlining a call that requires a change to PSTATE.SM"));
65
66static cl::opt<bool> EnableOrLikeSelectOpt("enable-aarch64-or-like-select",
67 cl::init(true), cl::Hidden);
68
69static cl::opt<bool> EnableLSRCostOpt("enable-aarch64-lsr-cost-opt",
70 cl::init(true), cl::Hidden);
71
72// A complete guess as to a reasonable cost.
74 BaseHistCntCost("aarch64-base-histcnt-cost", cl::init(8), cl::Hidden,
75 cl::desc("The cost of a histcnt instruction"));
76
78 "dmb-lookahead-threshold", cl::init(10), cl::Hidden,
79 cl::desc("The number of instructions to search for a redundant dmb"));
80
82 "aarch64-force-unroll-threshold", cl::init(0), cl::Hidden,
83 cl::desc("Threshold for forced unrolling of small loops in AArch64"));
84
85namespace {
86class TailFoldingOption {
87 // These bitfields will only ever be set to something non-zero in operator=,
88 // when setting the -sve-tail-folding option. This option should always be of
89 // the form (default|simple|all|disable)[+(Flag1|Flag2|etc)], where here
90 // InitialBits is one of (disabled|all|simple). EnableBits represents
91 // additional flags we're enabling, and DisableBits for those flags we're
92 // disabling. The default flag is tracked in the variable NeedsDefault, since
93 // at the time of setting the option we may not know what the default value
94 // for the CPU is.
98
99 // This value needs to be initialised to true in case the user does not
100 // explicitly set the -sve-tail-folding option.
101 bool NeedsDefault = true;
102
103 void setInitialBits(TailFoldingOpts Bits) { InitialBits = Bits; }
104
105 void setNeedsDefault(bool V) { NeedsDefault = V; }
106
107 void setEnableBit(TailFoldingOpts Bit) {
108 EnableBits |= Bit;
109 DisableBits &= ~Bit;
110 }
111
112 void setDisableBit(TailFoldingOpts Bit) {
113 EnableBits &= ~Bit;
114 DisableBits |= Bit;
115 }
116
117 TailFoldingOpts getBits(TailFoldingOpts DefaultBits) const {
118 TailFoldingOpts Bits = TailFoldingOpts::Disabled;
119
120 assert((InitialBits == TailFoldingOpts::Disabled || !NeedsDefault) &&
121 "Initial bits should only include one of "
122 "(disabled|all|simple|default)");
123 Bits = NeedsDefault ? DefaultBits : InitialBits;
124 Bits |= EnableBits;
125 Bits &= ~DisableBits;
126
127 return Bits;
128 }
129
130 void reportError(std::string Opt) {
131 errs() << "invalid argument '" << Opt
132 << "' to -sve-tail-folding=; the option should be of the form\n"
133 " (disabled|all|default|simple)[+(reductions|recurrences"
134 "|reverse|noreductions|norecurrences|noreverse)]\n";
135 report_fatal_error("Unrecognised tail-folding option");
136 }
137
138public:
139
140 void operator=(const std::string &Val) {
141 // If the user explicitly sets -sve-tail-folding= then treat as an error.
142 if (Val.empty()) {
143 reportError("");
144 return;
145 }
146
147 // Since the user is explicitly setting the option we don't automatically
148 // need the default unless they require it.
149 setNeedsDefault(false);
150
151 SmallVector<StringRef, 4> TailFoldTypes;
152 StringRef(Val).split(TailFoldTypes, '+', -1, false);
153
154 unsigned StartIdx = 1;
155 if (TailFoldTypes[0] == "disabled")
156 setInitialBits(TailFoldingOpts::Disabled);
157 else if (TailFoldTypes[0] == "all")
158 setInitialBits(TailFoldingOpts::All);
159 else if (TailFoldTypes[0] == "default")
160 setNeedsDefault(true);
161 else if (TailFoldTypes[0] == "simple")
162 setInitialBits(TailFoldingOpts::Simple);
163 else {
164 StartIdx = 0;
165 setInitialBits(TailFoldingOpts::Disabled);
166 }
167
168 for (unsigned I = StartIdx; I < TailFoldTypes.size(); I++) {
169 if (TailFoldTypes[I] == "reductions")
170 setEnableBit(TailFoldingOpts::Reductions);
171 else if (TailFoldTypes[I] == "recurrences")
172 setEnableBit(TailFoldingOpts::Recurrences);
173 else if (TailFoldTypes[I] == "reverse")
174 setEnableBit(TailFoldingOpts::Reverse);
175 else if (TailFoldTypes[I] == "noreductions")
176 setDisableBit(TailFoldingOpts::Reductions);
177 else if (TailFoldTypes[I] == "norecurrences")
178 setDisableBit(TailFoldingOpts::Recurrences);
179 else if (TailFoldTypes[I] == "noreverse")
180 setDisableBit(TailFoldingOpts::Reverse);
181 else
182 reportError(Val);
183 }
184 }
185
186 bool satisfies(TailFoldingOpts DefaultBits, TailFoldingOpts Required) const {
187 return (getBits(DefaultBits) & Required) == Required;
188 }
189};
190} // namespace
191
192TailFoldingOption TailFoldingOptionLoc;
193
195 "sve-tail-folding",
196 cl::desc(
197 "Control the use of vectorisation using tail-folding for SVE where the"
198 " option is specified in the form (Initial)[+(Flag1|Flag2|...)]:"
199 "\ndisabled (Initial) No loop types will vectorize using "
200 "tail-folding"
201 "\ndefault (Initial) Uses the default tail-folding settings for "
202 "the target CPU"
203 "\nall (Initial) All legal loop types will vectorize using "
204 "tail-folding"
205 "\nsimple (Initial) Use tail-folding for simple loops (not "
206 "reductions or recurrences)"
207 "\nreductions Use tail-folding for loops containing reductions"
208 "\nnoreductions Inverse of above"
209 "\nrecurrences Use tail-folding for loops containing fixed order "
210 "recurrences"
211 "\nnorecurrences Inverse of above"
212 "\nreverse Use tail-folding for loops requiring reversed "
213 "predicates"
214 "\nnoreverse Inverse of above"),
216
217// Experimental option that will only be fully functional when the
218// code-generator is changed to use SVE instead of NEON for all fixed-width
219// operations.
221 "enable-fixedwidth-autovec-in-streaming-mode", cl::init(false), cl::Hidden);
222
223// Experimental option that will only be fully functional when the cost-model
224// and code-generator have been changed to avoid using scalable vector
225// instructions that are not legal in streaming SVE mode.
227 "enable-scalable-autovec-in-streaming-mode", cl::init(false), cl::Hidden);
228
229static bool isSMEABIRoutineCall(const CallInst &CI,
230 const AArch64TargetLowering &TLI) {
231 const auto *F = CI.getCalledFunction();
232 return F &&
234}
235
236/// Returns true if the function has explicit operations that can only be
237/// lowered using incompatible instructions for the selected mode. This also
238/// returns true if the function F may use or modify ZA state.
240 const AArch64TargetLowering &TLI) {
241 for (const BasicBlock &BB : *F) {
242 for (const Instruction &I : BB) {
243 // Be conservative for now and assume that any call to inline asm or to
244 // intrinsics could could result in non-streaming ops (e.g. calls to
245 // @llvm.aarch64.* or @llvm.gather/scatter intrinsics). We can assume that
246 // all native LLVM instructions can be lowered to compatible instructions.
247 if (isa<CallInst>(I) && !I.isDebugOrPseudoInst() &&
248 (cast<CallInst>(I).isInlineAsm() || isa<IntrinsicInst>(I) ||
250 return true;
251 }
252 }
253 return false;
254}
255
257 SmallVectorImpl<StringRef> &Features) {
258 StringRef AttributeStr =
259 TTI->isMultiversionedFunction(F) ? "fmv-features" : "target-features";
260 StringRef FeatureStr = F.getFnAttribute(AttributeStr).getValueAsString();
261 FeatureStr.split(Features, ",");
262}
263
266 extractAttrFeatures(F, this, Features);
267 return AArch64::getCpuSupportsMask(Features);
268}
269
272 extractAttrFeatures(F, this, Features);
273 return AArch64::getFMVPriority(Features);
274}
275
277 return F.hasFnAttribute("fmv-features");
278}
279
281 const Function *Callee) const {
282 SMECallAttrs CallAttrs(*Caller, *Callee);
283
284 // Never inline a function explicitly marked as being streaming,
285 // into a non-streaming function. Assume it was marked as streaming
286 // for a reason.
287 if (CallAttrs.caller().hasNonStreamingInterfaceAndBody() &&
288 CallAttrs.callee().hasStreamingInterfaceOrBody())
289 return false;
290
291 // When inlining, we should consider the body of the function, not the
292 // interface.
293 if (CallAttrs.callee().hasStreamingBody()) {
294 CallAttrs.callee().set(SMEAttrs::SM_Compatible, false);
295 CallAttrs.callee().set(SMEAttrs::SM_Enabled, true);
296 }
297
298 if (CallAttrs.callee().isNewZA() || CallAttrs.callee().isNewZT0())
299 return false;
300
301 if (CallAttrs.requiresLazySave() || CallAttrs.requiresSMChange() ||
302 CallAttrs.requiresPreservingZT0() ||
303 CallAttrs.requiresPreservingAllZAState()) {
304 if (hasPossibleIncompatibleOps(Callee, *getTLI()))
305 return false;
306 }
307
308 return BaseT::areInlineCompatible(Caller, Callee);
309}
310
312 const Function *Callee,
313 ArrayRef<Type *> Types) const {
314 if (!BaseT::areTypesABICompatible(Caller, Callee, Types))
315 return false;
316
317 // We need to ensure that argument promotion does not attempt to promote
318 // pointers to fixed-length vector types larger than 128 bits like
319 // <8 x float> (and pointers to aggregate types which have such fixed-length
320 // vector type members) into the values of the pointees. Such vector types
321 // are used for SVE VLS but there is no ABI for SVE VLS arguments and the
322 // backend cannot lower such value arguments. The 128-bit fixed-length SVE
323 // types can be safely treated as 128-bit NEON types and they cannot be
324 // distinguished in IR.
325 if (ST->useSVEForFixedLengthVectors() && llvm::any_of(Types, [](Type *Ty) {
326 auto FVTy = dyn_cast<FixedVectorType>(Ty);
327 return FVTy &&
328 FVTy->getScalarSizeInBits() * FVTy->getNumElements() > 128;
329 }))
330 return false;
331
332 return true;
333}
334
335unsigned
337 unsigned DefaultCallPenalty) const {
338 // This function calculates a penalty for executing Call in F.
339 //
340 // There are two ways this function can be called:
341 // (1) F:
342 // call from F -> G (the call here is Call)
343 //
344 // For (1), Call.getCaller() == F, so it will always return a high cost if
345 // a streaming-mode change is required (thus promoting the need to inline the
346 // function)
347 //
348 // (2) F:
349 // call from F -> G (the call here is not Call)
350 // G:
351 // call from G -> H (the call here is Call)
352 //
353 // For (2), if after inlining the body of G into F the call to H requires a
354 // streaming-mode change, and the call to G from F would also require a
355 // streaming-mode change, then there is benefit to do the streaming-mode
356 // change only once and avoid inlining of G into F.
357
358 SMEAttrs FAttrs(*F);
359 SMECallAttrs CallAttrs(Call, &getTLI()->getRuntimeLibcallsInfo());
360
361 if (SMECallAttrs(FAttrs, CallAttrs.callee()).requiresSMChange()) {
362 if (F == Call.getCaller()) // (1)
363 return CallPenaltyChangeSM * DefaultCallPenalty;
364 if (SMECallAttrs(FAttrs, CallAttrs.caller()).requiresSMChange()) // (2)
365 return InlineCallPenaltyChangeSM * DefaultCallPenalty;
366 }
367
368 return DefaultCallPenalty;
369}
370
374
375 if (K == TargetTransformInfo::RGK_FixedWidthVector && ST->isNeonAvailable())
376 return true;
377
379 ST->isSVEorStreamingSVEAvailable() &&
380 !ST->disableMaximizeScalableBandwidth();
381}
382
383/// Calculate the cost of materializing a 64-bit value. This helper
384/// method might only calculate a fraction of a larger immediate. Therefore it
385/// is valid to return a cost of ZERO.
387 // Check if the immediate can be encoded within an instruction.
388 if (Val == 0 || AArch64_AM::isLogicalImmediate(Val, 64))
389 return 0;
390
391 if (Val < 0)
392 Val = ~Val;
393
394 // Calculate how many moves we will need to materialize this constant.
396 AArch64_IMM::expandMOVImm(Val, 64, Insn);
397 return Insn.size();
398}
399
400/// Calculate the cost of materializing the given constant.
404 assert(Ty->isIntegerTy());
405
406 unsigned BitSize = Ty->getPrimitiveSizeInBits();
407 if (BitSize == 0)
408 return ~0U;
409
410 // Sign-extend all constants to a multiple of 64-bit.
411 APInt ImmVal = Imm;
412 if (BitSize & 0x3f)
413 ImmVal = Imm.sext((BitSize + 63) & ~0x3fU);
414
415 // Split the constant into 64-bit chunks and calculate the cost for each
416 // chunk.
418 for (unsigned ShiftVal = 0; ShiftVal < BitSize; ShiftVal += 64) {
419 APInt Tmp = ImmVal.ashr(ShiftVal).sextOrTrunc(64);
420 int64_t Val = Tmp.getSExtValue();
421 Cost += getIntImmCost(Val);
422 }
423 // We need at least one instruction to materialze the constant.
424 return std::max<InstructionCost>(1, Cost);
425}
426
428 const APInt &Imm, Type *Ty,
430 Instruction *Inst) const {
431 assert(Ty->isIntegerTy());
432
433 unsigned BitSize = Ty->getPrimitiveSizeInBits();
434 // There is no cost model for constants with a bit size of 0. Return TCC_Free
435 // here, so that constant hoisting will ignore this constant.
436 if (BitSize == 0)
437 return TTI::TCC_Free;
438
439 unsigned ImmIdx = ~0U;
440 switch (Opcode) {
441 default:
442 return TTI::TCC_Free;
443 case Instruction::GetElementPtr:
444 // Always hoist the base address of a GetElementPtr.
445 if (Idx == 0)
446 return 2 * TTI::TCC_Basic;
447 return TTI::TCC_Free;
448 case Instruction::Store:
449 ImmIdx = 0;
450 break;
451 case Instruction::Add:
452 case Instruction::Sub:
453 case Instruction::Mul:
454 case Instruction::UDiv:
455 case Instruction::SDiv:
456 case Instruction::URem:
457 case Instruction::SRem:
458 case Instruction::And:
459 case Instruction::Or:
460 case Instruction::Xor:
461 case Instruction::ICmp:
462 ImmIdx = 1;
463 break;
464 // Always return TCC_Free for the shift value of a shift instruction.
465 case Instruction::Shl:
466 case Instruction::LShr:
467 case Instruction::AShr:
468 if (Idx == 1)
469 return TTI::TCC_Free;
470 break;
471 case Instruction::Trunc:
472 case Instruction::ZExt:
473 case Instruction::SExt:
474 case Instruction::IntToPtr:
475 case Instruction::PtrToInt:
476 case Instruction::BitCast:
477 case Instruction::PHI:
478 case Instruction::Call:
479 case Instruction::Select:
480 case Instruction::Ret:
481 case Instruction::Load:
482 break;
483 }
484
485 if (Idx == ImmIdx) {
486 int NumConstants = (BitSize + 63) / 64;
488 return (Cost <= NumConstants * TTI::TCC_Basic)
489 ? static_cast<int>(TTI::TCC_Free)
490 : Cost;
491 }
493}
494
497 const APInt &Imm, Type *Ty,
499 assert(Ty->isIntegerTy());
500
501 unsigned BitSize = Ty->getPrimitiveSizeInBits();
502 // There is no cost model for constants with a bit size of 0. Return TCC_Free
503 // here, so that constant hoisting will ignore this constant.
504 if (BitSize == 0)
505 return TTI::TCC_Free;
506
507 // Most (all?) AArch64 intrinsics do not support folding immediates into the
508 // selected instruction, so we compute the materialization cost for the
509 // immediate directly.
510 if (IID >= Intrinsic::aarch64_addg && IID <= Intrinsic::aarch64_udiv)
512
513 switch (IID) {
514 default:
515 return TTI::TCC_Free;
516 case Intrinsic::sadd_with_overflow:
517 case Intrinsic::uadd_with_overflow:
518 case Intrinsic::ssub_with_overflow:
519 case Intrinsic::usub_with_overflow:
520 case Intrinsic::smul_with_overflow:
521 case Intrinsic::umul_with_overflow:
522 if (Idx == 1) {
523 int NumConstants = (BitSize + 63) / 64;
525 return (Cost <= NumConstants * TTI::TCC_Basic)
526 ? static_cast<int>(TTI::TCC_Free)
527 : Cost;
528 }
529 break;
530 case Intrinsic::experimental_stackmap:
531 if ((Idx < 2) || (Imm.getBitWidth() <= 64 && isInt<64>(Imm.getSExtValue())))
532 return TTI::TCC_Free;
533 break;
534 case Intrinsic::experimental_patchpoint_void:
535 case Intrinsic::experimental_patchpoint:
536 if ((Idx < 4) || (Imm.getBitWidth() <= 64 && isInt<64>(Imm.getSExtValue())))
537 return TTI::TCC_Free;
538 break;
539 case Intrinsic::experimental_gc_statepoint:
540 if ((Idx < 5) || (Imm.getBitWidth() <= 64 && isInt<64>(Imm.getSExtValue())))
541 return TTI::TCC_Free;
542 break;
543 }
545}
546
548AArch64TTIImpl::getPopcntSupport(unsigned TyWidth) const {
549 assert(isPowerOf2_32(TyWidth) && "Ty width must be power of 2");
550 if (TyWidth == 32 || TyWidth == 64)
552 // TODO: AArch64TargetLowering::LowerCTPOP() supports 128bit popcount.
553 return TTI::PSK_Software;
554}
555
557 // MispredictPenalty is defined per-CPU in AArch64Sched*.td (e.g.,
558 // AArch64SchedNeoverseV2.td).
559 return ST->getMispredictionPenalty();
560}
561
562static bool isUnpackedVectorVT(EVT VecVT) {
563 return VecVT.isScalableVector() &&
565}
566
568 const IntrinsicCostAttributes &ICA) {
569 // We need to know at least the number of elements in the vector of buckets
570 // and the size of each element to update.
571 if (ICA.getArgTypes().size() < 2)
573
574 // Only interested in costing for the hardware instruction from SVE2.
575 if (!ST->hasSVE2())
577
578 Type *BucketPtrsTy = ICA.getArgTypes()[0]; // Type of vector of pointers
579 Type *EltTy = ICA.getArgTypes()[1]; // Type of bucket elements
580 unsigned TotalHistCnts = 1;
581
582 unsigned EltSize = EltTy->getScalarSizeInBits();
583 // Only allow (up to 64b) integers or pointers
584 if ((!EltTy->isIntegerTy() && !EltTy->isPointerTy()) || EltSize > 64)
586
587 // FIXME: We should be able to generate histcnt for fixed-length vectors
588 // using ptrue with a specific VL.
589 if (VectorType *VTy = dyn_cast<VectorType>(BucketPtrsTy)) {
590 unsigned EC = VTy->getElementCount().getKnownMinValue();
591 if (!isPowerOf2_64(EC) || !VTy->isScalableTy() || EC == 1)
593
594 // HistCnt only supports 32b and 64b element types
595 unsigned LegalEltSize = EltSize <= 32 ? 32 : 64;
596
597 if (EC == 2 || (LegalEltSize == 32 && EC == 4))
599
600 unsigned NaturalVectorWidth = AArch64::SVEBitsPerBlock / LegalEltSize;
601 TotalHistCnts = EC / NaturalVectorWidth;
602
603 return InstructionCost(BaseHistCntCost * TotalHistCnts);
604 }
605
607}
608
612 // The code-generator is currently not able to handle scalable vectors
613 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
614 // it. This change will be removed when code-generation for these types is
615 // sufficiently reliable.
616 auto *RetTy = ICA.getReturnType();
617 if (auto *VTy = dyn_cast<ScalableVectorType>(RetTy))
618 if (VTy->getElementCount() == ElementCount::getScalable(1))
620
621 switch (ICA.getID()) {
622 case Intrinsic::experimental_vector_histogram_add: {
623 InstructionCost HistCost = getHistogramCost(ST, ICA);
624 // If the cost isn't valid, we may still be able to scalarize
625 if (HistCost.isValid())
626 return HistCost;
627 break;
628 }
629 case Intrinsic::clmul: {
630 auto LT = getTypeLegalizationCost(RetTy);
631
632 // PMUL v8i8/v16i8 is always available on AArch64
633 if (ST->hasNEON()) {
634 if (LT.second == MVT::v8i8 || LT.second == MVT::v16i8)
635 return LT.first;
636
637 // Scalar i8 lowers through scalar/vector moves around PMUL.
638 if (TLI->getValueType(DL, RetTy, true) == MVT::i8) {
639 auto *VecTy =
640 FixedVectorType::get(Type::getInt8Ty(RetTy->getContext()), 8);
641 return 1 +
642 getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,
643 -1, nullptr, nullptr) *
644 2 +
645 getVectorInstrCost(Instruction::InsertElement, VecTy, CostKind,
646 -1, nullptr, nullptr);
647 }
648 }
649
650 if (LT.second.SimpleTy == MVT::nxv2i64)
651 if (ST->hasSVEAES() && (ST->isSVEAvailable() || ST->hasSSVE_AES()))
652 return LT.first * 3;
653
654 if (ST->hasSVE2() || ST->hasSME()) {
655 switch (LT.second.SimpleTy) {
656 case MVT::nxv16i8:
657 return LT.first;
658 case MVT::nxv8i16:
659 return LT.first * 6;
660 case MVT::nxv4i32:
661 return LT.first * 3;
662 case MVT::nxv2i64:
663 return LT.first * 8;
664 default:
665 break;
666 }
667 }
668
669 // Avoid +sve giving this cost 2 due to custom lowering: It's very slow
670 if (LT.second.SimpleTy == MVT::nxv2i64)
671 return 192;
672
673 if (ST->hasAES()) {
674 switch (LT.second.SimpleTy) {
675 case MVT::i16:
676 case MVT::i32:
677 case MVT::i64:
678 case MVT::i128: {
679 auto *VecTy =
680 FixedVectorType::get(Type::getInt64Ty(RetTy->getContext()), 1);
681 return LT.first *
682 (1 +
683 getVectorInstrCost(Instruction::ExtractElement, VecTy, CostKind,
684 -1, nullptr, nullptr) *
685 2 +
686 getVectorInstrCost(Instruction::InsertElement, VecTy, CostKind,
687 -1, nullptr, nullptr));
688 }
689 case MVT::v1i64:
690 return LT.first;
691 case MVT::v2i64:
692 return LT.first * 3;
693 case MVT::v2i32:
694 return LT.first * 6;
695 case MVT::v4i32:
696 return LT.first * 11;
697 case MVT::v4i16:
698 return LT.first * 14;
699 default:
700 break;
701 }
702 }
703 break;
704 }
705 case Intrinsic::umin:
706 case Intrinsic::umax:
707 case Intrinsic::smin:
708 case Intrinsic::smax: {
709 static const auto ValidMinMaxTys = {MVT::v8i8, MVT::v16i8, MVT::v4i16,
710 MVT::v8i16, MVT::v2i32, MVT::v4i32,
711 MVT::nxv16i8, MVT::nxv8i16, MVT::nxv4i32,
712 MVT::nxv2i64};
713 auto LT = getTypeLegalizationCost(RetTy);
714 // Type promotion for v2i8 and v2i16 types have a heavy cost when
715 // vectorising. Account for this cost to avoid vectorising unprofitable
716 // examples when vectorising loops with low trip counts.
717 bool IsSigned =
718 ICA.getID() == Intrinsic::smin || ICA.getID() == Intrinsic::smax;
719 EVT VT = TLI->getValueType(DL, RetTy, /*AllowUnknown=*/true);
720 if (VT == MVT::v2i8 || VT == MVT::v2i16 || VT == MVT::v4i8)
721 return LT.first * (IsSigned ? 5 : 3);
722 // v2i64 types get converted to cmp+bif hence the cost of 2
723 if (LT.second == MVT::v2i64)
724 return LT.first * 2;
725 if (any_of(ValidMinMaxTys, equal_to(LT.second)))
726 return LT.first;
727 break;
728 }
729 case Intrinsic::scmp:
730 case Intrinsic::ucmp: {
731 static const CostTblEntry BitreverseTbl[] = {
732 {Intrinsic::scmp, MVT::i32, 3}, // cmp+cset+csinv
733 {Intrinsic::scmp, MVT::i64, 3}, // cmp+cset+csinv
734 {Intrinsic::scmp, MVT::v8i8, 3}, // cmgt+cmgt+sub
735 {Intrinsic::scmp, MVT::v16i8, 3}, // cmgt+cmgt+sub
736 {Intrinsic::scmp, MVT::v4i16, 3}, // cmgt+cmgt+sub
737 {Intrinsic::scmp, MVT::v8i16, 3}, // cmgt+cmgt+sub
738 {Intrinsic::scmp, MVT::v2i32, 3}, // cmgt+cmgt+sub
739 {Intrinsic::scmp, MVT::v4i32, 3}, // cmgt+cmgt+sub
740 {Intrinsic::scmp, MVT::v1i64, 3}, // cmgt+cmgt+sub
741 {Intrinsic::scmp, MVT::v2i64, 3}, // cmgt+cmgt+sub
742 };
743 const auto LT = getTypeLegalizationCost(RetTy);
744 const auto *Entry =
745 CostTableLookup(BitreverseTbl, Intrinsic::scmp, LT.second);
746 if (Entry)
747 return Entry->Cost * LT.first;
748 break;
749 }
750 case Intrinsic::sadd_sat:
751 case Intrinsic::ssub_sat:
752 case Intrinsic::uadd_sat:
753 case Intrinsic::usub_sat: {
754 static const auto ValidSatTys = {MVT::v8i8, MVT::v16i8, MVT::v4i16,
755 MVT::v8i16, MVT::v2i32, MVT::v4i32,
756 MVT::v2i64};
757 auto LT = getTypeLegalizationCost(RetTy);
758 // This is a base cost of 1 for the vadd, plus 3 extract shifts if we
759 // need to extend the type, as it uses shr(qadd(shl, shl)).
760 unsigned Instrs =
761 LT.second.getScalarSizeInBits() == RetTy->getScalarSizeInBits() ? 1 : 4;
762 if (any_of(ValidSatTys, equal_to(LT.second)))
763 return LT.first * Instrs;
764
766 uint64_t VectorSize = TS.getKnownMinValue();
767
768 if (ST->isSVEAvailable() && VectorSize >= 128 && isPowerOf2_64(VectorSize))
769 return LT.first * Instrs;
770
771 break;
772 }
773 case Intrinsic::abs: {
774 static const auto ValidAbsTys = {MVT::v8i8, MVT::v16i8, MVT::v4i16,
775 MVT::v8i16, MVT::v2i32, MVT::v4i32,
776 MVT::v2i64, MVT::nxv16i8, MVT::nxv8i16,
777 MVT::nxv4i32, MVT::nxv2i64};
778 auto LT = getTypeLegalizationCost(RetTy);
779 if (any_of(ValidAbsTys, equal_to(LT.second)))
780 return LT.first;
781 break;
782 }
783 case Intrinsic::bswap: {
784 static const auto ValidAbsTys = {MVT::v4i16, MVT::v8i16, MVT::v2i32,
785 MVT::v4i32, MVT::v2i64};
786 auto LT = getTypeLegalizationCost(RetTy);
787 if (any_of(ValidAbsTys, equal_to(LT.second)) &&
788 LT.second.getScalarSizeInBits() == RetTy->getScalarSizeInBits())
789 return LT.first;
790 break;
791 }
792 case Intrinsic::fma:
793 case Intrinsic::fmuladd: {
794 // Given a fma or fmuladd, cost it the same as a fmul instruction which are
795 // usually the same for costs. TODO: Add fp16 and bf16 expansion costs.
796 Type *EltTy = RetTy->getScalarType();
797 if (EltTy->isFloatTy() || EltTy->isDoubleTy() ||
798 (EltTy->isHalfTy() && ST->hasFullFP16()))
799 return getArithmeticInstrCost(Instruction::FMul, RetTy, CostKind);
800 break;
801 }
802 case Intrinsic::stepvector: {
803 InstructionCost Cost = 1; // Cost of the `index' instruction
804 auto LT = getTypeLegalizationCost(RetTy);
805 // Legalisation of illegal vectors involves an `index' instruction plus
806 // (LT.first - 1) vector adds.
807 if (LT.first > 1) {
808 Type *LegalVTy = EVT(LT.second).getTypeForEVT(RetTy->getContext());
809 InstructionCost AddCost =
810 getArithmeticInstrCost(Instruction::Add, LegalVTy, CostKind);
811 Cost += AddCost * (LT.first - 1);
812 }
813 return Cost;
814 }
815 case Intrinsic::vector_extract:
816 case Intrinsic::vector_insert: {
817 // If both the vector and subvector types are legal types and the index
818 // is 0, then this should be a no-op or simple operation; return a
819 // relatively low cost.
820
821 // If arguments aren't actually supplied, then we cannot determine the
822 // value of the index. We also want to skip predicate types.
823 if (ICA.getArgs().size() != ICA.getArgTypes().size() ||
825 break;
826
827 LLVMContext &C = RetTy->getContext();
828 EVT VecVT = getTLI()->getValueType(DL, ICA.getArgTypes()[0]);
829 bool IsExtract = ICA.getID() == Intrinsic::vector_extract;
830 EVT SubVecVT = IsExtract ? getTLI()->getValueType(DL, RetTy)
831 : getTLI()->getValueType(DL, ICA.getArgTypes()[1]);
832 // Skip this if either the vector or subvector types are unpacked
833 // SVE types; they may get lowered to stack stores and loads.
834 if (isUnpackedVectorVT(VecVT) || isUnpackedVectorVT(SubVecVT))
835 break;
836
838 getTLI()->getTypeConversion(C, SubVecVT);
840 getTLI()->getTypeConversion(C, VecVT);
841 const Value *Idx = IsExtract ? ICA.getArgs()[1] : ICA.getArgs()[2];
842 const ConstantInt *CIdx = cast<ConstantInt>(Idx);
843 if (SubVecLK.first == TargetLoweringBase::TypeLegal &&
844 VecLK.first == TargetLoweringBase::TypeLegal && CIdx->isZero())
845 return TTI::TCC_Free;
846 break;
847 }
848 case Intrinsic::bitreverse: {
849 static const CostTblEntry BitreverseTbl[] = {
850 {Intrinsic::bitreverse, MVT::i32, 1},
851 {Intrinsic::bitreverse, MVT::i64, 1},
852 {Intrinsic::bitreverse, MVT::v8i8, 1},
853 {Intrinsic::bitreverse, MVT::v16i8, 1},
854 {Intrinsic::bitreverse, MVT::v4i16, 2},
855 {Intrinsic::bitreverse, MVT::v8i16, 2},
856 {Intrinsic::bitreverse, MVT::v2i32, 2},
857 {Intrinsic::bitreverse, MVT::v4i32, 2},
858 {Intrinsic::bitreverse, MVT::v1i64, 2},
859 {Intrinsic::bitreverse, MVT::v2i64, 2},
860 };
861 const auto LegalisationCost = getTypeLegalizationCost(RetTy);
862 const auto *Entry =
863 CostTableLookup(BitreverseTbl, ICA.getID(), LegalisationCost.second);
864 if (Entry) {
865 // Cost Model is using the legal type(i32) that i8 and i16 will be
866 // converted to +1 so that we match the actual lowering cost
867 if (TLI->getValueType(DL, RetTy, true) == MVT::i8 ||
868 TLI->getValueType(DL, RetTy, true) == MVT::i16)
869 return LegalisationCost.first * Entry->Cost + 1;
870
871 return LegalisationCost.first * Entry->Cost;
872 }
873 break;
874 }
875 case Intrinsic::ctpop: {
876 auto LT = getTypeLegalizationCost(RetTy);
877 MVT MTy = LT.second;
878
879 if (ST->hasCSSC() && !RetTy->isVectorTy()) {
880 int ExtraCost =
881 MTy.getScalarSizeInBits() != RetTy->getScalarSizeInBits() ? 1 : 0;
882 return LT.first + ExtraCost;
883 }
884 if (!ST->hasNEON()) {
885 // 32-bit or 64-bit ctpop without NEON is 12 instructions.
886 return getTypeLegalizationCost(RetTy).first * 12;
887 }
888 static const CostTblEntry CtpopCostTbl[] = {
889 {ISD::CTPOP, MVT::v2i64, 4},
890 {ISD::CTPOP, MVT::v4i32, 3},
891 {ISD::CTPOP, MVT::v8i16, 2},
892 {ISD::CTPOP, MVT::v16i8, 1},
893 {ISD::CTPOP, MVT::i64, 4},
894 {ISD::CTPOP, MVT::v2i32, 3},
895 {ISD::CTPOP, MVT::v4i16, 2},
896 {ISD::CTPOP, MVT::v8i8, 1},
897 {ISD::CTPOP, MVT::i32, 5},
898 // SVE types (For targets that override NEON for fixed length vectors)
899 {ISD::CTPOP, MVT::nxv2i64, 1},
900 {ISD::CTPOP, MVT::nxv4i32, 1},
901 {ISD::CTPOP, MVT::nxv8i16, 1},
902 {ISD::CTPOP, MVT::nxv16i8, 1},
903 };
904
905 // When SVE is available CNT will be used for fixed and scalable vectors.
906 if (ST->isSVEorStreamingSVEAvailable() && MTy.isFixedLengthVector())
908 128 / MTy.getScalarSizeInBits());
909
910 if (const auto *Entry = CostTableLookup(CtpopCostTbl, ISD::CTPOP, MTy)) {
911 // Extra cost of +1 when illegal vector types are legalized by promoting
912 // the integer type.
913 int ExtraCost = MTy.isVector() && MTy.getScalarSizeInBits() !=
914 RetTy->getScalarSizeInBits()
915 ? 1
916 : 0;
917 return LT.first * Entry->Cost + ExtraCost;
918 }
919 break;
920 }
921 case Intrinsic::sadd_with_overflow:
922 case Intrinsic::uadd_with_overflow:
923 case Intrinsic::ssub_with_overflow:
924 case Intrinsic::usub_with_overflow:
925 case Intrinsic::smul_with_overflow:
926 case Intrinsic::umul_with_overflow: {
927 static const CostTblEntry WithOverflowCostTbl[] = {
928 {Intrinsic::sadd_with_overflow, MVT::i8, 3},
929 {Intrinsic::uadd_with_overflow, MVT::i8, 3},
930 {Intrinsic::sadd_with_overflow, MVT::i16, 3},
931 {Intrinsic::uadd_with_overflow, MVT::i16, 3},
932 {Intrinsic::sadd_with_overflow, MVT::i32, 1},
933 {Intrinsic::uadd_with_overflow, MVT::i32, 1},
934 {Intrinsic::sadd_with_overflow, MVT::i64, 1},
935 {Intrinsic::uadd_with_overflow, MVT::i64, 1},
936 {Intrinsic::ssub_with_overflow, MVT::i8, 3},
937 {Intrinsic::usub_with_overflow, MVT::i8, 3},
938 {Intrinsic::ssub_with_overflow, MVT::i16, 3},
939 {Intrinsic::usub_with_overflow, MVT::i16, 3},
940 {Intrinsic::ssub_with_overflow, MVT::i32, 1},
941 {Intrinsic::usub_with_overflow, MVT::i32, 1},
942 {Intrinsic::ssub_with_overflow, MVT::i64, 1},
943 {Intrinsic::usub_with_overflow, MVT::i64, 1},
944 {Intrinsic::smul_with_overflow, MVT::i8, 5},
945 {Intrinsic::umul_with_overflow, MVT::i8, 4},
946 {Intrinsic::smul_with_overflow, MVT::i16, 5},
947 {Intrinsic::umul_with_overflow, MVT::i16, 4},
948 {Intrinsic::smul_with_overflow, MVT::i32, 2}, // eg umull;tst
949 {Intrinsic::umul_with_overflow, MVT::i32, 2}, // eg umull;cmp sxtw
950 {Intrinsic::smul_with_overflow, MVT::i64, 3}, // eg mul;smulh;cmp
951 {Intrinsic::umul_with_overflow, MVT::i64, 3}, // eg mul;umulh;cmp asr
952 };
953 EVT MTy = TLI->getValueType(DL, RetTy->getContainedType(0), true);
954 if (MTy.isSimple())
955 if (const auto *Entry = CostTableLookup(WithOverflowCostTbl, ICA.getID(),
956 MTy.getSimpleVT()))
957 return Entry->Cost;
958 break;
959 }
960 case Intrinsic::fptosi_sat:
961 case Intrinsic::fptoui_sat: {
962 if (ICA.getArgTypes().empty())
963 break;
964 bool IsSigned = ICA.getID() == Intrinsic::fptosi_sat;
965 auto LT = getTypeLegalizationCost(ICA.getArgTypes()[0]);
966 EVT MTy = TLI->getValueType(DL, RetTy);
967 // Check for the legal types, which are where the size of the input and the
968 // output are the same, or we are using cvt f64->i32 or f32->i64.
969 if ((LT.second == MVT::f32 || LT.second == MVT::f64 ||
970 LT.second == MVT::v2f32 || LT.second == MVT::v4f32 ||
971 LT.second == MVT::v2f64)) {
972 if ((LT.second.getScalarSizeInBits() == MTy.getScalarSizeInBits() ||
973 (LT.second == MVT::f64 && MTy == MVT::i32) ||
974 (LT.second == MVT::f32 && MTy == MVT::i64)))
975 return LT.first;
976 // Extending vector types v2f32->v2i64, fcvtl*2 + fcvt*2
977 if (LT.second.getScalarType() == MVT::f32 && MTy.isFixedLengthVector() &&
978 MTy.getScalarSizeInBits() == 64)
979 return LT.first * (MTy.getVectorNumElements() > 2 ? 4 : 2);
980 }
981 // Similarly for fp16 sizes. Without FullFP16 we generally need to fcvt to
982 // f32.
983 if (LT.second.getScalarType() == MVT::f16 && !ST->hasFullFP16())
984 return LT.first + getIntrinsicInstrCost(
985 {ICA.getID(),
986 RetTy,
987 {ICA.getArgTypes()[0]->getWithNewType(
988 Type::getFloatTy(RetTy->getContext()))}},
989 CostKind);
990 if ((LT.second == MVT::f16 && MTy == MVT::i32) ||
991 (LT.second == MVT::f16 && MTy == MVT::i64) ||
992 ((LT.second == MVT::v4f16 || LT.second == MVT::v8f16) &&
993 (LT.second.getScalarSizeInBits() == MTy.getScalarSizeInBits())))
994 return LT.first;
995 // Extending vector types v8f16->v8i32, fcvtl*2 + fcvt*2
996 if (LT.second.getScalarType() == MVT::f16 && MTy.isFixedLengthVector() &&
997 MTy.getScalarSizeInBits() == 32)
998 return LT.first * (MTy.getVectorNumElements() > 4 ? 4 : 2);
999 // Extending vector types v8f16->v8i32. These current scalarize but the
1000 // codegen could be better.
1001 if (LT.second.getScalarType() == MVT::f16 && MTy.isFixedLengthVector() &&
1002 MTy.getScalarSizeInBits() == 64)
1003 return MTy.getVectorNumElements() * 3;
1004
1005 // If we can we use a legal convert followed by a min+max
1006 if ((LT.second.getScalarType() == MVT::f32 ||
1007 LT.second.getScalarType() == MVT::f64 ||
1008 LT.second.getScalarType() == MVT::f16) &&
1009 LT.second.getScalarSizeInBits() >= MTy.getScalarSizeInBits()) {
1010 Type *LegalTy =
1011 Type::getIntNTy(RetTy->getContext(), LT.second.getScalarSizeInBits());
1012 if (LT.second.isVector())
1013 LegalTy = VectorType::get(LegalTy, LT.second.getVectorElementCount());
1015 IntrinsicCostAttributes Attrs1(IsSigned ? Intrinsic::smin
1016 : Intrinsic::umin,
1017 LegalTy, {LegalTy, LegalTy});
1019 IntrinsicCostAttributes Attrs2(IsSigned ? Intrinsic::smax
1020 : Intrinsic::umax,
1021 LegalTy, {LegalTy, LegalTy});
1023 return LT.first * Cost +
1024 ((LT.second.getScalarType() != MVT::f16 || ST->hasFullFP16()) ? 0
1025 : 1);
1026 }
1027 // Otherwise we need to follow the default expansion that clamps the value
1028 // using a float min/max with a fcmp+sel for nan handling when signed.
1029 Type *FPTy = ICA.getArgTypes()[0]->getScalarType();
1030 RetTy = RetTy->getScalarType();
1031 if (LT.second.isVector()) {
1032 FPTy = VectorType::get(FPTy, LT.second.getVectorElementCount());
1033 RetTy = VectorType::get(RetTy, LT.second.getVectorElementCount());
1034 }
1035 IntrinsicCostAttributes Attrs1(Intrinsic::minnum, FPTy, {FPTy, FPTy});
1037 IntrinsicCostAttributes Attrs2(Intrinsic::maxnum, FPTy, {FPTy, FPTy});
1039 Cost +=
1040 getCastInstrCost(IsSigned ? Instruction::FPToSI : Instruction::FPToUI,
1041 RetTy, FPTy, TTI::CastContextHint::None, CostKind);
1042 if (IsSigned) {
1043 Type *CondTy = RetTy->getWithNewBitWidth(1);
1044 Cost += getCmpSelInstrCost(BinaryOperator::FCmp, FPTy, CondTy,
1046 Cost += getCmpSelInstrCost(BinaryOperator::Select, RetTy, CondTy,
1048 }
1049 return LT.first * Cost;
1050 }
1051 case Intrinsic::fshl:
1052 case Intrinsic::fshr: {
1053 if (ICA.getArgs().empty())
1054 break;
1055
1056 const TTI::OperandValueInfo OpInfoZ = TTI::getOperandInfo(ICA.getArgs()[2]);
1057
1058 // ROTR / ROTL is a funnel shift with equal first and second operand. For
1059 // ROTR on integer registers (i32/i64) this can be done in a single ror
1060 // instruction. A fshl with a non-constant shift uses a neg + ror.
1061 if (RetTy->isIntegerTy() && ICA.getArgs()[0] == ICA.getArgs()[1] &&
1062 (RetTy->getPrimitiveSizeInBits() == 32 ||
1063 RetTy->getPrimitiveSizeInBits() == 64)) {
1064 InstructionCost NegCost =
1065 (ICA.getID() == Intrinsic::fshl && !OpInfoZ.isConstant()) ? 1 : 0;
1066 return 1 + NegCost;
1067 }
1068
1069 // TODO: Add handling for fshl where third argument is not a constant.
1070 if (!OpInfoZ.isConstant())
1071 break;
1072
1073 const auto LegalisationCost = getTypeLegalizationCost(RetTy);
1074 if (OpInfoZ.isUniform()) {
1075 static const CostTblEntry FshlTbl[] = {
1076 {Intrinsic::fshl, MVT::v4i32, 2}, // shl + usra
1077 {Intrinsic::fshl, MVT::v2i64, 2}, {Intrinsic::fshl, MVT::v16i8, 2},
1078 {Intrinsic::fshl, MVT::v8i16, 2}, {Intrinsic::fshl, MVT::v2i32, 2},
1079 {Intrinsic::fshl, MVT::v8i8, 2}, {Intrinsic::fshl, MVT::v4i16, 2}};
1080 // Costs for both fshl & fshr are the same, so just pass Intrinsic::fshl
1081 // to avoid having to duplicate the costs.
1082 const auto *Entry =
1083 CostTableLookup(FshlTbl, Intrinsic::fshl, LegalisationCost.second);
1084 if (Entry)
1085 return LegalisationCost.first * Entry->Cost;
1086 }
1087
1088 auto TyL = getTypeLegalizationCost(RetTy);
1089 if (!RetTy->isIntegerTy())
1090 break;
1091
1092 // Estimate cost manually, as types like i8 and i16 will get promoted to
1093 // i32 and CostTableLookup will ignore the extra conversion cost.
1094 bool HigherCost = (RetTy->getScalarSizeInBits() != 32 &&
1095 RetTy->getScalarSizeInBits() < 64) ||
1096 (RetTy->getScalarSizeInBits() % 64 != 0);
1097 unsigned ExtraCost = HigherCost ? 1 : 0;
1098 if (RetTy->getScalarSizeInBits() == 32 ||
1099 RetTy->getScalarSizeInBits() == 64)
1100 ExtraCost = 0; // fhsl/fshr for i32 and i64 can be lowered to a single
1101 // extr instruction.
1102 else if (HigherCost)
1103 ExtraCost = 1;
1104 else
1105 break;
1106 return TyL.first + ExtraCost;
1107 }
1108 case Intrinsic::get_active_lane_mask: {
1109 auto RetTy = cast<VectorType>(ICA.getReturnType());
1110 EVT RetVT = getTLI()->getValueType(DL, RetTy);
1111 EVT OpVT = getTLI()->getValueType(DL, ICA.getArgTypes()[0]);
1112 if (getTLI()->shouldExpandGetActiveLaneMask(RetVT, OpVT))
1113 break;
1114
1115 if (RetTy->isScalableTy()) {
1116 if (TLI->getTypeAction(RetTy->getContext(), RetVT) !=
1118 break;
1119
1120 auto LT = getTypeLegalizationCost(RetTy);
1121 InstructionCost Cost = LT.first;
1122 // When SVE2p1 or SME2 is available, we can halve getTypeLegalizationCost
1123 // as get_active_lane_mask may lower to the sve_whilelo_x2 intrinsic, e.g.
1124 // nxv32i1 = get_active_lane_mask(base, idx) ->
1125 // {nxv16i1, nxv16i1} = sve_whilelo_x2(base, idx)
1126 if (ST->hasSVE2p1() || ST->hasSME2()) {
1127 Cost /= 2;
1128 if (Cost == 1)
1129 return Cost;
1130 }
1131
1132 // If more than one whilelo intrinsic is required, include the extra cost
1133 // required by the saturating add & select required to increment the
1134 // start value after the first intrinsic call.
1135 Type *OpTy = ICA.getArgTypes()[0];
1136 IntrinsicCostAttributes AddAttrs(Intrinsic::uadd_sat, OpTy, {OpTy, OpTy});
1137 InstructionCost SplitCost = getIntrinsicInstrCost(AddAttrs, CostKind);
1138 Type *CondTy = OpTy->getWithNewBitWidth(1);
1139 SplitCost += getCmpSelInstrCost(Instruction::Select, OpTy, CondTy,
1141 return Cost + (SplitCost * (Cost - 1));
1142 } else if (!getTLI()->isTypeLegal(RetVT)) {
1143 // We don't have enough context at this point to determine if the mask
1144 // is going to be kept live after the block, which will force the vXi1
1145 // type to be expanded to legal vectors of integers, e.g. v4i1->v4i32.
1146 // For now, we just assume the vectorizer created this intrinsic and
1147 // the result will be the input for a PHI. In this case the cost will
1148 // be extremely high for fixed-width vectors.
1149 // NOTE: getScalarizationOverhead returns a cost that's far too
1150 // pessimistic for the actual generated codegen. In reality there are
1151 // two instructions generated per lane.
1152 return cast<FixedVectorType>(RetTy)->getNumElements() * 2;
1153 }
1154 break;
1155 }
1156 case Intrinsic::experimental_vector_match: {
1157 if (!ST->hasSVE2() || !ST->isSVEAvailable())
1158 break;
1159
1160 auto *NeedleTy = cast<FixedVectorType>(ICA.getArgTypes()[1]);
1161
1162 // We expand vector.matches with <= 2 elements to a chain of compares.
1163 unsigned SearchSize = NeedleTy->getNumElements();
1164 if (SearchSize <= 2)
1165 break;
1166
1167 auto [LegalParts, SearchVT] = getTypeLegalizationCost(ICA.getArgTypes()[0]);
1168 if (!is_contained(
1169 {MVT::nxv8i16, MVT::nxv16i8, MVT::v8i16, MVT::v16i8, MVT::v8i8},
1170 SearchVT.SimpleTy))
1171 break;
1172
1173 unsigned ElementSizeInBits = SearchVT.getScalarSizeInBits();
1174
1175 // Number of needle elements we can compare per `match` instruction.
1176 unsigned NeedleEltsPerMatch = AArch64::SVEBitsPerBlock / ElementSizeInBits;
1177
1178 // How many `match` instructions we need to match `SearchSize` elements.
1179 unsigned MatchesRequiredForNeedle =
1180 llvm::divideCeil(SearchSize, NeedleEltsPerMatch);
1181
1182 // Base cost for MATCH instructions. At least on the Neoverse V2 and
1183 // Neoverse V3, these are cheap operations with the same latency as a
1184 // vector ADD. In most cases, however, we also need to do an extra DUP.
1185 // For fixed-length vectors we currently need an extra five--six
1186 // instructions besides the MATCH.
1188 if (isa<FixedVectorType>(RetTy))
1189 Cost += 10;
1190
1191 return Cost * LegalParts * MatchesRequiredForNeedle;
1192 }
1193 case Intrinsic::cttz: {
1194 auto LT = getTypeLegalizationCost(ICA.getArgTypes()[0]);
1195 if (LT.second == MVT::v8i8 || LT.second == MVT::v16i8)
1196 return LT.first * 2;
1197 if (LT.second == MVT::v4i16 || LT.second == MVT::v8i16 ||
1198 LT.second == MVT::v2i32 || LT.second == MVT::v4i32)
1199 return LT.first * 3;
1200 break;
1201 }
1202 case Intrinsic::experimental_cttz_elts: {
1203 EVT ArgVT = getTLI()->getValueType(DL, ICA.getArgTypes()[0]);
1204 if (getTLI()->isOperationCustom(ISD::CTTZ_ELTS, ArgVT)) {
1205 // This will consist of a SVE brkb and a cntp instruction. These
1206 // typically have the same latency and half the throughput as a vector
1207 // add instruction.
1208 return 4;
1209 }
1210 break;
1211 }
1212 case Intrinsic::loop_dependence_raw_mask:
1213 case Intrinsic::loop_dependence_war_mask: {
1214 // The whilewr/rw instructions require SVE2 or SME.
1215 if (ST->hasSVE2() || ST->hasSME()) {
1216 EVT VecVT = getTLI()->getValueType(DL, RetTy);
1217 unsigned EltSizeInBytes =
1218 cast<ConstantInt>(ICA.getArgs()[2])->getZExtValue();
1219 if (!is_contained({1u, 2u, 4u, 8u}, EltSizeInBytes) ||
1220 VecVT.getVectorMinNumElements() != (16 / EltSizeInBytes))
1221 break;
1222 // For fixed-vector types we need to AND the mask with a ptrue vl<N>.
1223 return isa<FixedVectorType>(RetTy) ? 2 : 1;
1224 }
1225 break;
1226 }
1227 case Intrinsic::experimental_vector_extract_last_active:
1228 if (ST->isSVEorStreamingSVEAvailable()) {
1229 auto [LegalCost, _] = getTypeLegalizationCost(ICA.getArgTypes()[0]);
1230 // This should turn into chained clastb instructions.
1231 return LegalCost;
1232 }
1233 break;
1234 case Intrinsic::pow: {
1235 // For scalar calls we know the target has the libcall, and for fixed-width
1236 // vectors we know for the worst case it can be scalarised.
1237 EVT VT = getTLI()->getValueType(DL, RetTy);
1238 RTLIB::Libcall LC = RTLIB::getPOW(VT);
1239 bool HasLibcall = getTLI()->getLibcallImpl(LC) != RTLIB::Unsupported;
1240 bool CanLowerWithLibcalls = !isa<ScalableVectorType>(RetTy) || HasLibcall;
1241
1242 // If we know that the call can be lowered with libcalls then it's safe to
1243 // reduce the costs in some cases. This is important for scalable vectors,
1244 // since we cannot scalarize the call in the absence of a vector math
1245 // library.
1246 if (CanLowerWithLibcalls && ICA.getInst() && !ICA.getArgs().empty()) {
1247 // If we know the fast math flags and the exponent is a constant then the
1248 // cost may be less for some exponents like 0.25 and 0.75.
1249 const Constant *ExpC = dyn_cast<Constant>(ICA.getArgs()[1]);
1250 if (ExpC && isa<VectorType>(ExpC->getType()))
1251 ExpC = ExpC->getSplatValue();
1252 if (auto *ExpF = dyn_cast_or_null<ConstantFP>(ExpC)) {
1253 // The argument must be a FP constant.
1254 bool Is025 = ExpF->getValueAPF().isExactlyValue(0.25);
1255 bool Is075 = ExpF->getValueAPF().isExactlyValue(0.75);
1256 FastMathFlags FMF = ICA.getInst()->getFastMathFlags();
1257 if ((Is025 || Is075) && FMF.noInfs() && FMF.approxFunc() &&
1258 (!Is025 || FMF.noSignedZeros())) {
1259 IntrinsicCostAttributes Attrs(Intrinsic::sqrt, RetTy, {RetTy}, FMF);
1261 if (Is025)
1262 return 2 * Sqrt;
1264 getArithmeticInstrCost(Instruction::FMul, RetTy, CostKind);
1265 return (Sqrt * 2) + FMul;
1266 }
1267 // TODO: For 1/3 exponents we expect the cbrt call to be slightly
1268 // cheaper than pow.
1269 }
1270 }
1271
1272 if (HasLibcall)
1273 return getCallInstrCost(nullptr, RetTy, ICA.getArgTypes(), CostKind);
1274 break;
1275 }
1276 case Intrinsic::sqrt:
1277 case Intrinsic::fabs:
1278 case Intrinsic::ceil:
1279 case Intrinsic::floor:
1280 case Intrinsic::nearbyint:
1281 case Intrinsic::round:
1282 case Intrinsic::rint:
1283 case Intrinsic::roundeven:
1284 case Intrinsic::trunc:
1285 case Intrinsic::minnum:
1286 case Intrinsic::maxnum:
1287 case Intrinsic::minimum:
1288 case Intrinsic::maximum: {
1289 if (isa<ScalableVectorType>(RetTy) && ST->isSVEorStreamingSVEAvailable()) {
1290 auto LT = getTypeLegalizationCost(RetTy);
1291 return LT.first;
1292 }
1293 break;
1294 }
1295 default:
1296 break;
1297 }
1299}
1300
1301/// The function will remove redundant reinterprets casting in the presence
1302/// of the control flow
1303static std::optional<Instruction *> processPhiNode(InstCombiner &IC,
1304 IntrinsicInst &II) {
1306 auto RequiredType = II.getType();
1307
1308 auto *PN = dyn_cast<PHINode>(II.getArgOperand(0));
1309 assert(PN && "Expected Phi Node!");
1310
1311 // Don't create a new Phi unless we can remove the old one.
1312 if (!PN->hasOneUse())
1313 return std::nullopt;
1314
1315 for (Value *IncValPhi : PN->incoming_values()) {
1316 auto *Reinterpret = dyn_cast<IntrinsicInst>(IncValPhi);
1317 if (!Reinterpret ||
1318 Reinterpret->getIntrinsicID() !=
1319 Intrinsic::aarch64_sve_convert_to_svbool ||
1320 RequiredType != Reinterpret->getArgOperand(0)->getType())
1321 return std::nullopt;
1322 }
1323
1324 // Create the new Phi
1325 IC.Builder.SetInsertPoint(PN);
1326 PHINode *NPN = IC.Builder.CreatePHI(RequiredType, PN->getNumIncomingValues());
1327 Worklist.push_back(PN);
1328
1329 for (unsigned I = 0; I < PN->getNumIncomingValues(); I++) {
1330 auto *Reinterpret = cast<Instruction>(PN->getIncomingValue(I));
1331 NPN->addIncoming(Reinterpret->getOperand(0), PN->getIncomingBlock(I));
1332 Worklist.push_back(Reinterpret);
1333 }
1334
1335 // Cleanup Phi Node and reinterprets
1336 return IC.replaceInstUsesWith(II, NPN);
1337}
1338
1339// A collection of properties common to SVE intrinsics that allow for combines
1340// to be written without needing to know the specific intrinsic.
1342 //
1343 // Helper routines for common intrinsic definitions.
1344 //
1345
1346 // e.g. llvm.aarch64.sve.add pg, op1, op2
1347 // with IID ==> llvm.aarch64.sve.add_u
1348 static SVEIntrinsicInfo
1355
1356 // e.g. llvm.aarch64.sve.neg inactive, pg, op
1363
1364 // e.g. llvm.aarch64.sve.fcvtnt inactive, pg, op
1370
1371 // e.g. llvm.aarch64.sve.add_u pg, op1, op2
1377
1378 // e.g. llvm.aarch64.sve.prf pg, ptr (GPIndex = 0)
1379 // llvm.aarch64.sve.st1 data, pg, ptr (GPIndex = 1)
1380 static SVEIntrinsicInfo defaultVoidOp(unsigned GPIndex) {
1381 return SVEIntrinsicInfo()
1384 }
1385
1386 // e.g. llvm.aarch64.sve.cmpeq pg, op1, op2
1387 // llvm.aarch64.sve.ld1 pg, ptr
1394
1395 // All properties relate to predication and thus having a general predicate
1396 // is the minimum requirement to say there is intrinsic info to act on.
1397 explicit operator bool() const { return hasGoverningPredicate(); }
1398
1399 //
1400 // Properties relating to the governing predicate.
1401 //
1402
1404 return GoverningPredicateIdx != std::numeric_limits<unsigned>::max();
1405 }
1406
1408 assert(hasGoverningPredicate() && "Property not set!");
1409 return GoverningPredicateIdx;
1410 }
1411
1413 assert(!hasGoverningPredicate() && "Cannot set property twice!");
1414 GoverningPredicateIdx = Index;
1415 return *this;
1416 }
1417
1418 //
1419 // Properties relating to operations the intrinsic could be transformed into.
1420 // NOTE: This does not mean such a transformation is always possible, but the
1421 // knowledge makes it possible to reuse existing optimisations without needing
1422 // to embed specific handling for each intrinsic. For example, instruction
1423 // simplification can be used to optimise an intrinsic's active lanes.
1424 //
1425
1426 //
1427 // Intrinsic that produces the same result for active lanes.
1428 //
1429
1431 return UndefIntrinsic != Intrinsic::not_intrinsic;
1432 }
1433
1435 assert(hasMatchingUndefIntrinsic() && "Property not set!");
1436 return UndefIntrinsic;
1437 }
1438
1440 assert(!hasMatchingUndefIntrinsic() && "Cannot set property twice!");
1441 UndefIntrinsic = IID;
1442 return *this;
1443 }
1444
1445 //
1446 // Instruction where active lanes produce the same result.
1447 //
1448
1449 bool hasMatchingIROpode() const { return IROpcode != 0; }
1450
1451 unsigned getMatchingIROpode() const {
1452 assert(hasMatchingIROpode() && "Property not set!");
1453 return IROpcode;
1454 }
1455
1457 assert(!hasMatchingIROpode() && "Cannot set property twice!");
1458 IROpcode = Opcode;
1459 return *this;
1460 }
1461
1462 bool hasCmpPredicate() const {
1463 return CmpPredicate != CmpInst::BAD_ICMP_PREDICATE;
1464 }
1465
1467 assert(hasCmpPredicate() && "Property not set!");
1468 return CmpPredicate;
1469 }
1470
1472 assert(!hasCmpPredicate() && "Cannot set property twice!");
1473 CmpPredicate = Pred;
1474
1475 if (CmpInst::isFPPredicate(Pred))
1476 return setMatchingIROpcode(Instruction::FCmp);
1477
1478 if (CmpInst::isIntPredicate(Pred))
1479 return setMatchingIROpcode(Instruction::ICmp);
1480
1481 llvm_unreachable("Unsupported compare predicate!");
1482 }
1483
1484 //
1485 // Properties relating to the result of inactive lanes.
1486 //
1487
1489 return ResultLanes == InactiveLanesTakenFromOperand;
1490 }
1491
1493 assert(inactiveLanesTakenFromOperand() && "Property not set!");
1494 return OperandIdxForInactiveLanes;
1495 }
1496
1498 assert(ResultLanes == Uninitialized && "Cannot set property twice!");
1499 ResultLanes = InactiveLanesTakenFromOperand;
1500 OperandIdxForInactiveLanes = Index;
1501 return *this;
1502 }
1503
1505 return ResultLanes == InactiveLanesAreNotDefined;
1506 }
1507
1509 assert(ResultLanes == Uninitialized && "Cannot set property twice!");
1510 ResultLanes = InactiveLanesAreNotDefined;
1511 return *this;
1512 }
1513
1515 return ResultLanes == InactiveLanesAreUnused;
1516 }
1517
1519 assert(ResultLanes == Uninitialized && "Cannot set property twice!");
1520 ResultLanes = InactiveLanesAreUnused;
1521 return *this;
1522 }
1523
1524 // NOTE: Whilst not limited to only inactive lanes, the common use case is:
1525 // inactiveLanesAreZeroed =
1526 // resultIsZeroInitialized() && inactiveLanesAreUnused()
1527 bool resultIsZeroInitialized() const { return ResultIsZeroInitialized; }
1528
1530 ResultIsZeroInitialized = true;
1531 return *this;
1532 }
1533
1534 //
1535 // The first operand of unary merging operations is typically only used to
1536 // set the result for inactive lanes. Knowing this allows us to deadcode the
1537 // operand when we can prove there are no inactive lanes.
1538 //
1539
1541 return OperandIdxWithNoActiveLanes != std::numeric_limits<unsigned>::max();
1542 }
1543
1545 assert(hasOperandWithNoActiveLanes() && "Property not set!");
1546 return OperandIdxWithNoActiveLanes;
1547 }
1548
1550 assert(!hasOperandWithNoActiveLanes() && "Cannot set property twice!");
1551 OperandIdxWithNoActiveLanes = Index;
1552 return *this;
1553 }
1554
1555private:
1556 unsigned GoverningPredicateIdx = std::numeric_limits<unsigned>::max();
1557
1558 Intrinsic::ID UndefIntrinsic = Intrinsic::not_intrinsic;
1559 unsigned IROpcode = 0;
1561
1562 enum PredicationStyle {
1564 InactiveLanesTakenFromOperand,
1565 InactiveLanesAreNotDefined,
1566 InactiveLanesAreUnused
1567 } ResultLanes = Uninitialized;
1568
1569 bool ResultIsZeroInitialized = false;
1570 unsigned OperandIdxForInactiveLanes = std::numeric_limits<unsigned>::max();
1571 unsigned OperandIdxWithNoActiveLanes = std::numeric_limits<unsigned>::max();
1572};
1573
1575 // Some SVE intrinsics do not use scalable vector types, but since they are
1576 // not relevant from an SVEIntrinsicInfo perspective, they are also ignored.
1577 if (!isa<ScalableVectorType>(II.getType()) &&
1578 all_of(II.args(), [&](const Value *V) {
1579 return !isa<ScalableVectorType>(V->getType());
1580 }))
1581 return SVEIntrinsicInfo();
1582
1583 Intrinsic::ID IID = II.getIntrinsicID();
1584 switch (IID) {
1585 default:
1586 break;
1587 case Intrinsic::aarch64_sve_fcvt_bf16f32_v2:
1588 case Intrinsic::aarch64_sve_fcvt_f16f32:
1589 case Intrinsic::aarch64_sve_fcvt_f16f64:
1590 case Intrinsic::aarch64_sve_fcvt_f32f16:
1591 case Intrinsic::aarch64_sve_fcvt_f32f64:
1592 case Intrinsic::aarch64_sve_fcvt_f64f16:
1593 case Intrinsic::aarch64_sve_fcvt_f64f32:
1594 case Intrinsic::aarch64_sve_fcvtlt_f32f16:
1595 case Intrinsic::aarch64_sve_fcvtlt_f64f32:
1596 case Intrinsic::aarch64_sve_fcvtx_f32f64:
1597 case Intrinsic::aarch64_sve_fcvtzs:
1598 case Intrinsic::aarch64_sve_fcvtzs_i32f16:
1599 case Intrinsic::aarch64_sve_fcvtzs_i32f64:
1600 case Intrinsic::aarch64_sve_fcvtzs_i64f16:
1601 case Intrinsic::aarch64_sve_fcvtzs_i64f32:
1602 case Intrinsic::aarch64_sve_fcvtzu:
1603 case Intrinsic::aarch64_sve_fcvtzu_i32f16:
1604 case Intrinsic::aarch64_sve_fcvtzu_i32f64:
1605 case Intrinsic::aarch64_sve_fcvtzu_i64f16:
1606 case Intrinsic::aarch64_sve_fcvtzu_i64f32:
1607 case Intrinsic::aarch64_sve_revb:
1608 case Intrinsic::aarch64_sve_revh:
1609 case Intrinsic::aarch64_sve_revw:
1610 case Intrinsic::aarch64_sve_revd:
1611 case Intrinsic::aarch64_sve_scvtf:
1612 case Intrinsic::aarch64_sve_scvtf_f16i32:
1613 case Intrinsic::aarch64_sve_scvtf_f16i64:
1614 case Intrinsic::aarch64_sve_scvtf_f32i64:
1615 case Intrinsic::aarch64_sve_scvtf_f64i32:
1616 case Intrinsic::aarch64_sve_ucvtf:
1617 case Intrinsic::aarch64_sve_ucvtf_f16i32:
1618 case Intrinsic::aarch64_sve_ucvtf_f16i64:
1619 case Intrinsic::aarch64_sve_ucvtf_f32i64:
1620 case Intrinsic::aarch64_sve_ucvtf_f64i32:
1622
1623 case Intrinsic::aarch64_sve_fcvtnt_bf16f32_v2:
1624 case Intrinsic::aarch64_sve_fcvtnt_f16f32:
1625 case Intrinsic::aarch64_sve_fcvtnt_f32f64:
1626 case Intrinsic::aarch64_sve_fcvtxnt_f32f64:
1628
1629 case Intrinsic::aarch64_sve_fabd:
1630 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fabd_u);
1631 case Intrinsic::aarch64_sve_fadd:
1632 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fadd_u)
1633 .setMatchingIROpcode(Instruction::FAdd);
1634 case Intrinsic::aarch64_sve_fdiv:
1635 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fdiv_u)
1636 .setMatchingIROpcode(Instruction::FDiv);
1637 case Intrinsic::aarch64_sve_fmax:
1638 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmax_u);
1639 case Intrinsic::aarch64_sve_fmaxnm:
1640 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmaxnm_u);
1641 case Intrinsic::aarch64_sve_fmin:
1642 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmin_u);
1643 case Intrinsic::aarch64_sve_fminnm:
1644 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fminnm_u);
1645 case Intrinsic::aarch64_sve_fmla:
1646 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmla_u);
1647 case Intrinsic::aarch64_sve_fmls:
1648 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmls_u);
1649 case Intrinsic::aarch64_sve_fmul:
1650 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmul_u)
1651 .setMatchingIROpcode(Instruction::FMul);
1652 case Intrinsic::aarch64_sve_fmulx:
1653 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fmulx_u);
1654 case Intrinsic::aarch64_sve_fnmla:
1655 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fnmla_u);
1656 case Intrinsic::aarch64_sve_fnmls:
1657 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fnmls_u);
1658 case Intrinsic::aarch64_sve_fsub:
1659 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_fsub_u)
1660 .setMatchingIROpcode(Instruction::FSub);
1661 case Intrinsic::aarch64_sve_add:
1662 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_add_u)
1663 .setMatchingIROpcode(Instruction::Add);
1664 case Intrinsic::aarch64_sve_mla:
1665 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_mla_u);
1666 case Intrinsic::aarch64_sve_mls:
1667 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_mls_u);
1668 case Intrinsic::aarch64_sve_mul:
1669 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_mul_u)
1670 .setMatchingIROpcode(Instruction::Mul);
1671 case Intrinsic::aarch64_sve_sabd:
1672 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sabd_u);
1673 case Intrinsic::aarch64_sve_sdiv:
1674 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sdiv_u)
1675 .setMatchingIROpcode(Instruction::SDiv);
1676 case Intrinsic::aarch64_sve_smax:
1677 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_smax_u);
1678 case Intrinsic::aarch64_sve_smin:
1679 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_smin_u);
1680 case Intrinsic::aarch64_sve_smulh:
1681 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_smulh_u);
1682 case Intrinsic::aarch64_sve_sub:
1683 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sub_u)
1684 .setMatchingIROpcode(Instruction::Sub);
1685 case Intrinsic::aarch64_sve_uabd:
1686 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_uabd_u);
1687 case Intrinsic::aarch64_sve_udiv:
1688 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_udiv_u)
1689 .setMatchingIROpcode(Instruction::UDiv);
1690 case Intrinsic::aarch64_sve_umax:
1691 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_umax_u);
1692 case Intrinsic::aarch64_sve_umin:
1693 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_umin_u);
1694 case Intrinsic::aarch64_sve_umulh:
1695 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_umulh_u);
1696 case Intrinsic::aarch64_sve_asr:
1697 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_asr_u)
1698 .setMatchingIROpcode(Instruction::AShr);
1699 case Intrinsic::aarch64_sve_lsl:
1700 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_lsl_u)
1701 .setMatchingIROpcode(Instruction::Shl);
1702 case Intrinsic::aarch64_sve_lsr:
1703 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_lsr_u)
1704 .setMatchingIROpcode(Instruction::LShr);
1705 case Intrinsic::aarch64_sve_and:
1706 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_and_u)
1707 .setMatchingIROpcode(Instruction::And);
1708 case Intrinsic::aarch64_sve_bic:
1709 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_bic_u);
1710 case Intrinsic::aarch64_sve_eor:
1711 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_eor_u)
1712 .setMatchingIROpcode(Instruction::Xor);
1713 case Intrinsic::aarch64_sve_orr:
1714 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_orr_u)
1715 .setMatchingIROpcode(Instruction::Or);
1716 case Intrinsic::aarch64_sve_shsub:
1717 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_shsub_u);
1718 case Intrinsic::aarch64_sve_shsubr:
1720 case Intrinsic::aarch64_sve_sqrshl:
1721 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sqrshl_u);
1722 case Intrinsic::aarch64_sve_sqshl:
1723 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sqshl_u);
1724 case Intrinsic::aarch64_sve_sqsub:
1725 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_sqsub_u);
1726 case Intrinsic::aarch64_sve_srshl:
1727 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_srshl_u);
1728 case Intrinsic::aarch64_sve_uhsub:
1729 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_uhsub_u);
1730 case Intrinsic::aarch64_sve_uhsubr:
1732 case Intrinsic::aarch64_sve_uqrshl:
1733 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_uqrshl_u);
1734 case Intrinsic::aarch64_sve_uqshl:
1735 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_uqshl_u);
1736 case Intrinsic::aarch64_sve_uqsub:
1737 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_uqsub_u);
1738 case Intrinsic::aarch64_sve_urshl:
1739 return SVEIntrinsicInfo::defaultMergingOp(Intrinsic::aarch64_sve_urshl_u);
1740
1741 case Intrinsic::aarch64_sve_add_u:
1743 Instruction::Add);
1744 case Intrinsic::aarch64_sve_and_u:
1746 Instruction::And);
1747 case Intrinsic::aarch64_sve_asr_u:
1749 Instruction::AShr);
1750 case Intrinsic::aarch64_sve_eor_u:
1752 Instruction::Xor);
1753 case Intrinsic::aarch64_sve_fadd_u:
1755 Instruction::FAdd);
1756 case Intrinsic::aarch64_sve_fdiv_u:
1758 Instruction::FDiv);
1759 case Intrinsic::aarch64_sve_fmul_u:
1761 Instruction::FMul);
1762 case Intrinsic::aarch64_sve_fsub_u:
1764 Instruction::FSub);
1765 case Intrinsic::aarch64_sve_lsl_u:
1767 Instruction::Shl);
1768 case Intrinsic::aarch64_sve_lsr_u:
1770 Instruction::LShr);
1771 case Intrinsic::aarch64_sve_mul_u:
1773 Instruction::Mul);
1774 case Intrinsic::aarch64_sve_orr_u:
1776 Instruction::Or);
1777 case Intrinsic::aarch64_sve_sdiv_u:
1779 Instruction::SDiv);
1780 case Intrinsic::aarch64_sve_sub_u:
1782 Instruction::Sub);
1783 case Intrinsic::aarch64_sve_udiv_u:
1785 Instruction::UDiv);
1786
1787 case Intrinsic::aarch64_sve_addqv:
1788 case Intrinsic::aarch64_sve_bic_z:
1789 case Intrinsic::aarch64_sve_brka_z:
1790 case Intrinsic::aarch64_sve_brkb_z:
1791 case Intrinsic::aarch64_sve_brkn_z:
1792 case Intrinsic::aarch64_sve_brkpa_z:
1793 case Intrinsic::aarch64_sve_brkpb_z:
1794 case Intrinsic::aarch64_sve_cntp:
1795 case Intrinsic::aarch64_sve_compact:
1796 case Intrinsic::aarch64_sve_eorv:
1797 case Intrinsic::aarch64_sve_eorqv:
1798 case Intrinsic::aarch64_sve_nand_z:
1799 case Intrinsic::aarch64_sve_nor_z:
1800 case Intrinsic::aarch64_sve_orn_z:
1801 case Intrinsic::aarch64_sve_orv:
1802 case Intrinsic::aarch64_sve_orqv:
1803 case Intrinsic::aarch64_sve_pnext:
1804 case Intrinsic::aarch64_sve_rdffr_z:
1805 case Intrinsic::aarch64_sve_saddv:
1806 case Intrinsic::aarch64_sve_uaddv:
1807 case Intrinsic::aarch64_sve_umaxv:
1808 case Intrinsic::aarch64_sve_umaxqv:
1809 case Intrinsic::aarch64_sve_facge:
1810 case Intrinsic::aarch64_sve_facgt:
1811 case Intrinsic::aarch64_sve_ld1:
1812 case Intrinsic::aarch64_sve_ld1_gather:
1813 case Intrinsic::aarch64_sve_ld1_gather_index:
1814 case Intrinsic::aarch64_sve_ld1_gather_scalar_offset:
1815 case Intrinsic::aarch64_sve_ld1_gather_sxtw:
1816 case Intrinsic::aarch64_sve_ld1_gather_sxtw_index:
1817 case Intrinsic::aarch64_sve_ld1_gather_uxtw:
1818 case Intrinsic::aarch64_sve_ld1_gather_uxtw_index:
1819 case Intrinsic::aarch64_sve_ld1q_gather_index:
1820 case Intrinsic::aarch64_sve_ld1q_gather_scalar_offset:
1821 case Intrinsic::aarch64_sve_ld1q_gather_vector_offset:
1822 case Intrinsic::aarch64_sve_ld1ro:
1823 case Intrinsic::aarch64_sve_ld1rq:
1824 case Intrinsic::aarch64_sve_ld1udq:
1825 case Intrinsic::aarch64_sve_ld1uwq:
1826 case Intrinsic::aarch64_sve_ld2_sret:
1827 case Intrinsic::aarch64_sve_ld2q_sret:
1828 case Intrinsic::aarch64_sve_ld3_sret:
1829 case Intrinsic::aarch64_sve_ld3q_sret:
1830 case Intrinsic::aarch64_sve_ld4_sret:
1831 case Intrinsic::aarch64_sve_ld4q_sret:
1832 case Intrinsic::aarch64_sve_ldff1:
1833 case Intrinsic::aarch64_sve_ldff1_gather:
1834 case Intrinsic::aarch64_sve_ldff1_gather_index:
1835 case Intrinsic::aarch64_sve_ldff1_gather_scalar_offset:
1836 case Intrinsic::aarch64_sve_ldff1_gather_sxtw:
1837 case Intrinsic::aarch64_sve_ldff1_gather_sxtw_index:
1838 case Intrinsic::aarch64_sve_ldff1_gather_uxtw:
1839 case Intrinsic::aarch64_sve_ldff1_gather_uxtw_index:
1840 case Intrinsic::aarch64_sve_ldnf1:
1841 case Intrinsic::aarch64_sve_ldnt1:
1842 case Intrinsic::aarch64_sve_ldnt1_gather:
1843 case Intrinsic::aarch64_sve_ldnt1_gather_index:
1844 case Intrinsic::aarch64_sve_ldnt1_gather_scalar_offset:
1845 case Intrinsic::aarch64_sve_ldnt1_gather_uxtw:
1847
1848 case Intrinsic::aarch64_sve_and_z:
1850 Instruction::And);
1851 case Intrinsic::aarch64_sve_orr_z:
1853 Instruction::Or);
1854 case Intrinsic::aarch64_sve_eor_z:
1856 Instruction::Xor);
1857
1858 case Intrinsic::aarch64_sve_cmpeq:
1859 case Intrinsic::aarch64_sve_cmpeq_wide:
1862 case Intrinsic::aarch64_sve_cmpge:
1863 case Intrinsic::aarch64_sve_cmpge_wide:
1866 case Intrinsic::aarch64_sve_cmpgt:
1867 case Intrinsic::aarch64_sve_cmpgt_wide:
1870 case Intrinsic::aarch64_sve_cmphi:
1871 case Intrinsic::aarch64_sve_cmphi_wide:
1874 case Intrinsic::aarch64_sve_cmphs:
1875 case Intrinsic::aarch64_sve_cmphs_wide:
1878 case Intrinsic::aarch64_sve_cmple_wide:
1881 case Intrinsic::aarch64_sve_cmplo_wide:
1884 case Intrinsic::aarch64_sve_cmpls_wide:
1887 case Intrinsic::aarch64_sve_cmplt_wide:
1890 case Intrinsic::aarch64_sve_cmpne:
1891 case Intrinsic::aarch64_sve_cmpne_wide:
1894 case Intrinsic::aarch64_sve_fcmpeq:
1897 case Intrinsic::aarch64_sve_fcmpge:
1900 case Intrinsic::aarch64_sve_fcmpgt:
1903 case Intrinsic::aarch64_sve_fcmpne:
1906 case Intrinsic::aarch64_sve_fcmpuo:
1909
1910 case Intrinsic::aarch64_sve_prf:
1911 case Intrinsic::aarch64_sve_prfb_gather_index:
1912 case Intrinsic::aarch64_sve_prfb_gather_scalar_offset:
1913 case Intrinsic::aarch64_sve_prfb_gather_sxtw_index:
1914 case Intrinsic::aarch64_sve_prfb_gather_uxtw_index:
1915 case Intrinsic::aarch64_sve_prfd_gather_index:
1916 case Intrinsic::aarch64_sve_prfd_gather_scalar_offset:
1917 case Intrinsic::aarch64_sve_prfd_gather_sxtw_index:
1918 case Intrinsic::aarch64_sve_prfd_gather_uxtw_index:
1919 case Intrinsic::aarch64_sve_prfh_gather_index:
1920 case Intrinsic::aarch64_sve_prfh_gather_scalar_offset:
1921 case Intrinsic::aarch64_sve_prfh_gather_sxtw_index:
1922 case Intrinsic::aarch64_sve_prfh_gather_uxtw_index:
1923 case Intrinsic::aarch64_sve_prfw_gather_index:
1924 case Intrinsic::aarch64_sve_prfw_gather_scalar_offset:
1925 case Intrinsic::aarch64_sve_prfw_gather_sxtw_index:
1926 case Intrinsic::aarch64_sve_prfw_gather_uxtw_index:
1928
1929 case Intrinsic::aarch64_sve_st1_scatter:
1930 case Intrinsic::aarch64_sve_st1_scatter_scalar_offset:
1931 case Intrinsic::aarch64_sve_st1_scatter_sxtw:
1932 case Intrinsic::aarch64_sve_st1_scatter_sxtw_index:
1933 case Intrinsic::aarch64_sve_st1_scatter_uxtw:
1934 case Intrinsic::aarch64_sve_st1_scatter_uxtw_index:
1935 case Intrinsic::aarch64_sve_st1dq:
1936 case Intrinsic::aarch64_sve_st1q_scatter_index:
1937 case Intrinsic::aarch64_sve_st1q_scatter_scalar_offset:
1938 case Intrinsic::aarch64_sve_st1q_scatter_vector_offset:
1939 case Intrinsic::aarch64_sve_st1wq:
1940 case Intrinsic::aarch64_sve_stnt1:
1941 case Intrinsic::aarch64_sve_stnt1_scatter:
1942 case Intrinsic::aarch64_sve_stnt1_scatter_index:
1943 case Intrinsic::aarch64_sve_stnt1_scatter_scalar_offset:
1944 case Intrinsic::aarch64_sve_stnt1_scatter_uxtw:
1946 case Intrinsic::aarch64_sve_st2:
1947 case Intrinsic::aarch64_sve_st2q:
1949 case Intrinsic::aarch64_sve_st3:
1950 case Intrinsic::aarch64_sve_st3q:
1952 case Intrinsic::aarch64_sve_st4:
1953 case Intrinsic::aarch64_sve_st4q:
1955 }
1956
1957 return SVEIntrinsicInfo();
1958}
1959
1960static bool isAllActivePredicate(Value *Pred) {
1961 Value *UncastedPred;
1962
1963 // Look through predicate casts that only remove lanes.
1965 m_Value(UncastedPred)))) {
1966 auto *OrigPredTy = cast<ScalableVectorType>(Pred->getType());
1967 Pred = UncastedPred;
1968
1970 m_Value(UncastedPred))))
1971 // If the predicate has the same or less lanes than the uncasted predicate
1972 // then we know the casting has no effect.
1973 if (OrigPredTy->getMinNumElements() <=
1974 cast<ScalableVectorType>(UncastedPred->getType())
1975 ->getMinNumElements())
1976 Pred = UncastedPred;
1977 }
1978
1979 auto *C = dyn_cast<Constant>(Pred);
1980 return C && C->isAllOnesValue();
1981}
1982
1983// Simplify `V` by only considering the operations that affect active lanes.
1984// This function should only return existing Values or newly created Constants.
1985static Value *stripInactiveLanes(Value *V, const Value *Pg) {
1986 auto *Dup = dyn_cast<IntrinsicInst>(V);
1987 if (Dup && Dup->getIntrinsicID() == Intrinsic::aarch64_sve_dup &&
1988 Dup->getOperand(1) == Pg && isa<Constant>(Dup->getOperand(2)))
1990 cast<VectorType>(V->getType())->getElementCount(),
1991 cast<Constant>(Dup->getOperand(2)));
1992
1993 return V;
1994}
1995
1996static std::optional<Instruction *>
1998 const SVEIntrinsicInfo &IInfo) {
1999 const unsigned Opc = IInfo.getMatchingIROpode();
2000 assert(Instruction::isBinaryOp(Opc) && "Expected a binary operation!");
2001
2002 Value *Pg = II.getOperand(0);
2003 Value *Op1 = II.getOperand(1);
2004 Value *Op2 = II.getOperand(2);
2005 const DataLayout &DL = II.getDataLayout();
2006
2007 // Canonicalise constants to the RHS.
2009 isa<Constant>(Op1) && !isa<Constant>(Op2)) {
2010 IC.replaceOperand(II, 1, Op2);
2011 IC.replaceOperand(II, 2, Op1);
2012 return &II;
2013 }
2014
2015 // Only active lanes matter when simplifying the operation.
2016 Op1 = stripInactiveLanes(Op1, Pg);
2017 Op2 = stripInactiveLanes(Op2, Pg);
2018
2019 Value *SimpleII;
2020 if (auto FII = dyn_cast<FPMathOperator>(&II))
2021 SimpleII = simplifyBinOp(Opc, Op1, Op2, FII->getFastMathFlags(), DL);
2022 else
2023 SimpleII = simplifyBinOp(Opc, Op1, Op2, DL);
2024
2025 // If both operands are convert.to.svbool from the same narrower predicate
2026 // type, try to simplify the operation at that narrower type. This is valid
2027 // because the conversions zero the lanes not represented by the narrower
2028 // type, so those lanes of the result are zero either way.
2029 Value *NarrowOp1, *NarrowOp2;
2030 if (!SimpleII &&
2032 m_Value(NarrowOp1))) &&
2034 m_Value(NarrowOp2))) &&
2035 NarrowOp1->getType() == NarrowOp2->getType()) {
2036 Value *SimpleNarrow = simplifyBinOp(Opc, NarrowOp1, NarrowOp2, DL);
2037 if (SimpleNarrow && !isa<UndefValue>(SimpleNarrow)) {
2038 if (match(SimpleNarrow, m_ZeroInt()))
2039 SimpleII = Constant::getNullValue(II.getType());
2040 else if (SimpleNarrow == NarrowOp1)
2041 SimpleII = Op1;
2042 else if (SimpleNarrow == NarrowOp2)
2043 SimpleII = Op2;
2044 else
2045 SimpleII =
2046 IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_to_svbool,
2047 SimpleNarrow->getType(), SimpleNarrow);
2048 }
2049 }
2050
2051 // An SVE intrinsic's result is always defined. However, this is not the case
2052 // for its equivalent IR instruction (e.g. when shifting by an amount more
2053 // than the data's bitwidth). Simplifications to an undefined result must be
2054 // ignored to preserve the intrinsic's expected behaviour.
2055 if (!SimpleII || isa<UndefValue>(SimpleII))
2056 return std::nullopt;
2057
2058 if (IInfo.inactiveLanesAreNotDefined())
2059 return IC.replaceInstUsesWith(II, SimpleII);
2060
2061 Value *Inactive =
2063 ? Constant::getNullValue(II.getType())
2064 : II.getOperand(IInfo.getOperandIdxInactiveLanesTakenFrom());
2065
2066 // The intrinsic does nothing (e.g. sve.mul(pg, A, 1.0)).
2067 if (SimpleII == Inactive)
2068 return IC.replaceInstUsesWith(II, SimpleII);
2069
2070 // Inactive lanes must be preserved.
2071 SimpleII = IC.Builder.CreateSelect(Pg, SimpleII, Inactive);
2072 return IC.replaceInstUsesWith(II, SimpleII);
2073}
2074
2075static std::optional<Instruction *>
2077 const SVEIntrinsicInfo &IInfo) {
2078 const unsigned Opc = IInfo.getMatchingIROpode();
2079 assert((Opc == Instruction::ICmp || Opc == Instruction::FCmp) &&
2080 "Expected a compare operation!");
2081
2082 Value *Pg = II.getOperand(0);
2083 Value *LHS = II.getOperand(1);
2084 Value *RHS = II.getOperand(2);
2085 CmpInst::Predicate CmpPred = IInfo.getCmpPredicate();
2086 bool IsWideICmp =
2087 Opc == Instruction::ICmp && LHS->getType() != RHS->getType();
2088 assert((IsWideICmp || LHS->getType() == RHS->getType()) &&
2089 "Unexpected wide compare!");
2090
2091 // Canonicalise constants to the RHS.
2092 if ((ICmpInst::isCommutative(CmpPred) || FCmpInst::isCommutative(CmpPred)) &&
2093 isa<Constant>(LHS) && !isa<Constant>(RHS) && !IsWideICmp) {
2094 IC.replaceOperand(II, 1, RHS);
2095 IC.replaceOperand(II, 2, LHS);
2096 return &II;
2097 }
2098
2099 // Only active lanes matter when simplifying the operation.
2100 LHS = stripInactiveLanes(LHS, Pg);
2101 RHS = stripInactiveLanes(RHS, Pg);
2102
2103 if (IsWideICmp) {
2104 // We can do more for wide compares, but not using simplifyCmpInst.
2105 const APInt *LHSVal, *RHSVal;
2106 if (!match(LHS, m_APInt(LHSVal)) || !match(RHS, m_APInt(RHSVal)))
2107 return std::nullopt;
2108
2109 // Consider cmpge.wide(..., <vscale x 4 x i32> LHS, <vscale x 2 x i64> RHS),
2110 // we must reconstruct the constants because LHS has the wrong element type,
2111 // and RHS the wrong element count.
2112 Type *WideVT = VectorType::get(RHS->getType()->getScalarType(),
2113 cast<VectorType>(LHS->getType()));
2114 // NOTE: Wide equality comparisons are signed.
2115 if (ICmpInst::isUnsigned(CmpPred)) {
2116 LHS = ConstantInt::get(WideVT, LHSVal->getZExtValue());
2117 RHS = ConstantInt::get(WideVT, RHSVal->getZExtValue());
2118 } else {
2119 LHS = ConstantInt::get(WideVT, LHSVal->getSExtValue());
2120 RHS = ConstantInt::get(WideVT, RHSVal->getSExtValue());
2121 }
2122 }
2123
2124 // TODO: Allow fast-math flags for calls to compare intrinsics.
2125 const DataLayout &DL = II.getDataLayout();
2126 Value *SimpleII = simplifyCmpInst(CmpPred, LHS, RHS, DL);
2127
2128 // No simplification happened.
2129 if (!SimpleII)
2130 return std::nullopt;
2131
2132 assert(IInfo.resultIsZeroInitialized() && "Expected a zeroing operation!");
2133
2134 if (match(SimpleII, m_ZeroInt()))
2135 return IC.replaceInstUsesWith(II, SimpleII);
2136
2137 // Inactive lanes must be zeroed.
2138 SimpleII = IC.Builder.CreateLogicalAnd(Pg, SimpleII);
2139 return IC.replaceInstUsesWith(II, SimpleII);
2140}
2141
2142// Use SVE intrinsic info to eliminate redundant operands and/or canonicalise
2143// to operations with less strict inactive lane requirements.
2144static std::optional<Instruction *>
2146 const SVEIntrinsicInfo &IInfo) {
2147 if (!IInfo.hasGoverningPredicate())
2148 return std::nullopt;
2149
2150 auto *OpPredicate = II.getOperand(IInfo.getGoverningPredicateOperandIdx());
2151
2152 // If there are no active lanes.
2153 if (match(OpPredicate, m_ZeroInt())) {
2155 return IC.replaceInstUsesWith(
2156 II, II.getOperand(IInfo.getOperandIdxInactiveLanesTakenFrom()));
2157
2158 if (IInfo.inactiveLanesAreUnused()) {
2159 if (IInfo.resultIsZeroInitialized())
2161
2162 return IC.eraseInstFromFunction(II);
2163 }
2164 }
2165
2166 // If there are no inactive lanes.
2167 if (isAllActivePredicate(OpPredicate)) {
2168 if (IInfo.hasOperandWithNoActiveLanes()) {
2169 unsigned OpIdx = IInfo.getOperandIdxWithNoActiveLanes();
2170 if (!isa<UndefValue>(II.getOperand(OpIdx)))
2171 return IC.replaceOperand(II, OpIdx, UndefValue::get(II.getType()));
2172 }
2173
2174 if (IInfo.hasMatchingUndefIntrinsic()) {
2175 auto *NewDecl = Intrinsic::getOrInsertDeclaration(
2176 II.getModule(), IInfo.getMatchingUndefIntrinsic(), {II.getType()});
2177 II.setCalledFunction(NewDecl);
2178 return &II;
2179 }
2180 }
2181
2182 if (!IInfo.hasMatchingIROpode())
2183 return std::nullopt;
2184
2185 //
2186 // Operation specific simplifications.
2187 //
2188
2189 unsigned Opc = IInfo.getMatchingIROpode();
2190
2192 return simplifySVEIntrinsicBinOp(IC, II, IInfo);
2193
2194 if (Opc == Instruction::FCmp || Opc == Instruction::ICmp)
2195 return simplifySVEIntrinsicCompare(IC, II, IInfo);
2196
2197 return std::nullopt;
2198}
2199
2200// (from_svbool (binop (to_svbool pred) (svbool_t _) (svbool_t _))))
2201// => (binop (pred) (from_svbool _) (from_svbool _))
2202//
2203// The above transformation eliminates a `to_svbool` in the predicate
2204// operand of bitwise operation `binop` by narrowing the vector width of
2205// the operation. For example, it would convert a `<vscale x 16 x i1>
2206// and` into a `<vscale x 4 x i1> and`. This is profitable because
2207// to_svbool must zero the new lanes during widening, whereas
2208// from_svbool is free.
2209static std::optional<Instruction *>
2211 auto m_ConvertToSVBool = [](auto P) {
2213 };
2214 constexpr Intrinsic::ID ConvertFromSVBool =
2215 Intrinsic::aarch64_sve_convert_from_svbool;
2216
2217 Type *Ty = II.getType();
2218 Value *LHS, *RHS, *NarrowLHS, *NarrowRHS;
2219
2220 if (match(II.getOperand(0),
2222 m_ConvertToSVBool(m_SpecificType(Ty, NarrowRHS))))) {
2223 NarrowLHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, LHS);
2224 Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
2225 return IC.replaceInstUsesWith(II, NarrowAnd);
2226 }
2227
2228 if (match(II.getOperand(0),
2229 m_LogicalAnd(m_ConvertToSVBool(m_SpecificType(Ty, NarrowLHS)),
2230 m_Value(RHS)))) {
2231 NarrowRHS = IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, RHS);
2232 Value *NarrowAnd = IC.Builder.CreateLogicalAnd(NarrowLHS, NarrowRHS);
2233 return IC.replaceInstUsesWith(II, NarrowAnd);
2234 }
2235
2236 auto BinOp = dyn_cast<IntrinsicInst>(II.getOperand(0));
2237 if (!BinOp)
2238 return std::nullopt;
2239
2240 Intrinsic::ID BinOpIID = BinOp->getIntrinsicID();
2241 switch (BinOpIID) {
2242 case Intrinsic::aarch64_sve_and_z:
2243 case Intrinsic::aarch64_sve_bic_z:
2244 case Intrinsic::aarch64_sve_eor_z:
2245 case Intrinsic::aarch64_sve_nand_z:
2246 case Intrinsic::aarch64_sve_nor_z:
2247 case Intrinsic::aarch64_sve_orn_z:
2248 case Intrinsic::aarch64_sve_orr_z:
2249 break;
2250 default:
2251 return std::nullopt;
2252 }
2253
2254 Value *BinOpPred = BinOp->getOperand(0);
2255 Value *BinOpOp1 = BinOp->getOperand(1);
2256 Value *BinOpOp2 = BinOp->getOperand(2);
2257
2258 Value *NarrowBinOpPred;
2259 if (!match(BinOpPred, m_ConvertToSVBool(m_SpecificType(Ty, NarrowBinOpPred))))
2260 return std::nullopt;
2261
2262 Value *NarrowBinOpOp1 =
2263 IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp1);
2264 Value *NarrowBinOpOp2 = NarrowBinOpOp1;
2265 if (BinOpOp1 != BinOpOp2)
2266 NarrowBinOpOp2 =
2267 IC.Builder.CreateIntrinsic(ConvertFromSVBool, Ty, BinOpOp2);
2268 Value *NarrowedBinOp = IC.Builder.CreateIntrinsic(
2269 BinOpIID, Ty, {NarrowBinOpPred, NarrowBinOpOp1, NarrowBinOpOp2});
2270 return IC.replaceInstUsesWith(II, NarrowedBinOp);
2271}
2272
2273static std::optional<Instruction *>
2275 // If the reinterpret instruction operand is a PHI Node
2276 if (isa<PHINode>(II.getArgOperand(0)))
2277 return processPhiNode(IC, II);
2278
2279 if (auto BinOpCombine = tryCombineFromSVBoolBinOp(IC, II))
2280 return BinOpCombine;
2281
2282 // Ignore converts to/from svcount_t.
2283 if (isa<TargetExtType>(II.getArgOperand(0)->getType()) ||
2284 isa<TargetExtType>(II.getType()))
2285 return std::nullopt;
2286
2287 SmallVector<Instruction *, 32> CandidatesForRemoval;
2288 Value *Cursor = II.getOperand(0), *EarliestReplacement = nullptr;
2289
2290 const auto *IVTy = cast<VectorType>(II.getType());
2291
2292 // Walk the chain of conversions.
2293 while (Cursor) {
2294 // If the type of the cursor has fewer lanes than the final result, zeroing
2295 // must take place, which breaks the equivalence chain.
2296 const auto *CursorVTy = cast<VectorType>(Cursor->getType());
2297 if (CursorVTy->getElementCount().getKnownMinValue() <
2298 IVTy->getElementCount().getKnownMinValue())
2299 break;
2300
2301 // If the cursor has the same type as I, it is a viable replacement.
2302 if (Cursor->getType() == IVTy)
2303 EarliestReplacement = Cursor;
2304
2305 auto *IntrinsicCursor = dyn_cast<IntrinsicInst>(Cursor);
2306
2307 // If this is not an SVE conversion intrinsic, this is the end of the chain.
2308 if (!IntrinsicCursor || !(IntrinsicCursor->getIntrinsicID() ==
2309 Intrinsic::aarch64_sve_convert_to_svbool ||
2310 IntrinsicCursor->getIntrinsicID() ==
2311 Intrinsic::aarch64_sve_convert_from_svbool))
2312 break;
2313
2314 CandidatesForRemoval.insert(CandidatesForRemoval.begin(), IntrinsicCursor);
2315 Cursor = IntrinsicCursor->getOperand(0);
2316 }
2317
2318 // If no viable replacement in the conversion chain was found, there is
2319 // nothing to do.
2320 if (!EarliestReplacement)
2321 return std::nullopt;
2322
2323 return IC.replaceInstUsesWith(II, EarliestReplacement);
2324}
2325
2326static std::optional<Instruction *> instCombineSVESel(InstCombiner &IC,
2327 IntrinsicInst &II) {
2328 // svsel(ptrue, x, y) => x
2329 auto *OpPredicate = II.getOperand(0);
2330 if (isAllActivePredicate(OpPredicate))
2331 return IC.replaceInstUsesWith(II, II.getOperand(1));
2332
2333 auto Select =
2334 IC.Builder.CreateSelect(OpPredicate, II.getOperand(1), II.getOperand(2));
2335 return IC.replaceInstUsesWith(II, Select);
2336}
2337
2338static std::optional<Instruction *> instCombineSVEDup(InstCombiner &IC,
2339 IntrinsicInst &II) {
2340 Value *Pg = II.getOperand(1);
2341
2342 // sve.dup(V, all_active, X) ==> splat(X)
2343 if (isAllActivePredicate(Pg)) {
2344 auto *RetTy = cast<ScalableVectorType>(II.getType());
2345 Value *Splat = IC.Builder.CreateVectorSplat(RetTy->getElementCount(),
2346 II.getArgOperand(2));
2347 return IC.replaceInstUsesWith(II, Splat);
2348 }
2349
2351 m_SpecificInt(AArch64SVEPredPattern::vl1))))
2352 return std::nullopt;
2353
2354 // sve.dup(V, sve.ptrue(vl1), X) ==> insertelement V, X, 0
2355 Value *Insert = IC.Builder.CreateInsertElement(
2356 II.getArgOperand(0), II.getArgOperand(2), uint64_t(0));
2357 return IC.replaceInstUsesWith(II, Insert);
2358}
2359
2360static std::optional<Instruction *> instCombineSVEDupX(InstCombiner &IC,
2361 IntrinsicInst &II) {
2362 // Replace DupX with a regular IR splat.
2363 auto *RetTy = cast<ScalableVectorType>(II.getType());
2364 Value *Splat = IC.Builder.CreateVectorSplat(RetTy->getElementCount(),
2365 II.getArgOperand(0));
2366 Splat->takeName(&II);
2367 return IC.replaceInstUsesWith(II, Splat);
2368}
2369
2370// xor(cmpne(%pg, %lhs, %rhs), %pg)
2371// -> cmpeq(%pg, %lhs, %rhs)
2372static std::optional<Instruction *> instCombineXorSVECmpCC(InstCombiner &IC,
2373 IntrinsicInst &II) {
2374 if (!II.hasOneUse())
2375 return std::nullopt;
2376 auto *User = cast<Instruction>(*II.user_begin());
2377 if (!match(User, m_c_Xor(m_Specific(&II), m_Specific(II.getOperand(0)))))
2378 return std::nullopt;
2379
2380 Intrinsic::ID IID;
2381 switch (II.getIntrinsicID()) {
2382 case Intrinsic::aarch64_sve_cmpne:
2383 IID = Intrinsic::aarch64_sve_cmpeq;
2384 break;
2385 case Intrinsic::aarch64_sve_cmpne_wide:
2386 IID = Intrinsic::aarch64_sve_cmpeq_wide;
2387 break;
2388 case Intrinsic::aarch64_sve_cmpeq:
2389 IID = Intrinsic::aarch64_sve_cmpne;
2390 break;
2391 case Intrinsic::aarch64_sve_cmpeq_wide:
2392 IID = Intrinsic::aarch64_sve_cmpne_wide;
2393 break;
2394 default:
2395 return std::nullopt;
2396 }
2397
2399 Value *CMPCC = IC.Builder.CreateIntrinsic(
2400 IID, II.getOperand(1)->getType(),
2401 {II.getOperand(0), II.getOperand(1), II.getOperand(2)});
2402 IC.replaceInstUsesWith(*User, CMPCC);
2404 return &II;
2405}
2406
2407// zext(cmpne(ptrue, %v, 0))
2408// -> umin(%pg, %v, 1)
2409static std::optional<Instruction *> instCombineZExtSVECmpNE(InstCombiner &IC,
2410 IntrinsicInst &II) {
2411 if (!isAllActivePredicate(II.getOperand(0)) ||
2412 !match(II.getOperand(2), m_Zero()))
2413 return std::nullopt;
2414
2415 for (auto *U : II.users()) {
2416 if (match(U, m_ZExt(m_Specific(&II)))) {
2417 auto *User = cast<Instruction>(U);
2418 Type *Ty = II.getOperand(1)->getType();
2419 if (User->getType() != Ty)
2420 continue;
2423 Intrinsic::aarch64_sve_umin, Ty,
2424 {II.getOperand(0), II.getOperand(1), ConstantInt::get(Ty, 1)});
2427 return &II;
2428 }
2429 }
2430 return std::nullopt;
2431}
2432
2433static std::optional<Instruction *> instCombineSVECmpNE(InstCombiner &IC,
2434 IntrinsicInst &II) {
2435 LLVMContext &Ctx = II.getContext();
2436
2437 if (auto Res = instCombineXorSVECmpCC(IC, II))
2438 return Res;
2439
2440 if (auto Res = instCombineZExtSVECmpNE(IC, II))
2441 return Res;
2442
2443 if (!isAllActivePredicate(II.getArgOperand(0)))
2444 return std::nullopt;
2445
2446 // Check that we have a compare of zero..
2447 auto *SplatValue =
2449 if (!SplatValue || !SplatValue->isZero())
2450 return std::nullopt;
2451
2452 // ..against a dupq
2453 auto *DupQLane = dyn_cast<IntrinsicInst>(II.getArgOperand(1));
2454 if (!DupQLane ||
2455 DupQLane->getIntrinsicID() != Intrinsic::aarch64_sve_dupq_lane)
2456 return std::nullopt;
2457
2458 // Where the dupq is a lane 0 replicate of a vector insert
2459 auto *DupQLaneIdx = dyn_cast<ConstantInt>(DupQLane->getArgOperand(1));
2460 if (!DupQLaneIdx || !DupQLaneIdx->isZero())
2461 return std::nullopt;
2462
2463 auto *VecIns = dyn_cast<IntrinsicInst>(DupQLane->getArgOperand(0));
2464 if (!VecIns || VecIns->getIntrinsicID() != Intrinsic::vector_insert)
2465 return std::nullopt;
2466
2467 // Where the vector insert is a fixed constant vector insert into undef at
2468 // index zero
2469 if (!isa<UndefValue>(VecIns->getArgOperand(0)))
2470 return std::nullopt;
2471
2472 if (!cast<ConstantInt>(VecIns->getArgOperand(2))->isZero())
2473 return std::nullopt;
2474
2475 auto *ConstVec = dyn_cast<Constant>(VecIns->getArgOperand(1));
2476 if (!ConstVec)
2477 return std::nullopt;
2478
2479 auto *VecTy = dyn_cast<FixedVectorType>(ConstVec->getType());
2480 auto *OutTy = dyn_cast<ScalableVectorType>(II.getType());
2481 if (!VecTy || !OutTy || VecTy->getNumElements() != OutTy->getMinNumElements())
2482 return std::nullopt;
2483
2484 unsigned NumElts = VecTy->getNumElements();
2485 unsigned PredicateBits = 0;
2486
2487 // Expand intrinsic operands to a 16-bit byte level predicate
2488 for (unsigned I = 0; I < NumElts; ++I) {
2489 auto *Arg = dyn_cast<ConstantInt>(ConstVec->getAggregateElement(I));
2490 if (!Arg)
2491 return std::nullopt;
2492 if (!Arg->isZero())
2493 PredicateBits |= 1 << (I * (16 / NumElts));
2494 }
2495
2496 // If all bits are zero bail early with an empty predicate
2497 if (PredicateBits == 0) {
2498 auto *PFalse = Constant::getNullValue(II.getType());
2499 PFalse->takeName(&II);
2500 return IC.replaceInstUsesWith(II, PFalse);
2501 }
2502
2503 // Calculate largest predicate type used (where byte predicate is largest)
2504 unsigned Mask = 8;
2505 for (unsigned I = 0; I < 16; ++I)
2506 if ((PredicateBits & (1 << I)) != 0)
2507 Mask |= (I % 8);
2508
2509 unsigned PredSize = Mask & -Mask;
2510 auto *PredType = ScalableVectorType::get(
2511 Type::getInt1Ty(Ctx), AArch64::SVEBitsPerBlock / (PredSize * 8));
2512
2513 // Ensure all relevant bits are set
2514 for (unsigned I = 0; I < 16; I += PredSize)
2515 if ((PredicateBits & (1 << I)) == 0)
2516 return std::nullopt;
2517
2518 auto *ConvertToSVBool =
2519 IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_to_svbool,
2520 PredType, ConstantInt::getTrue(PredType));
2521 auto *ConvertFromSVBool =
2522 IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_convert_from_svbool,
2523 II.getType(), ConvertToSVBool);
2524
2525 ConvertFromSVBool->takeName(&II);
2526 return IC.replaceInstUsesWith(II, ConvertFromSVBool);
2527}
2528
2529static std::optional<Instruction *> instCombineSVELast(InstCombiner &IC,
2530 IntrinsicInst &II) {
2531 Value *Pg = II.getArgOperand(0);
2532 Value *Vec = II.getArgOperand(1);
2533 auto IntrinsicID = II.getIntrinsicID();
2534 bool IsAfter = IntrinsicID == Intrinsic::aarch64_sve_lasta;
2535
2536 // lastX(splat(X)) --> X
2537 if (auto *SplatVal = getSplatValue(Vec))
2538 return IC.replaceInstUsesWith(II, SplatVal);
2539
2540 // If x and/or y is a splat value then:
2541 // lastX (binop (x, y)) --> binop(lastX(x), lastX(y))
2542 Value *LHS, *RHS;
2543 if (match(Vec, m_OneUse(m_BinOp(m_Value(LHS), m_Value(RHS))))) {
2544 if (isSplatValue(LHS) || isSplatValue(RHS)) {
2545 auto *OldBinOp = cast<BinaryOperator>(Vec);
2546 auto OpC = OldBinOp->getOpcode();
2547 auto *NewLHS =
2548 IC.Builder.CreateIntrinsic(IntrinsicID, {Vec->getType()}, {Pg, LHS});
2549 auto *NewRHS =
2550 IC.Builder.CreateIntrinsic(IntrinsicID, {Vec->getType()}, {Pg, RHS});
2552 OpC, NewLHS, NewRHS, OldBinOp, OldBinOp->getName(), II.getIterator());
2553 return IC.replaceInstUsesWith(II, NewBinOp);
2554 }
2555 }
2556
2557 auto *C = dyn_cast<Constant>(Pg);
2558 if (IsAfter && C && C->isNullValue()) {
2559 // The intrinsic is extracting lane 0 so use an extract instead.
2560 auto *IdxTy = Type::getInt64Ty(II.getContext());
2561 auto *Extract = ExtractElementInst::Create(Vec, ConstantInt::get(IdxTy, 0));
2562 Extract->insertBefore(II.getIterator());
2563 Extract->takeName(&II);
2564 return IC.replaceInstUsesWith(II, Extract);
2565 }
2566
2567 auto *IntrPG = dyn_cast<IntrinsicInst>(Pg);
2568 if (!IntrPG)
2569 return std::nullopt;
2570
2571 if (IntrPG->getIntrinsicID() != Intrinsic::aarch64_sve_ptrue)
2572 return std::nullopt;
2573
2574 const auto PTruePattern =
2575 cast<ConstantInt>(IntrPG->getOperand(0))->getZExtValue();
2576
2577 // Can the intrinsic's predicate be converted to a known constant index?
2578 unsigned MinNumElts = getNumElementsFromSVEPredPattern(PTruePattern);
2579 if (!MinNumElts)
2580 return std::nullopt;
2581
2582 unsigned Idx = MinNumElts - 1;
2583 // Increment the index if extracting the element after the last active
2584 // predicate element.
2585 if (IsAfter)
2586 ++Idx;
2587
2588 // Ignore extracts whose index is larger than the known minimum vector
2589 // length. NOTE: This is an artificial constraint where we prefer to
2590 // maintain what the user asked for until an alternative is proven faster.
2591 auto *PgVTy = cast<ScalableVectorType>(Pg->getType());
2592 if (Idx >= PgVTy->getMinNumElements())
2593 return std::nullopt;
2594
2595 // The intrinsic is extracting a fixed lane so use an extract instead.
2596 auto *IdxTy = Type::getInt64Ty(II.getContext());
2597 auto *Extract = ExtractElementInst::Create(Vec, ConstantInt::get(IdxTy, Idx));
2598 Extract->insertBefore(II.getIterator());
2599 Extract->takeName(&II);
2600 return IC.replaceInstUsesWith(II, Extract);
2601}
2602
2603static std::optional<Instruction *> instCombineSVECondLast(InstCombiner &IC,
2604 IntrinsicInst &II) {
2605 // The SIMD&FP variant of CLAST[AB] is significantly faster than the scalar
2606 // integer variant across a variety of micro-architectures. Replace scalar
2607 // integer CLAST[AB] intrinsic with optimal SIMD&FP variant. A simple
2608 // bitcast-to-fp + clast[ab] + bitcast-to-int will cost a cycle or two more
2609 // depending on the micro-architecture, but has been observed as generally
2610 // being faster, particularly when the CLAST[AB] op is a loop-carried
2611 // dependency.
2612 Value *Pg = II.getArgOperand(0);
2613 Value *Fallback = II.getArgOperand(1);
2614 Value *Vec = II.getArgOperand(2);
2615 Type *Ty = II.getType();
2616
2617 if (!Ty->isIntegerTy())
2618 return std::nullopt;
2619
2620 Type *FPTy;
2621 switch (cast<IntegerType>(Ty)->getBitWidth()) {
2622 default:
2623 return std::nullopt;
2624 case 16:
2625 FPTy = IC.Builder.getHalfTy();
2626 break;
2627 case 32:
2628 FPTy = IC.Builder.getFloatTy();
2629 break;
2630 case 64:
2631 FPTy = IC.Builder.getDoubleTy();
2632 break;
2633 }
2634
2635 Value *FPFallBack = IC.Builder.CreateBitCast(Fallback, FPTy);
2636 auto *FPVTy = VectorType::get(
2637 FPTy, cast<VectorType>(Vec->getType())->getElementCount());
2638 Value *FPVec = IC.Builder.CreateBitCast(Vec, FPVTy);
2639 auto *FPII = IC.Builder.CreateIntrinsic(
2640 II.getIntrinsicID(), {FPVec->getType()}, {Pg, FPFallBack, FPVec});
2641 Value *FPIItoInt = IC.Builder.CreateBitCast(FPII, II.getType());
2642 return IC.replaceInstUsesWith(II, FPIItoInt);
2643}
2644
2645static std::optional<Instruction *> instCombineRDFFR(InstCombiner &IC,
2646 IntrinsicInst &II) {
2647 // Replace rdffr with predicated rdffr.z intrinsic, so that optimizePTestInstr
2648 // can work with RDFFR_PP for ptest elimination.
2649 auto *RDFFR = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_rdffr_z,
2650 ConstantInt::getTrue(II.getType()));
2651 RDFFR->takeName(&II);
2652 return IC.replaceInstUsesWith(II, RDFFR);
2653}
2654
2655static std::optional<Instruction *>
2657 const auto Pattern = cast<ConstantInt>(II.getArgOperand(0))->getZExtValue();
2658
2659 if (Pattern == AArch64SVEPredPattern::all) {
2661 II.getType(), ElementCount::getScalable(NumElts));
2662 Cnt->takeName(&II);
2663 return IC.replaceInstUsesWith(II, Cnt);
2664 }
2665
2666 unsigned MinNumElts = getNumElementsFromSVEPredPattern(Pattern);
2667
2668 return MinNumElts && NumElts >= MinNumElts
2669 ? std::optional<Instruction *>(IC.replaceInstUsesWith(
2670 II, ConstantInt::get(II.getType(), MinNumElts)))
2671 : std::nullopt;
2672}
2673
2674static std::optional<Instruction *>
2676 const AArch64Subtarget *ST) {
2677 if (!ST->isStreaming())
2678 return std::nullopt;
2679
2680 // In streaming-mode, aarch64_sme_cntds is equivalent to aarch64_sve_cntd
2681 // with SVEPredPattern::all
2682 Value *Cnt =
2684 Cnt->takeName(&II);
2685 return IC.replaceInstUsesWith(II, Cnt);
2686}
2687
2688static std::optional<Instruction *> instCombineSVEPTest(InstCombiner &IC,
2689 IntrinsicInst &II) {
2690 Value *PgVal = II.getArgOperand(0);
2691 Value *OpVal = II.getArgOperand(1);
2692
2693 // PTEST_<FIRST|LAST>(X, X) is equivalent to PTEST_ANY(X, X).
2694 // Later optimizations prefer this form.
2695 if (PgVal == OpVal &&
2696 (II.getIntrinsicID() == Intrinsic::aarch64_sve_ptest_first ||
2697 II.getIntrinsicID() == Intrinsic::aarch64_sve_ptest_last)) {
2698 Value *Ops[] = {PgVal, OpVal};
2699 Type *Tys[] = {PgVal->getType()};
2700
2701 auto *PTest =
2702 IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_ptest_any, Tys, Ops);
2703 PTest->takeName(&II);
2704
2705 return IC.replaceInstUsesWith(II, PTest);
2706 }
2707
2710
2711 if (!Pg || !Op)
2712 return std::nullopt;
2713
2714 Intrinsic::ID OpIID = Op->getIntrinsicID();
2715
2716 if (Pg->getIntrinsicID() == Intrinsic::aarch64_sve_convert_to_svbool &&
2717 OpIID == Intrinsic::aarch64_sve_convert_to_svbool &&
2718 Pg->getArgOperand(0)->getType() == Op->getArgOperand(0)->getType()) {
2719 Value *Ops[] = {Pg->getArgOperand(0), Op->getArgOperand(0)};
2720 Type *Tys[] = {Pg->getArgOperand(0)->getType()};
2721
2722 auto *PTest = IC.Builder.CreateIntrinsic(II.getIntrinsicID(), Tys, Ops);
2723
2724 PTest->takeName(&II);
2725 return IC.replaceInstUsesWith(II, PTest);
2726 }
2727
2728 // Transform PTEST_ANY(X=OP(PG,...), X) -> PTEST_ANY(PG, X)).
2729 // Later optimizations may rewrite sequence to use the flag-setting variant
2730 // of instruction X to remove PTEST.
2731 if ((Pg == Op) && (II.getIntrinsicID() == Intrinsic::aarch64_sve_ptest_any) &&
2732 ((OpIID == Intrinsic::aarch64_sve_brka_z) ||
2733 (OpIID == Intrinsic::aarch64_sve_brkb_z) ||
2734 (OpIID == Intrinsic::aarch64_sve_brkpa_z) ||
2735 (OpIID == Intrinsic::aarch64_sve_brkpb_z) ||
2736 (OpIID == Intrinsic::aarch64_sve_rdffr_z) ||
2737 (OpIID == Intrinsic::aarch64_sve_and_z) ||
2738 (OpIID == Intrinsic::aarch64_sve_bic_z) ||
2739 (OpIID == Intrinsic::aarch64_sve_eor_z) ||
2740 (OpIID == Intrinsic::aarch64_sve_nand_z) ||
2741 (OpIID == Intrinsic::aarch64_sve_nor_z) ||
2742 (OpIID == Intrinsic::aarch64_sve_orn_z) ||
2743 (OpIID == Intrinsic::aarch64_sve_orr_z))) {
2744 Value *Ops[] = {Pg->getArgOperand(0), Pg};
2745 Type *Tys[] = {Pg->getType()};
2746
2747 auto *PTest = IC.Builder.CreateIntrinsic(II.getIntrinsicID(), Tys, Ops);
2748 PTest->takeName(&II);
2749
2750 return IC.replaceInstUsesWith(II, PTest);
2751 }
2752
2753 return std::nullopt;
2754}
2755
2756template <Intrinsic::ID MulOpc, Intrinsic::ID FuseOpc>
2757static std::optional<Instruction *>
2759 bool MergeIntoAddendOp) {
2760 Value *P = II.getOperand(0);
2761 Value *MulOp0, *MulOp1, *AddendOp, *Mul;
2762 if (MergeIntoAddendOp) {
2763 AddendOp = II.getOperand(1);
2764 Mul = II.getOperand(2);
2765 } else {
2766 AddendOp = II.getOperand(2);
2767 Mul = II.getOperand(1);
2768 }
2769
2771 m_Value(MulOp1))))
2772 return std::nullopt;
2773
2774 if (!Mul->hasOneUse())
2775 return std::nullopt;
2776
2777 Instruction *FMFSource = nullptr;
2778 if (II.getType()->isFPOrFPVectorTy()) {
2779 llvm::FastMathFlags FAddFlags = II.getFastMathFlags();
2780 // Stop the combine when the flags on the inputs differ in case dropping
2781 // flags would lead to us missing out on more beneficial optimizations.
2782 if (FAddFlags != cast<CallInst>(Mul)->getFastMathFlags())
2783 return std::nullopt;
2784 if (!FAddFlags.allowContract())
2785 return std::nullopt;
2786 FMFSource = &II;
2787 }
2788
2789 Value *Res;
2790 if (MergeIntoAddendOp)
2791 Res = IC.Builder.CreateIntrinsic(FuseOpc, {II.getType()},
2792 {P, AddendOp, MulOp0, MulOp1}, FMFSource);
2793 else
2794 Res = IC.Builder.CreateIntrinsic(FuseOpc, {II.getType()},
2795 {P, MulOp0, MulOp1, AddendOp}, FMFSource);
2796
2797 return IC.replaceInstUsesWith(II, Res);
2798}
2799
2800static std::optional<Instruction *>
2802 Value *Pred = II.getOperand(0);
2803 Value *PtrOp = II.getOperand(1);
2804 Type *VecTy = II.getType();
2805
2806 if (isAllActivePredicate(Pred)) {
2807 LoadInst *Load = IC.Builder.CreateLoad(VecTy, PtrOp);
2808 Load->copyMetadata(II);
2809 return IC.replaceInstUsesWith(II, Load);
2810 }
2811
2812 CallInst *MaskedLoad =
2813 IC.Builder.CreateMaskedLoad(VecTy, PtrOp, PtrOp->getPointerAlignment(DL),
2814 Pred, ConstantAggregateZero::get(VecTy));
2815 MaskedLoad->copyMetadata(II);
2816 return IC.replaceInstUsesWith(II, MaskedLoad);
2817}
2818
2819static std::optional<Instruction *>
2821 Value *VecOp = II.getOperand(0);
2822 Value *Pred = II.getOperand(1);
2823 Value *PtrOp = II.getOperand(2);
2824
2825 if (isAllActivePredicate(Pred)) {
2826 StoreInst *Store = IC.Builder.CreateStore(VecOp, PtrOp);
2827 Store->copyMetadata(II);
2828 return IC.eraseInstFromFunction(II);
2829 }
2830
2831 CallInst *MaskedStore = IC.Builder.CreateMaskedStore(
2832 VecOp, PtrOp, PtrOp->getPointerAlignment(DL), Pred);
2833 MaskedStore->copyMetadata(II);
2834 return IC.eraseInstFromFunction(II);
2835}
2836
2838 switch (Intrinsic) {
2839 case Intrinsic::aarch64_sve_fmul_u:
2840 return Instruction::BinaryOps::FMul;
2841 case Intrinsic::aarch64_sve_fadd_u:
2842 return Instruction::BinaryOps::FAdd;
2843 case Intrinsic::aarch64_sve_fsub_u:
2844 return Instruction::BinaryOps::FSub;
2845 default:
2846 return Instruction::BinaryOpsEnd;
2847 }
2848}
2849
2850static std::optional<Instruction *>
2852 // Bail due to missing support for ISD::STRICT_ scalable vector operations.
2853 if (II.isStrictFP())
2854 return std::nullopt;
2855
2856 auto *OpPredicate = II.getOperand(0);
2857 auto BinOpCode = intrinsicIDToBinOpCode(II.getIntrinsicID());
2858 if (BinOpCode == Instruction::BinaryOpsEnd ||
2859 !isAllActivePredicate(OpPredicate))
2860 return std::nullopt;
2861 auto BinOp = IC.Builder.CreateBinOpFMF(
2862 BinOpCode, II.getOperand(1), II.getOperand(2), II.getFastMathFlags());
2863 return IC.replaceInstUsesWith(II, BinOp);
2864}
2865
2866static std::optional<Instruction *>
2868 assert(II.getIntrinsicID() == Intrinsic::aarch64_sve_mla_u &&
2869 "Expected MLA_U intrinsic");
2870 Value *Acc = II.getArgOperand(1);
2871 Value *MulOp0 = II.getArgOperand(2);
2872 Value *MulOp1 = II.getArgOperand(3);
2873
2874 // For mla_u, inactive lanes are undefined, so it is valid to drop the
2875 // predicate when replacing mla_u(acc, x, 1) with add(acc, x) or
2876 // mla_u(acc, x, -1) with sub(acc, x).
2877 if (match(MulOp0, m_One()))
2878 return IC.replaceInstUsesWith(II, IC.Builder.CreateAdd(Acc, MulOp1));
2879 if (match(MulOp1, m_One()))
2880 return IC.replaceInstUsesWith(II, IC.Builder.CreateAdd(Acc, MulOp0));
2881 if (match(MulOp0, m_AllOnes()))
2882 return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Acc, MulOp1));
2883 if (match(MulOp1, m_AllOnes()))
2884 return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Acc, MulOp0));
2885
2886 if (isa<Constant>(MulOp0) && !isa<Constant>(MulOp1)) {
2887 II.setArgOperand(2, MulOp1);
2888 II.setArgOperand(3, MulOp0);
2889 return &II;
2890 }
2891
2892 return std::nullopt;
2893}
2894
2895static std::optional<Instruction *>
2897 assert((II.getIntrinsicID() == Intrinsic::aarch64_sve_sadalp ||
2898 II.getIntrinsicID() == Intrinsic::aarch64_sve_uadalp) &&
2899 "Expected SADALP or UADALP intrinsic");
2900
2901 // Simplify add(adalp(pg, zeroinitializer, in), wide_acc)
2902 // -> adalp(pg, wide_acc, in)
2903 auto *User = dyn_cast_or_null<Instruction>(II.getUniqueUndroppableUser());
2904 if (!User || !match(II.getArgOperand(1), m_Zero()))
2905 return std::nullopt;
2906
2907 Value *Acc;
2908 if (!match(User, m_c_Add(m_Specific(&II), m_Value(Acc))))
2909 return std::nullopt;
2910
2912 Value *PairwiseAddLong = IC.Builder.CreateIntrinsic(
2913 II.getIntrinsicID(), {II.getType()},
2914 {II.getArgOperand(0), Acc, II.getArgOperand(2)});
2915
2916 IC.replaceInstUsesWith(*User, PairwiseAddLong);
2918 return &II; // II is now trivially dead and will get erased.
2919}
2920
2921static std::optional<Instruction *> instCombineSVEVectorAdd(InstCombiner &IC,
2922 IntrinsicInst &II) {
2923 if (auto MLA = instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul,
2924 Intrinsic::aarch64_sve_mla>(
2925 IC, II, true))
2926 return MLA;
2927 if (auto MAD = instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul,
2928 Intrinsic::aarch64_sve_mad>(
2929 IC, II, false))
2930 return MAD;
2931 return std::nullopt;
2932}
2933
2934static std::optional<Instruction *>
2936 if (auto FMLA =
2937 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2938 Intrinsic::aarch64_sve_fmla>(IC, II,
2939 true))
2940 return FMLA;
2941 if (auto FMAD =
2942 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2943 Intrinsic::aarch64_sve_fmad>(IC, II,
2944 false))
2945 return FMAD;
2946 if (auto FMLA =
2947 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul_u,
2948 Intrinsic::aarch64_sve_fmla>(IC, II,
2949 true))
2950 return FMLA;
2951 return std::nullopt;
2952}
2953
2954static std::optional<Instruction *>
2956 if (auto FMLA =
2957 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2958 Intrinsic::aarch64_sve_fmla>(IC, II,
2959 true))
2960 return FMLA;
2961 if (auto FMAD =
2962 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2963 Intrinsic::aarch64_sve_fmad>(IC, II,
2964 false))
2965 return FMAD;
2966 if (auto FMLA_U =
2967 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul_u,
2968 Intrinsic::aarch64_sve_fmla_u>(
2969 IC, II, true))
2970 return FMLA_U;
2971 return instCombineSVEVectorBinOp(IC, II);
2972}
2973
2974static std::optional<Instruction *>
2976 if (auto FMLS =
2977 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2978 Intrinsic::aarch64_sve_fmls>(IC, II,
2979 true))
2980 return FMLS;
2981 if (auto FMSB =
2982 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2983 Intrinsic::aarch64_sve_fnmsb>(
2984 IC, II, false))
2985 return FMSB;
2986 if (auto FMLS =
2987 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul_u,
2988 Intrinsic::aarch64_sve_fmls>(IC, II,
2989 true))
2990 return FMLS;
2991 return std::nullopt;
2992}
2993
2994static std::optional<Instruction *>
2996 if (auto FMLS =
2997 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
2998 Intrinsic::aarch64_sve_fmls>(IC, II,
2999 true))
3000 return FMLS;
3001 if (auto FMSB =
3002 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul,
3003 Intrinsic::aarch64_sve_fnmsb>(
3004 IC, II, false))
3005 return FMSB;
3006 if (auto FMLS_U =
3007 instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_fmul_u,
3008 Intrinsic::aarch64_sve_fmls_u>(
3009 IC, II, true))
3010 return FMLS_U;
3011 return instCombineSVEVectorBinOp(IC, II);
3012}
3013
3014static std::optional<Instruction *> instCombineSVEVectorSub(InstCombiner &IC,
3015 IntrinsicInst &II) {
3016 if (auto MLS = instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul,
3017 Intrinsic::aarch64_sve_mls>(
3018 IC, II, true))
3019 return MLS;
3020 return std::nullopt;
3021}
3022
3023static std::optional<Instruction *> instCombineSVEUnpack(InstCombiner &IC,
3024 IntrinsicInst &II) {
3025 Value *UnpackArg = II.getArgOperand(0);
3026 auto *RetTy = cast<ScalableVectorType>(II.getType());
3027 bool IsSigned = II.getIntrinsicID() == Intrinsic::aarch64_sve_sunpkhi ||
3028 II.getIntrinsicID() == Intrinsic::aarch64_sve_sunpklo;
3029
3030 // Hi = uunpkhi(splat(X)) --> Hi = splat(extend(X))
3031 // Lo = uunpklo(splat(X)) --> Lo = splat(extend(X))
3032 if (auto *ScalarArg = getSplatValue(UnpackArg)) {
3033 ScalarArg =
3034 IC.Builder.CreateIntCast(ScalarArg, RetTy->getScalarType(), IsSigned);
3035 Value *NewVal =
3036 IC.Builder.CreateVectorSplat(RetTy->getElementCount(), ScalarArg);
3037 NewVal->takeName(&II);
3038 return IC.replaceInstUsesWith(II, NewVal);
3039 }
3040
3041 return std::nullopt;
3042}
3043static std::optional<Instruction *> instCombineSVETBL(InstCombiner &IC,
3044 IntrinsicInst &II) {
3045 auto *OpVal = II.getOperand(0);
3046 auto *OpIndices = II.getOperand(1);
3047 VectorType *VTy = cast<VectorType>(II.getType());
3048
3049 // Check whether OpIndices is a constant splat value < minimal element count
3050 // of result.
3051 auto *SplatValue = dyn_cast_or_null<ConstantInt>(getSplatValue(OpIndices));
3052 if (!SplatValue ||
3053 SplatValue->getValue().uge(VTy->getElementCount().getKnownMinValue()))
3054 return std::nullopt;
3055
3056 // Convert sve_tbl(OpVal sve_dup_x(SplatValue)) to
3057 // splat_vector(extractelement(OpVal, SplatValue)) for further optimization.
3058 auto *Extract = IC.Builder.CreateExtractElement(OpVal, SplatValue);
3059 auto *VectorSplat =
3060 IC.Builder.CreateVectorSplat(VTy->getElementCount(), Extract);
3061
3062 VectorSplat->takeName(&II);
3063 return IC.replaceInstUsesWith(II, VectorSplat);
3064}
3065
3066static std::optional<Instruction *> instCombineSVEUzp1(InstCombiner &IC,
3067 IntrinsicInst &II) {
3068 Value *A, *B;
3069 Type *RetTy = II.getType();
3070 constexpr Intrinsic::ID FromSVB = Intrinsic::aarch64_sve_convert_from_svbool;
3071 constexpr Intrinsic::ID ToSVB = Intrinsic::aarch64_sve_convert_to_svbool;
3072
3073 // uzp1(to_svbool(A), to_svbool(B)) --> <A, B>
3074 // uzp1(from_svbool(to_svbool(A)), from_svbool(to_svbool(B))) --> <A, B>
3075 if ((match(II.getArgOperand(0),
3077 match(II.getArgOperand(1),
3079 (match(II.getArgOperand(0), m_Intrinsic<ToSVB>(m_Value(A))) &&
3080 match(II.getArgOperand(1), m_Intrinsic<ToSVB>(m_Value(B))))) {
3081 auto *TyA = cast<ScalableVectorType>(A->getType());
3082 if (TyA == B->getType() &&
3084 auto *SubVec = IC.Builder.CreateInsertVector(
3085 RetTy, PoisonValue::get(RetTy), A, uint64_t(0));
3086 auto *ConcatVec = IC.Builder.CreateInsertVector(RetTy, SubVec, B,
3087 TyA->getMinNumElements());
3088 ConcatVec->takeName(&II);
3089 return IC.replaceInstUsesWith(II, ConcatVec);
3090 }
3091 }
3092
3093 return std::nullopt;
3094}
3095
3096static std::optional<Instruction *> instCombineSVEZip(InstCombiner &IC,
3097 IntrinsicInst &II) {
3098 // zip1(uzp1(A, B), uzp2(A, B)) --> A
3099 // zip2(uzp1(A, B), uzp2(A, B)) --> B
3100 Value *A, *B;
3101 if (match(II.getArgOperand(0),
3104 m_Specific(A), m_Specific(B))))
3105 return IC.replaceInstUsesWith(
3106 II, (II.getIntrinsicID() == Intrinsic::aarch64_sve_zip1 ? A : B));
3107
3108 return std::nullopt;
3109}
3110
3111static std::optional<Instruction *>
3113 Value *Mask = II.getOperand(0);
3114 Value *BasePtr = II.getOperand(1);
3115 Value *Index = II.getOperand(2);
3116 Type *Ty = II.getType();
3117 Value *PassThru = ConstantAggregateZero::get(Ty);
3118
3119 // Contiguous gather => masked load.
3120 // (sve.ld1.gather.index Mask BasePtr (sve.index IndexBase 1))
3121 // => (masked.load (gep BasePtr IndexBase) Align Mask zeroinitializer)
3122 Value *IndexBase;
3124 m_One()))) {
3125 Align Alignment =
3126 BasePtr->getPointerAlignment(II.getDataLayout());
3127
3128 Value *Ptr = IC.Builder.CreateGEP(cast<VectorType>(Ty)->getElementType(),
3129 BasePtr, IndexBase);
3130 CallInst *MaskedLoad =
3131 IC.Builder.CreateMaskedLoad(Ty, Ptr, Alignment, Mask, PassThru);
3132 MaskedLoad->takeName(&II);
3133 return IC.replaceInstUsesWith(II, MaskedLoad);
3134 }
3135
3136 return std::nullopt;
3137}
3138
3139static std::optional<Instruction *>
3141 Value *Val = II.getOperand(0);
3142 Value *Mask = II.getOperand(1);
3143 Value *BasePtr = II.getOperand(2);
3144 Value *Index = II.getOperand(3);
3145 Type *Ty = Val->getType();
3146
3147 // Contiguous scatter => masked store.
3148 // (sve.st1.scatter.index Value Mask BasePtr (sve.index IndexBase 1))
3149 // => (masked.store Value (gep BasePtr IndexBase) Align Mask)
3150 Value *IndexBase;
3152 m_One()))) {
3153 Align Alignment =
3154 BasePtr->getPointerAlignment(II.getDataLayout());
3155
3156 Value *Ptr = IC.Builder.CreateGEP(cast<VectorType>(Ty)->getElementType(),
3157 BasePtr, IndexBase);
3158 (void)IC.Builder.CreateMaskedStore(Val, Ptr, Alignment, Mask);
3159
3160 return IC.eraseInstFromFunction(II);
3161 }
3162
3163 return std::nullopt;
3164}
3165
3166static std::optional<Instruction *> instCombineSVESDIV(InstCombiner &IC,
3167 IntrinsicInst &II) {
3168 Type *Int32Ty = IC.Builder.getInt32Ty();
3169 Value *Pred = II.getOperand(0);
3170 Value *Vec = II.getOperand(1);
3171 Value *DivVec = II.getOperand(2);
3172
3173 Value *SplatValue = getSplatValue(DivVec);
3174 ConstantInt *SplatConstantInt = dyn_cast_or_null<ConstantInt>(SplatValue);
3175 if (!SplatConstantInt)
3176 return std::nullopt;
3177
3178 APInt Divisor = SplatConstantInt->getValue();
3179 const int64_t DivisorValue = Divisor.getSExtValue();
3180 if (DivisorValue == -1)
3181 return std::nullopt;
3182 if (DivisorValue == 1)
3183 IC.replaceInstUsesWith(II, Vec);
3184
3185 if (Divisor.isPowerOf2()) {
3186 Constant *DivisorLog2 = ConstantInt::get(Int32Ty, Divisor.logBase2());
3187 auto ASRD = IC.Builder.CreateIntrinsic(
3188 Intrinsic::aarch64_sve_asrd, {II.getType()}, {Pred, Vec, DivisorLog2});
3189 return IC.replaceInstUsesWith(II, ASRD);
3190 }
3191 if (Divisor.isNegatedPowerOf2()) {
3192 Divisor.negate();
3193 Constant *DivisorLog2 = ConstantInt::get(Int32Ty, Divisor.logBase2());
3194 auto ASRD = IC.Builder.CreateIntrinsic(
3195 Intrinsic::aarch64_sve_asrd, {II.getType()}, {Pred, Vec, DivisorLog2});
3196 auto NEG = IC.Builder.CreateIntrinsic(
3197 Intrinsic::aarch64_sve_neg, {ASRD->getType()}, {ASRD, Pred, ASRD});
3198 return IC.replaceInstUsesWith(II, NEG);
3199 }
3200
3201 return std::nullopt;
3202}
3203
3204bool SimplifyValuePattern(SmallVector<Value *> &Vec, bool AllowPoison) {
3205 size_t VecSize = Vec.size();
3206 if (VecSize == 1)
3207 return true;
3208 if (!isPowerOf2_64(VecSize))
3209 return false;
3210 size_t HalfVecSize = VecSize / 2;
3211
3212 for (auto LHS = Vec.begin(), RHS = Vec.begin() + HalfVecSize;
3213 RHS != Vec.end(); LHS++, RHS++) {
3214 if (*LHS != nullptr && *RHS != nullptr) {
3215 if (*LHS == *RHS)
3216 continue;
3217 else
3218 return false;
3219 }
3220 if (!AllowPoison)
3221 return false;
3222 if (*LHS == nullptr && *RHS != nullptr)
3223 *LHS = *RHS;
3224 }
3225
3226 Vec.resize(HalfVecSize);
3227 SimplifyValuePattern(Vec, AllowPoison);
3228 return true;
3229}
3230
3231// Try to simplify dupqlane patterns like dupqlane(f32 A, f32 B, f32 A, f32 B)
3232// to dupqlane(f64(C)) where C is A concatenated with B
3233static std::optional<Instruction *> instCombineSVEDupqLane(InstCombiner &IC,
3234 IntrinsicInst &II) {
3235 Value *CurrentInsertElt = nullptr, *Default = nullptr;
3236 if (!match(II.getOperand(0),
3238 m_Value(Default), m_Value(CurrentInsertElt), m_Value())) ||
3239 !isa<FixedVectorType>(CurrentInsertElt->getType()))
3240 return std::nullopt;
3241 auto IIScalableTy = cast<ScalableVectorType>(II.getType());
3242
3243 // Insert the scalars into a container ordered by InsertElement index
3244 SmallVector<Value *> Elts(IIScalableTy->getMinNumElements(), nullptr);
3245 while (auto InsertElt = dyn_cast<InsertElementInst>(CurrentInsertElt)) {
3246 auto Idx = cast<ConstantInt>(InsertElt->getOperand(2));
3247 Elts[Idx->getValue().getZExtValue()] = InsertElt->getOperand(1);
3248 CurrentInsertElt = InsertElt->getOperand(0);
3249 }
3250
3251 bool AllowPoison =
3252 isa<PoisonValue>(CurrentInsertElt) && isa<PoisonValue>(Default);
3253 if (!SimplifyValuePattern(Elts, AllowPoison))
3254 return std::nullopt;
3255
3256 // Rebuild the simplified chain of InsertElements. e.g. (a, b, a, b) as (a, b)
3257 Value *InsertEltChain = PoisonValue::get(CurrentInsertElt->getType());
3258 for (size_t I = 0; I < Elts.size(); I++) {
3259 if (Elts[I] == nullptr)
3260 continue;
3261 InsertEltChain = IC.Builder.CreateInsertElement(InsertEltChain, Elts[I],
3262 IC.Builder.getInt64(I));
3263 }
3264 if (InsertEltChain == nullptr)
3265 return std::nullopt;
3266
3267 // Splat the simplified sequence, e.g. (f16 a, f16 b, f16 c, f16 d) as one i64
3268 // value or (f16 a, f16 b) as one i32 value. This requires an InsertSubvector
3269 // be bitcast to a type wide enough to fit the sequence, be splatted, and then
3270 // be narrowed back to the original type.
3271 unsigned PatternWidth = IIScalableTy->getScalarSizeInBits() * Elts.size();
3272 unsigned PatternElementCount = IIScalableTy->getScalarSizeInBits() *
3273 IIScalableTy->getMinNumElements() /
3274 PatternWidth;
3275
3276 IntegerType *WideTy = IC.Builder.getIntNTy(PatternWidth);
3277 auto *WideScalableTy = ScalableVectorType::get(WideTy, PatternElementCount);
3278 auto *WideShuffleMaskTy =
3279 ScalableVectorType::get(IC.Builder.getInt32Ty(), PatternElementCount);
3280
3281 auto InsertSubvector = IC.Builder.CreateInsertVector(
3282 II.getType(), PoisonValue::get(II.getType()), InsertEltChain,
3283 uint64_t(0));
3284 auto WideBitcast =
3285 IC.Builder.CreateBitOrPointerCast(InsertSubvector, WideScalableTy);
3286 auto WideShuffleMask = ConstantAggregateZero::get(WideShuffleMaskTy);
3287 auto WideShuffle = IC.Builder.CreateShuffleVector(
3288 WideBitcast, PoisonValue::get(WideScalableTy), WideShuffleMask);
3289 auto NarrowBitcast =
3290 IC.Builder.CreateBitOrPointerCast(WideShuffle, II.getType());
3291
3292 return IC.replaceInstUsesWith(II, NarrowBitcast);
3293}
3294
3295static std::optional<Instruction *> instCombineMaxMinNM(InstCombiner &IC,
3296 IntrinsicInst &II) {
3297 Value *A = II.getArgOperand(0);
3298 Value *B = II.getArgOperand(1);
3299 if (A == B)
3300 return IC.replaceInstUsesWith(II, A);
3301
3302 return std::nullopt;
3303}
3304
3305static std::optional<Instruction *> instCombineSVESrshl(InstCombiner &IC,
3306 IntrinsicInst &II) {
3307 Value *Pred = II.getOperand(0);
3308 Value *Vec = II.getOperand(1);
3309 Value *Shift = II.getOperand(2);
3310
3311 // Convert SRSHL into the simpler LSL intrinsic when fed by an ABS intrinsic.
3312 Value *AbsPred, *MergedValue;
3314 m_Value(MergedValue), m_Value(AbsPred), m_Value())) &&
3316 m_Value(MergedValue), m_Value(AbsPred), m_Value())))
3317
3318 return std::nullopt;
3319
3320 // Transform is valid if any of the following are true:
3321 // * The ABS merge value is an undef or non-negative
3322 // * The ABS predicate is all active
3323 // * The ABS predicate and the SRSHL predicates are the same
3324 if (!isa<UndefValue>(MergedValue) && !match(MergedValue, m_NonNegative()) &&
3325 AbsPred != Pred && !isAllActivePredicate(AbsPred))
3326 return std::nullopt;
3327
3328 // Only valid when the shift amount is non-negative, otherwise the rounding
3329 // behaviour of SRSHL cannot be ignored.
3330 if (!match(Shift, m_NonNegative()))
3331 return std::nullopt;
3332
3333 auto LSL = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_lsl,
3334 {II.getType()}, {Pred, Vec, Shift});
3335
3336 return IC.replaceInstUsesWith(II, LSL);
3337}
3338
3339static std::optional<Instruction *> instCombineSVEInsr(InstCombiner &IC,
3340 IntrinsicInst &II) {
3341 Value *Vec = II.getOperand(0);
3342
3343 if (getSplatValue(Vec) == II.getOperand(1))
3344 return IC.replaceInstUsesWith(II, Vec);
3345
3346 return std::nullopt;
3347}
3348
3349static std::optional<Instruction *> instCombineDMB(InstCombiner &IC,
3350 IntrinsicInst &II) {
3351 // If this barrier is post-dominated by identical one we can remove it
3352 auto *NI = II.getNextNode();
3353 unsigned LookaheadThreshold = DMBLookaheadThreshold;
3354 auto CanSkipOver = [](Instruction *I) {
3355 return !I->mayReadOrWriteMemory() && !I->mayHaveSideEffects();
3356 };
3357 while (LookaheadThreshold-- && CanSkipOver(NI)) {
3358 auto *NIBB = NI->getParent();
3359 NI = NI->getNextNode();
3360 if (!NI) {
3361 if (auto *SuccBB = NIBB->getUniqueSuccessor())
3362 NI = &*SuccBB->getFirstNonPHIOrDbgOrLifetime();
3363 else
3364 break;
3365 }
3366 }
3367 auto *NextII = dyn_cast_or_null<IntrinsicInst>(NI);
3368 if (NextII && II.isIdenticalTo(NextII))
3369 return IC.eraseInstFromFunction(II);
3370
3371 return std::nullopt;
3372}
3373
3374static std::optional<Instruction *> instCombineWhilelo(InstCombiner &IC,
3375 IntrinsicInst &II) {
3376 return IC.replaceInstUsesWith(
3377 II,
3378 IC.Builder.CreateIntrinsic(Intrinsic::get_active_lane_mask,
3379 {II.getType(), II.getOperand(0)->getType()},
3380 {II.getOperand(0), II.getOperand(1)}));
3381}
3382
3383static std::optional<Instruction *> instCombinePTrue(InstCombiner &IC,
3384 IntrinsicInst &II) {
3385 unsigned PredPattern = cast<ConstantInt>(II.getOperand(0))->getZExtValue();
3386 // SVE vector length is a power-of-two, thus pow2 is synonymous with all.
3387 if (PredPattern == AArch64SVEPredPattern::all ||
3388 PredPattern == AArch64SVEPredPattern::pow2)
3389 return IC.replaceInstUsesWith(II, ConstantInt::getTrue(II.getType()));
3390 return std::nullopt;
3391}
3392
3393static std::optional<Instruction *> instCombineSVEUxt(InstCombiner &IC,
3395 unsigned NumBits) {
3396 Value *Passthru = II.getOperand(0);
3397 Value *Pg = II.getOperand(1);
3398 Value *Op = II.getOperand(2);
3399
3400 // Convert UXT[BHW] to AND.
3401 if (isa<UndefValue>(Passthru) || isAllActivePredicate(Pg)) {
3402 auto *Ty = cast<VectorType>(II.getType());
3403 auto MaskValue = APInt::getLowBitsSet(Ty->getScalarSizeInBits(), NumBits);
3404 auto *Mask = ConstantInt::get(Ty, MaskValue);
3405 auto *And = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_and_u, {Ty},
3406 {Pg, Op, Mask});
3407 return IC.replaceInstUsesWith(II, And);
3408 }
3409
3410 return std::nullopt;
3411}
3412
3413static std::optional<Instruction *>
3415 SMEAttrs FnSMEAttrs(*II.getFunction());
3416 bool IsStreaming = FnSMEAttrs.hasStreamingInterfaceOrBody();
3417 if (IsStreaming || !FnSMEAttrs.hasStreamingCompatibleInterface())
3418 return IC.replaceInstUsesWith(
3419 II, ConstantInt::getBool(II.getType(), IsStreaming));
3420 return std::nullopt;
3421}
3422
3423static std::optional<Instruction *> instCombineSVEUMin(InstCombiner &IC,
3424 IntrinsicInst &II) {
3425 // umin(umin(A, 1), umin(B, 1)) -> umin(umin(A,B), 1)
3426 constexpr Intrinsic::ID UMinID = Intrinsic::aarch64_sve_umin_u;
3427 Value *A, *B;
3428 Value *Pg = II.getOperand(0);
3429 if (match(II.getOperand(1), m_OneUse(m_Intrinsic<UMinID>(
3430 m_Specific(Pg), m_Value(A), m_One()))) &&
3431 match(II.getOperand(2), m_OneUse(m_Intrinsic<UMinID>(
3432 m_Specific(Pg), m_Value(B), m_One())))) {
3433 Value *NewUMin =
3434 IC.Builder.CreateIntrinsic(UMinID, II.getType(), {Pg, A, B});
3435 Value *NewLogicalUMin = IC.Builder.CreateIntrinsic(
3436 UMinID, II.getType(), {Pg, NewUMin, ConstantInt::get(II.getType(), 1)});
3437 return IC.replaceInstUsesWith(II, NewLogicalUMin);
3438 }
3439
3440 // umin(umin(A, 1), 1) -> umin(A, 1)
3441 if (match(II.getOperand(1),
3443 match(II.getOperand(2), m_One()))
3444 return IC.replaceInstUsesWith(II, II.getOperand(1));
3445
3446 return std::nullopt;
3447}
3448
3449static std::optional<Instruction *> instCombineSVEOrr(InstCombiner &IC,
3450 IntrinsicInst &II) {
3451 // orr(umin(A, 1), umin(B, 1)) -> umin(orr(A, B), 1)
3452 constexpr Intrinsic::ID UMinID = Intrinsic::aarch64_sve_umin_u;
3453 Value *Pg = II.getOperand(0);
3454
3455 Value *A, *B;
3456 if (!match(II.getOperand(1), m_OneUse(m_Intrinsic<UMinID>(
3457 m_Specific(Pg), m_Value(A), m_One()))) ||
3458 !match(II.getOperand(2), m_OneUse(m_Intrinsic<UMinID>(
3459 m_Specific(Pg), m_Value(B), m_One()))))
3460 return std::nullopt;
3461
3462 Value *NewOrr = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_orr_u,
3463 II.getType(), {Pg, A, B});
3464 Value *NewUMin = IC.Builder.CreateIntrinsic(
3465 UMinID, II.getType(), {Pg, NewOrr, ConstantInt::get(II.getType(), 1)});
3466 return IC.replaceInstUsesWith(II, NewUMin);
3467}
3468
3469static std::optional<Instruction *> instCombineSVEAnd(InstCombiner &IC,
3470 IntrinsicInst &II) {
3471 // and(cmphs(pg, ConstA, A), cmphs(pg, A, ConstB))
3472 // ->
3473 // cmphs(pg, ConstA - ConstB, sub(pg, A, ConstB))
3474 constexpr Intrinsic::ID CmphsID = Intrinsic::aarch64_sve_cmphs;
3475 Value *Pg = II.getOperand(0);
3476 Value *LHS = II.getOperand(1);
3477 Value *RHS = II.getOperand(2);
3478
3479 Value *A, *PgLHS, *PgRHS;
3480 uint64_t ConstA, ConstB;
3481 if (!match(LHS, m_Intrinsic<CmphsID>(m_Value(PgLHS), m_ConstantInt(ConstA),
3482 m_Value(A))) ||
3484 m_ConstantInt(ConstB))) ||
3485 !LHS->hasOneUser() || !RHS->hasOneUser())
3486 return std::nullopt;
3487
3488 // Always false regardless of predication
3489 if (ConstB > ConstA)
3490 return IC.replaceInstUsesWith(II, Constant::getNullValue(II.getType()));
3491
3492 // The predicate for both CMPHSs must match.
3493 // The predicate for the AND can either be equal to the CMPHS predicates, or
3494 // either of the CMPHS values.
3495 if (PgLHS != PgRHS || (Pg != LHS && Pg != RHS && Pg != PgLHS))
3496 return std::nullopt;
3497
3498 Type *VecTy = A->getType();
3499 Constant *Base = ConstantInt::get(VecTy, ConstB);
3500 Value *Sub = IC.Builder.CreateIntrinsic(Intrinsic::aarch64_sve_sub_u, VecTy,
3501 {PgLHS, A, Base});
3502 Constant *Limit = ConstantInt::get(VecTy, ConstA - ConstB);
3503 Value *NewCmphs =
3504 IC.Builder.CreateIntrinsic(CmphsID, VecTy, {PgLHS, Limit, Sub});
3505
3506 return IC.replaceInstUsesWith(II, NewCmphs);
3507}
3508
3509std::optional<Instruction *>
3511 IntrinsicInst &II) const {
3513 if (std::optional<Instruction *> I = simplifySVEIntrinsic(IC, II, IInfo))
3514 return I;
3515
3516 Intrinsic::ID IID = II.getIntrinsicID();
3517 switch (IID) {
3518 default:
3519 break;
3520 case Intrinsic::aarch64_dmb:
3521 return instCombineDMB(IC, II);
3522 case Intrinsic::aarch64_neon_fmaxnm:
3523 case Intrinsic::aarch64_neon_fminnm:
3524 return instCombineMaxMinNM(IC, II);
3525 case Intrinsic::aarch64_sve_convert_from_svbool:
3526 return instCombineConvertFromSVBool(IC, II);
3527 case Intrinsic::aarch64_sve_dup:
3528 return instCombineSVEDup(IC, II);
3529 case Intrinsic::aarch64_sve_dup_x:
3530 return instCombineSVEDupX(IC, II);
3531 case Intrinsic::aarch64_sve_cmpeq:
3532 case Intrinsic::aarch64_sve_cmpeq_wide:
3533 return instCombineXorSVECmpCC(IC, II);
3534 case Intrinsic::aarch64_sve_cmpne:
3535 case Intrinsic::aarch64_sve_cmpne_wide:
3536 return instCombineSVECmpNE(IC, II);
3537 case Intrinsic::aarch64_sve_rdffr:
3538 return instCombineRDFFR(IC, II);
3539 case Intrinsic::aarch64_sve_lasta:
3540 case Intrinsic::aarch64_sve_lastb:
3541 return instCombineSVELast(IC, II);
3542 case Intrinsic::aarch64_sve_clasta_n:
3543 case Intrinsic::aarch64_sve_clastb_n:
3544 return instCombineSVECondLast(IC, II);
3545 case Intrinsic::aarch64_sve_cntd:
3546 return instCombineSVECntElts(IC, II, 2);
3547 case Intrinsic::aarch64_sve_cntw:
3548 return instCombineSVECntElts(IC, II, 4);
3549 case Intrinsic::aarch64_sve_cnth:
3550 return instCombineSVECntElts(IC, II, 8);
3551 case Intrinsic::aarch64_sve_cntb:
3552 return instCombineSVECntElts(IC, II, 16);
3553 case Intrinsic::aarch64_sme_cntsd:
3554 return instCombineSMECntsd(IC, II, ST);
3555 case Intrinsic::aarch64_sve_ptest_any:
3556 case Intrinsic::aarch64_sve_ptest_first:
3557 case Intrinsic::aarch64_sve_ptest_last:
3558 return instCombineSVEPTest(IC, II);
3559 case Intrinsic::aarch64_sve_fadd:
3560 return instCombineSVEVectorFAdd(IC, II);
3561 case Intrinsic::aarch64_sve_fadd_u:
3562 return instCombineSVEVectorFAddU(IC, II);
3563 case Intrinsic::aarch64_sve_fmul_u:
3564 return instCombineSVEVectorBinOp(IC, II);
3565 case Intrinsic::aarch64_sve_fsub:
3566 return instCombineSVEVectorFSub(IC, II);
3567 case Intrinsic::aarch64_sve_fsub_u:
3568 return instCombineSVEVectorFSubU(IC, II);
3569 case Intrinsic::aarch64_sve_add:
3570 return instCombineSVEVectorAdd(IC, II);
3571 case Intrinsic::aarch64_sve_add_u:
3572 return instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul_u,
3573 Intrinsic::aarch64_sve_mla_u>(
3574 IC, II, true);
3575 case Intrinsic::aarch64_sve_mla_u:
3576 return instCombineSVEVectorMlaU(IC, II);
3577 case Intrinsic::aarch64_sve_sadalp:
3578 case Intrinsic::aarch64_sve_uadalp:
3580 case Intrinsic::aarch64_sve_sub:
3581 return instCombineSVEVectorSub(IC, II);
3582 case Intrinsic::aarch64_sve_sub_u:
3583 return instCombineSVEVectorFuseMulAddSub<Intrinsic::aarch64_sve_mul_u,
3584 Intrinsic::aarch64_sve_mls_u>(
3585 IC, II, true);
3586 case Intrinsic::aarch64_sve_tbl:
3587 return instCombineSVETBL(IC, II);
3588 case Intrinsic::aarch64_sve_uunpkhi:
3589 case Intrinsic::aarch64_sve_uunpklo:
3590 case Intrinsic::aarch64_sve_sunpkhi:
3591 case Intrinsic::aarch64_sve_sunpklo:
3592 return instCombineSVEUnpack(IC, II);
3593 case Intrinsic::aarch64_sve_uzp1:
3594 return instCombineSVEUzp1(IC, II);
3595 case Intrinsic::aarch64_sve_zip1:
3596 case Intrinsic::aarch64_sve_zip2:
3597 return instCombineSVEZip(IC, II);
3598 case Intrinsic::aarch64_sve_ld1_gather_index:
3599 return instCombineLD1GatherIndex(IC, II);
3600 case Intrinsic::aarch64_sve_st1_scatter_index:
3601 return instCombineST1ScatterIndex(IC, II);
3602 case Intrinsic::aarch64_sve_ld1:
3603 return instCombineSVELD1(IC, II, DL);
3604 case Intrinsic::aarch64_sve_st1:
3605 return instCombineSVEST1(IC, II, DL);
3606 case Intrinsic::aarch64_sve_sdiv:
3607 return instCombineSVESDIV(IC, II);
3608 case Intrinsic::aarch64_sve_sel:
3609 return instCombineSVESel(IC, II);
3610 case Intrinsic::aarch64_sve_srshl:
3611 return instCombineSVESrshl(IC, II);
3612 case Intrinsic::aarch64_sve_dupq_lane:
3613 return instCombineSVEDupqLane(IC, II);
3614 case Intrinsic::aarch64_sve_insr:
3615 return instCombineSVEInsr(IC, II);
3616 case Intrinsic::aarch64_sve_whilelo:
3617 return instCombineWhilelo(IC, II);
3618 case Intrinsic::aarch64_sve_ptrue:
3619 return instCombinePTrue(IC, II);
3620 case Intrinsic::aarch64_sve_uxtb:
3621 return instCombineSVEUxt(IC, II, 8);
3622 case Intrinsic::aarch64_sve_uxth:
3623 return instCombineSVEUxt(IC, II, 16);
3624 case Intrinsic::aarch64_sve_uxtw:
3625 return instCombineSVEUxt(IC, II, 32);
3626 case Intrinsic::aarch64_sme_in_streaming_mode:
3627 return instCombineInStreamingMode(IC, II);
3628 case Intrinsic::aarch64_sve_umin_u:
3629 return instCombineSVEUMin(IC, II);
3630 case Intrinsic::aarch64_sve_orr_u:
3631 return instCombineSVEOrr(IC, II);
3632 case Intrinsic::aarch64_sve_and_z:
3633 return instCombineSVEAnd(IC, II);
3634 }
3635
3636 return std::nullopt;
3637}
3638
3640 InstCombiner &IC, IntrinsicInst &II, APInt OrigDemandedElts,
3641 APInt &UndefElts, APInt &UndefElts2, APInt &UndefElts3,
3642 std::function<void(Instruction *, unsigned, APInt, APInt &)>
3643 SimplifyAndSetOp) const {
3644 switch (II.getIntrinsicID()) {
3645 default:
3646 break;
3647 case Intrinsic::aarch64_neon_fcvtxn:
3648 case Intrinsic::aarch64_neon_rshrn:
3649 case Intrinsic::aarch64_neon_sqrshrn:
3650 case Intrinsic::aarch64_neon_sqrshrun:
3651 case Intrinsic::aarch64_neon_sqshrn:
3652 case Intrinsic::aarch64_neon_sqshrun:
3653 case Intrinsic::aarch64_neon_sqxtn:
3654 case Intrinsic::aarch64_neon_sqxtun:
3655 case Intrinsic::aarch64_neon_uqrshrn:
3656 case Intrinsic::aarch64_neon_uqshrn:
3657 case Intrinsic::aarch64_neon_uqxtn:
3658 SimplifyAndSetOp(&II, 0, OrigDemandedElts, UndefElts);
3659 break;
3660 }
3661
3662 return std::nullopt;
3663}
3664
3666 return ST->isSVEAvailable() || (ST->isSVEorStreamingSVEAvailable() &&
3668}
3669
3672 switch (K) {
3674 return TypeSize::getFixed(64);
3676 if (ST->useSVEForFixedLengthVectors() &&
3677 (ST->isSVEAvailable() || EnableFixedwidthAutovecInStreamingMode))
3678 return TypeSize::getFixed(
3679 std::max(ST->getMinSVEVectorSizeInBits(), 128u));
3680 else if (ST->isNeonAvailable())
3681 return TypeSize::getFixed(128);
3682 else
3683 return TypeSize::getFixed(0);
3685 if (ST->isSVEAvailable() || (ST->isSVEorStreamingSVEAvailable() &&
3687 return TypeSize::getScalable(128);
3688 else
3689 return TypeSize::getScalable(0);
3690 }
3691 llvm_unreachable("Unsupported register kind");
3692}
3693
3694bool AArch64TTIImpl::isSingleExtWideningInstruction(
3695 unsigned Opcode, Type *DstTy, ArrayRef<const Value *> Args,
3696 Type *SrcOverrideTy) const {
3697 // A helper that returns a vector type from the given type. The number of
3698 // elements in type Ty determines the vector width.
3699 auto toVectorTy = [&](Type *ArgTy) {
3700 return VectorType::get(ArgTy->getScalarType(),
3701 cast<VectorType>(DstTy)->getElementCount());
3702 };
3703
3704 // Exit early if DstTy is not a vector type whose elements are one of [i16,
3705 // i32, i64]. SVE doesn't generally have the same set of instructions to
3706 // perform an extend with the add/sub/mul. There are SMULLB style
3707 // instructions, but they operate on top/bottom, requiring some sort of lane
3708 // interleaving to be used with zext/sext.
3709 unsigned DstEltSize = DstTy->getScalarSizeInBits();
3710 if (!useNeonVector(DstTy) || Args.size() != 2 ||
3711 (DstEltSize != 16 && DstEltSize != 32 && DstEltSize != 64))
3712 return false;
3713
3714 Type *SrcTy = SrcOverrideTy;
3715 switch (Opcode) {
3716 case Instruction::Add: // UADDW(2), SADDW(2).
3717 case Instruction::Sub: { // USUBW(2), SSUBW(2).
3718 // The second operand needs to be an extend
3719 if (isa<SExtInst>(Args[1]) || isa<ZExtInst>(Args[1])) {
3720 if (!SrcTy)
3721 SrcTy =
3722 toVectorTy(cast<Instruction>(Args[1])->getOperand(0)->getType());
3723 break;
3724 }
3725
3726 if (Opcode == Instruction::Sub)
3727 return false;
3728
3729 // UADDW(2), SADDW(2) can be commutted.
3730 if (isa<SExtInst>(Args[0]) || isa<ZExtInst>(Args[0])) {
3731 if (!SrcTy)
3732 SrcTy =
3733 toVectorTy(cast<Instruction>(Args[0])->getOperand(0)->getType());
3734 break;
3735 }
3736 return false;
3737 }
3738 default:
3739 return false;
3740 }
3741
3742 // Legalize the destination type and ensure it can be used in a widening
3743 // operation.
3744 auto DstTyL = getTypeLegalizationCost(DstTy);
3745 if (!DstTyL.second.isVector() || DstEltSize != DstTy->getScalarSizeInBits())
3746 return false;
3747
3748 // Legalize the source type and ensure it can be used in a widening
3749 // operation.
3750 assert(SrcTy && "Expected some SrcTy");
3751 auto SrcTyL = getTypeLegalizationCost(SrcTy);
3752 unsigned SrcElTySize = SrcTyL.second.getScalarSizeInBits();
3753 if (!SrcTyL.second.isVector() || SrcElTySize != SrcTy->getScalarSizeInBits())
3754 return false;
3755
3756 // Get the total number of vector elements in the legalized types.
3757 InstructionCost NumDstEls =
3758 DstTyL.first * DstTyL.second.getVectorMinNumElements();
3759 InstructionCost NumSrcEls =
3760 SrcTyL.first * SrcTyL.second.getVectorMinNumElements();
3761
3762 // Return true if the legalized types have the same number of vector elements
3763 // and the destination element type size is twice that of the source type.
3764 return NumDstEls == NumSrcEls && 2 * SrcElTySize == DstEltSize;
3765}
3766
3767Type *AArch64TTIImpl::isBinExtWideningInstruction(unsigned Opcode, Type *DstTy,
3769 Type *SrcOverrideTy) const {
3770 if (Opcode != Instruction::Add && Opcode != Instruction::Sub &&
3771 Opcode != Instruction::Mul)
3772 return nullptr;
3773
3774 // Exit early if DstTy is not a vector type whose elements are one of [i16,
3775 // i32, i64]. SVE doesn't generally have the same set of instructions to
3776 // perform an extend with the add/sub/mul. There are SMULLB style
3777 // instructions, but they operate on top/bottom, requiring some sort of lane
3778 // interleaving to be used with zext/sext.
3779 unsigned DstEltSize = DstTy->getScalarSizeInBits();
3780 if (!useNeonVector(DstTy) || Args.size() != 2 ||
3781 (DstEltSize != 16 && DstEltSize != 32 && DstEltSize != 64))
3782 return nullptr;
3783
3784 auto getScalarSizeWithOverride = [&](const Value *V) {
3785 if (SrcOverrideTy)
3786 return SrcOverrideTy->getScalarSizeInBits();
3787 return cast<Instruction>(V)
3788 ->getOperand(0)
3789 ->getType()
3790 ->getScalarSizeInBits();
3791 };
3792
3793 unsigned MaxEltSize = 0;
3794 if ((isa<SExtInst>(Args[0]) && isa<SExtInst>(Args[1])) ||
3795 (isa<ZExtInst>(Args[0]) && isa<ZExtInst>(Args[1]))) {
3796 unsigned EltSize0 = getScalarSizeWithOverride(Args[0]);
3797 unsigned EltSize1 = getScalarSizeWithOverride(Args[1]);
3798 MaxEltSize = std::max(EltSize0, EltSize1);
3799 } else if (isa<SExtInst, ZExtInst>(Args[0]) &&
3800 isa<SExtInst, ZExtInst>(Args[1])) {
3801 unsigned EltSize0 = getScalarSizeWithOverride(Args[0]);
3802 unsigned EltSize1 = getScalarSizeWithOverride(Args[1]);
3803 // mul(sext, zext) will become smull(sext, zext) if the extends are large
3804 // enough.
3805 if (EltSize0 >= DstEltSize / 2 || EltSize1 >= DstEltSize / 2)
3806 return nullptr;
3807 MaxEltSize = DstEltSize / 2;
3808 } else if (Opcode == Instruction::Mul &&
3809 (isa<ZExtInst>(Args[0]) || isa<ZExtInst>(Args[1]))) {
3810 // If one of the operands is a Zext and the other has enough zero bits
3811 // to be treated as unsigned, we can still generate a umull, meaning the
3812 // zext is free.
3813 KnownBits Known =
3814 computeKnownBits(isa<ZExtInst>(Args[0]) ? Args[1] : Args[0], DL);
3815 if (Args[0]->getType()->getScalarSizeInBits() -
3816 Known.Zero.countLeadingOnes() >
3817 DstTy->getScalarSizeInBits() / 2)
3818 return nullptr;
3819
3820 MaxEltSize =
3821 getScalarSizeWithOverride(isa<ZExtInst>(Args[0]) ? Args[0] : Args[1]);
3822 } else
3823 return nullptr;
3824
3825 if (MaxEltSize * 2 > DstEltSize)
3826 return nullptr;
3827
3828 Type *ExtTy = DstTy->getWithNewBitWidth(MaxEltSize * 2);
3829 if (ExtTy->getPrimitiveSizeInBits() <= 64)
3830 return nullptr;
3831 return ExtTy;
3832}
3833
3834// s/urhadd instructions implement the following pattern, making the
3835// extends free:
3836// %x = add ((zext i8 -> i16), 1)
3837// %y = (zext i8 -> i16)
3838// trunc i16 (lshr (add %x, %y), 1) -> i8
3839//
3841 Type *Src) const {
3842 // The source should be a legal vector type.
3843 if (!Src->isVectorTy() || !TLI->isTypeLegal(TLI->getValueType(DL, Src)) ||
3844 (Src->isScalableTy() && !ST->hasSVE2()))
3845 return false;
3846
3847 if (ExtUser->getOpcode() != Instruction::Add || !ExtUser->hasOneUse())
3848 return false;
3849
3850 // Look for trunc/shl/add before trying to match the pattern.
3851 const Instruction *Add = ExtUser;
3852 auto *AddUser =
3853 dyn_cast_or_null<Instruction>(Add->getUniqueUndroppableUser());
3854 if (AddUser && AddUser->getOpcode() == Instruction::Add)
3855 Add = AddUser;
3856
3857 auto *Shr = dyn_cast_or_null<Instruction>(Add->getUniqueUndroppableUser());
3858 if (!Shr || Shr->getOpcode() != Instruction::LShr)
3859 return false;
3860
3861 auto *Trunc = dyn_cast_or_null<Instruction>(Shr->getUniqueUndroppableUser());
3862 if (!Trunc || Trunc->getOpcode() != Instruction::Trunc ||
3863 Src->getScalarSizeInBits() !=
3864 cast<CastInst>(Trunc)->getDestTy()->getScalarSizeInBits())
3865 return false;
3866
3867 // Try to match the whole pattern. Ext could be either the first or second
3868 // m_ZExtOrSExt matched.
3869 Instruction *Ex1, *Ex2;
3870 if (!(match(Add, m_c_Add(m_Instruction(Ex1),
3871 m_c_Add(m_Instruction(Ex2), m_One())))))
3872 return false;
3873
3874 // Ensure both extends are of the same type
3875 if (match(Ex1, m_ZExtOrSExt(m_Value())) &&
3876 Ex1->getOpcode() == Ex2->getOpcode())
3877 return true;
3878
3879 return false;
3880}
3881
3883 Type *Src,
3886 const Instruction *I) const {
3887 int ISD = TLI->InstructionOpcodeToISD(Opcode);
3888 assert(ISD && "Invalid opcode");
3889 // If the cast is observable, and it is used by a widening instruction (e.g.,
3890 // uaddl, saddw, etc.), it may be free.
3891 if (I && I->hasOneUser()) {
3892 auto *SingleUser = cast<Instruction>(*I->user_begin());
3893 SmallVector<const Value *, 4> Operands(SingleUser->operand_values());
3894 if (Type *ExtTy = isBinExtWideningInstruction(
3895 SingleUser->getOpcode(), Dst, Operands,
3896 Src != I->getOperand(0)->getType() ? Src : nullptr)) {
3897 // The cost from Src->Src*2 needs to be added if required, the cost from
3898 // Src*2->ExtTy is free.
3899 if (ExtTy->getScalarSizeInBits() > Src->getScalarSizeInBits() * 2) {
3900 Type *DoubleSrcTy =
3901 Src->getWithNewBitWidth(Src->getScalarSizeInBits() * 2);
3902 return getCastInstrCost(Opcode, DoubleSrcTy, Src,
3904 }
3905
3906 return 0;
3907 }
3908
3909 if (isSingleExtWideningInstruction(
3910 SingleUser->getOpcode(), Dst, Operands,
3911 Src != I->getOperand(0)->getType() ? Src : nullptr)) {
3912 // For adds only count the second operand as free if both operands are
3913 // extends but not the same operation. (i.e both operands are not free in
3914 // add(sext, zext)).
3915 if (SingleUser->getOpcode() == Instruction::Add) {
3916 if (I == SingleUser->getOperand(1) ||
3917 (isa<CastInst>(SingleUser->getOperand(1)) &&
3918 cast<CastInst>(SingleUser->getOperand(1))->getOpcode() == Opcode))
3919 return 0;
3920 } else {
3921 // Others are free so long as isSingleExtWideningInstruction
3922 // returned true.
3923 return 0;
3924 }
3925 }
3926
3927 // The cast will be free for the s/urhadd instructions
3928 if ((isa<ZExtInst>(I) || isa<SExtInst>(I)) &&
3929 isExtPartOfAvgExpr(SingleUser, Dst, Src))
3930 return 0;
3931 }
3932
3933 EVT SrcTy = TLI->getValueType(DL, Src);
3934 EVT DstTy = TLI->getValueType(DL, Dst);
3935
3936 // From a vector to a scalarized vector will be an series of extract-element
3937 // and extends.
3938 if ((ISD == ISD::ZERO_EXTEND || ISD == ISD::SIGN_EXTEND) &&
3939 DstTy.getScalarSizeInBits() > 64 && SrcTy.getScalarSizeInBits() <= 64 &&
3940 DstTy.isFixedLengthVector()) {
3942 Instruction::ExtractElement, Src, CostKind, -1, nullptr, nullptr);
3944 Opcode, Dst->getScalarType(), Src->getScalarType(), CCH, CostKind);
3945 return DstTy.getVectorNumElements() * (LaneCost + ExtCost);
3946 }
3947
3948 if (!SrcTy.isSimple() || !DstTy.isSimple())
3949 return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I);
3950
3951 // For the moment we do not have lowering for SVE1-only fptrunc f64->bf16 as
3952 // we use fcvtx under SVE2. Give them invalid costs.
3953 if (!ST->hasSVE2() && !ST->isStreamingSVEAvailable() &&
3954 ISD == ISD::FP_ROUND && SrcTy.isScalableVector() &&
3955 DstTy.getScalarType() == MVT::bf16 && SrcTy.getScalarType() == MVT::f64)
3957
3958 static const TypeConversionCostTblEntry BF16Tbl[] = {
3959 {ISD::FP_ROUND, MVT::bf16, MVT::f32, 1}, // bfcvt
3960 {ISD::FP_ROUND, MVT::bf16, MVT::f64, 1}, // bfcvt
3961 {ISD::FP_ROUND, MVT::v4bf16, MVT::v4f32, 1}, // bfcvtn
3962 {ISD::FP_ROUND, MVT::v8bf16, MVT::v8f32, 2}, // bfcvtn+bfcvtn2
3963 {ISD::FP_ROUND, MVT::v2bf16, MVT::v2f64, 2}, // bfcvtn+fcvtn
3964 {ISD::FP_ROUND, MVT::v4bf16, MVT::v4f64, 3}, // fcvtn+fcvtl2+bfcvtn
3965 {ISD::FP_ROUND, MVT::v8bf16, MVT::v8f64, 6}, // 2 * fcvtn+fcvtn2+bfcvtn
3966 {ISD::FP_ROUND, MVT::nxv2bf16, MVT::nxv2f32, 1}, // bfcvt
3967 {ISD::FP_ROUND, MVT::nxv4bf16, MVT::nxv4f32, 1}, // bfcvt
3968 {ISD::FP_ROUND, MVT::nxv8bf16, MVT::nxv8f32, 3}, // bfcvt+bfcvt+uzp1
3969 {ISD::FP_ROUND, MVT::nxv2bf16, MVT::nxv2f64, 2}, // fcvtx+bfcvt
3970 {ISD::FP_ROUND, MVT::nxv4bf16, MVT::nxv4f64, 5}, // 2*fcvtx+2*bfcvt+uzp1
3971 {ISD::FP_ROUND, MVT::nxv8bf16, MVT::nxv8f64, 11}, // 4*fcvt+4*bfcvt+3*uzp
3972 };
3973
3974 if (ST->hasBF16())
3975 if (const auto *Entry = ConvertCostTableLookup(
3976 BF16Tbl, ISD, DstTy.getSimpleVT(), SrcTy.getSimpleVT()))
3977 return Entry->Cost;
3978
3979 // We have to estimate a cost of fixed length operation upon
3980 // SVE registers(operations) with the number of registers required
3981 // for a fixed type to be represented upon SVE registers.
3982 EVT WiderTy = SrcTy.bitsGT(DstTy) ? SrcTy : DstTy;
3983 if (SrcTy.isFixedLengthVector() && DstTy.isFixedLengthVector() &&
3984 SrcTy.getVectorNumElements() == DstTy.getVectorNumElements() &&
3985 ST->useSVEForFixedLengthVectors(WiderTy)) {
3986 std::pair<InstructionCost, MVT> LT =
3987 getTypeLegalizationCost(WiderTy.getTypeForEVT(Dst->getContext()));
3988 unsigned NumElements =
3989 AArch64::SVEBitsPerBlock / LT.second.getScalarSizeInBits();
3990 return LT.first *
3992 Opcode,
3993 ScalableVectorType::get(Dst->getScalarType(), NumElements),
3994 ScalableVectorType::get(Src->getScalarType(), NumElements), CCH,
3995 CostKind, I);
3996 }
3997
3998 // Symbolic constants for the SVE sitofp/uitofp entries in the table below
3999 // The cost of unpacking twice is artificially increased for now in order
4000 // to avoid regressions against NEON, which will use tbl instructions directly
4001 // instead of multiple layers of [s|u]unpk[lo|hi].
4002 // We use the unpacks in cases where the destination type is illegal and
4003 // requires splitting of the input, even if the input type itself is legal.
4004 const unsigned int SVE_EXT_COST = 1;
4005 const unsigned int SVE_FCVT_COST = 1;
4006 const unsigned int SVE_UNPACK_ONCE = 4;
4007 const unsigned int SVE_UNPACK_TWICE = 16;
4008
4009 static const TypeConversionCostTblEntry ConversionTbl[] = {
4010 {ISD::TRUNCATE, MVT::v2i8, MVT::v2i64, 1}, // xtn
4011 {ISD::TRUNCATE, MVT::v2i16, MVT::v2i64, 1}, // xtn
4012 {ISD::TRUNCATE, MVT::v2i32, MVT::v2i64, 1}, // xtn
4013 {ISD::TRUNCATE, MVT::v4i8, MVT::v4i32, 1}, // xtn
4014 {ISD::TRUNCATE, MVT::v4i8, MVT::v4i64, 3}, // 2 xtn + 1 uzp1
4015 {ISD::TRUNCATE, MVT::v4i16, MVT::v4i32, 1}, // xtn
4016 {ISD::TRUNCATE, MVT::v4i16, MVT::v4i64, 2}, // 1 uzp1 + 1 xtn
4017 {ISD::TRUNCATE, MVT::v4i32, MVT::v4i64, 1}, // 1 uzp1
4018 {ISD::TRUNCATE, MVT::v8i8, MVT::v8i16, 1}, // 1 xtn
4019 {ISD::TRUNCATE, MVT::v8i8, MVT::v8i32, 2}, // 1 uzp1 + 1 xtn
4020 {ISD::TRUNCATE, MVT::v8i8, MVT::v8i64, 4}, // 3 x uzp1 + xtn
4021 {ISD::TRUNCATE, MVT::v8i16, MVT::v8i32, 1}, // 1 uzp1
4022 {ISD::TRUNCATE, MVT::v8i16, MVT::v8i64, 3}, // 3 x uzp1
4023 {ISD::TRUNCATE, MVT::v8i32, MVT::v8i64, 2}, // 2 x uzp1
4024 {ISD::TRUNCATE, MVT::v16i8, MVT::v16i16, 1}, // uzp1
4025 {ISD::TRUNCATE, MVT::v16i8, MVT::v16i32, 3}, // (2 + 1) x uzp1
4026 {ISD::TRUNCATE, MVT::v16i8, MVT::v16i64, 7}, // (4 + 2 + 1) x uzp1
4027 {ISD::TRUNCATE, MVT::v16i16, MVT::v16i32, 2}, // 2 x uzp1
4028 {ISD::TRUNCATE, MVT::v16i16, MVT::v16i64, 6}, // (4 + 2) x uzp1
4029 {ISD::TRUNCATE, MVT::v16i32, MVT::v16i64, 4}, // 4 x uzp1
4030
4031 // Truncations on nxvmiN
4032 {ISD::TRUNCATE, MVT::nxv2i1, MVT::nxv2i8, 2},
4033 {ISD::TRUNCATE, MVT::nxv2i1, MVT::nxv2i16, 2},
4034 {ISD::TRUNCATE, MVT::nxv2i1, MVT::nxv2i32, 2},
4035 {ISD::TRUNCATE, MVT::nxv2i1, MVT::nxv2i64, 2},
4036 {ISD::TRUNCATE, MVT::nxv4i1, MVT::nxv4i8, 2},
4037 {ISD::TRUNCATE, MVT::nxv4i1, MVT::nxv4i16, 2},
4038 {ISD::TRUNCATE, MVT::nxv4i1, MVT::nxv4i32, 2},
4039 {ISD::TRUNCATE, MVT::nxv4i1, MVT::nxv4i64, 5},
4040 {ISD::TRUNCATE, MVT::nxv8i1, MVT::nxv8i8, 2},
4041 {ISD::TRUNCATE, MVT::nxv8i1, MVT::nxv8i16, 2},
4042 {ISD::TRUNCATE, MVT::nxv8i1, MVT::nxv8i32, 5},
4043 {ISD::TRUNCATE, MVT::nxv8i1, MVT::nxv8i64, 11},
4044 {ISD::TRUNCATE, MVT::nxv16i1, MVT::nxv16i8, 2},
4045 {ISD::TRUNCATE, MVT::nxv2i8, MVT::nxv2i16, 0},
4046 {ISD::TRUNCATE, MVT::nxv2i8, MVT::nxv2i32, 0},
4047 {ISD::TRUNCATE, MVT::nxv2i8, MVT::nxv2i64, 0},
4048 {ISD::TRUNCATE, MVT::nxv2i16, MVT::nxv2i32, 0},
4049 {ISD::TRUNCATE, MVT::nxv2i16, MVT::nxv2i64, 0},
4050 {ISD::TRUNCATE, MVT::nxv2i32, MVT::nxv2i64, 0},
4051 {ISD::TRUNCATE, MVT::nxv4i8, MVT::nxv4i16, 0},
4052 {ISD::TRUNCATE, MVT::nxv4i8, MVT::nxv4i32, 0},
4053 {ISD::TRUNCATE, MVT::nxv4i8, MVT::nxv4i64, 1},
4054 {ISD::TRUNCATE, MVT::nxv4i16, MVT::nxv4i32, 0},
4055 {ISD::TRUNCATE, MVT::nxv4i16, MVT::nxv4i64, 1},
4056 {ISD::TRUNCATE, MVT::nxv4i32, MVT::nxv4i64, 1},
4057 {ISD::TRUNCATE, MVT::nxv8i8, MVT::nxv8i16, 0},
4058 {ISD::TRUNCATE, MVT::nxv8i8, MVT::nxv8i32, 1},
4059 {ISD::TRUNCATE, MVT::nxv8i8, MVT::nxv8i64, 3},
4060 {ISD::TRUNCATE, MVT::nxv8i16, MVT::nxv8i32, 1},
4061 {ISD::TRUNCATE, MVT::nxv8i16, MVT::nxv8i64, 3},
4062 {ISD::TRUNCATE, MVT::nxv16i8, MVT::nxv16i16, 1},
4063 {ISD::TRUNCATE, MVT::nxv16i8, MVT::nxv16i32, 3},
4064 {ISD::TRUNCATE, MVT::nxv16i8, MVT::nxv16i64, 7},
4065
4066 // The number of shll instructions for the extension.
4067 {ISD::SIGN_EXTEND, MVT::v4i64, MVT::v4i16, 3},
4068 {ISD::ZERO_EXTEND, MVT::v4i64, MVT::v4i16, 3},
4069 {ISD::SIGN_EXTEND, MVT::v4i64, MVT::v4i32, 2},
4070 {ISD::ZERO_EXTEND, MVT::v4i64, MVT::v4i32, 2},
4071 {ISD::SIGN_EXTEND, MVT::v8i32, MVT::v8i8, 3},
4072 {ISD::ZERO_EXTEND, MVT::v8i32, MVT::v8i8, 3},
4073 {ISD::SIGN_EXTEND, MVT::v8i32, MVT::v8i16, 2},
4074 {ISD::ZERO_EXTEND, MVT::v8i32, MVT::v8i16, 2},
4075 {ISD::SIGN_EXTEND, MVT::v8i64, MVT::v8i8, 7},
4076 {ISD::ZERO_EXTEND, MVT::v8i64, MVT::v8i8, 7},
4077 {ISD::SIGN_EXTEND, MVT::v8i64, MVT::v8i16, 6},
4078 {ISD::ZERO_EXTEND, MVT::v8i64, MVT::v8i16, 6},
4079 {ISD::SIGN_EXTEND, MVT::v16i16, MVT::v16i8, 2},
4080 {ISD::ZERO_EXTEND, MVT::v16i16, MVT::v16i8, 2},
4081 {ISD::SIGN_EXTEND, MVT::v16i32, MVT::v16i8, 6},
4082 {ISD::ZERO_EXTEND, MVT::v16i32, MVT::v16i8, 6},
4083
4084 // FP Ext and trunc
4085 {ISD::FP_EXTEND, MVT::f64, MVT::f32, 1}, // fcvt
4086 {ISD::FP_EXTEND, MVT::v2f64, MVT::v2f32, 1}, // fcvtl
4087 {ISD::FP_EXTEND, MVT::v4f64, MVT::v4f32, 2}, // fcvtl+fcvtl2
4088 // FP16
4089 {ISD::FP_EXTEND, MVT::f32, MVT::f16, 1}, // fcvt
4090 {ISD::FP_EXTEND, MVT::f64, MVT::f16, 1}, // fcvt
4091 {ISD::FP_EXTEND, MVT::v4f32, MVT::v4f16, 1}, // fcvtl
4092 {ISD::FP_EXTEND, MVT::v8f32, MVT::v8f16, 2}, // fcvtl+fcvtl2
4093 {ISD::FP_EXTEND, MVT::v2f64, MVT::v2f16, 2}, // fcvtl+fcvtl
4094 {ISD::FP_EXTEND, MVT::v4f64, MVT::v4f16, 3}, // fcvtl+fcvtl2+fcvtl
4095 {ISD::FP_EXTEND, MVT::v8f64, MVT::v8f16, 6}, // 2 * fcvtl+fcvtl2+fcvtl
4096 // BF16 (uses shift)
4097 {ISD::FP_EXTEND, MVT::f32, MVT::bf16, 1}, // shl
4098 {ISD::FP_EXTEND, MVT::f64, MVT::bf16, 2}, // shl+fcvt
4099 {ISD::FP_EXTEND, MVT::v4f32, MVT::v4bf16, 1}, // shll
4100 {ISD::FP_EXTEND, MVT::v8f32, MVT::v8bf16, 2}, // shll+shll2
4101 {ISD::FP_EXTEND, MVT::v2f64, MVT::v2bf16, 2}, // shll+fcvtl
4102 {ISD::FP_EXTEND, MVT::v4f64, MVT::v4bf16, 3}, // shll+fcvtl+fcvtl2
4103 {ISD::FP_EXTEND, MVT::v8f64, MVT::v8bf16, 6}, // 2 * shll+fcvtl+fcvtl2
4104 // FP Ext and trunc
4105 {ISD::FP_ROUND, MVT::f32, MVT::f64, 1}, // fcvt
4106 {ISD::FP_ROUND, MVT::v2f32, MVT::v2f64, 1}, // fcvtn
4107 {ISD::FP_ROUND, MVT::v4f32, MVT::v4f64, 2}, // fcvtn+fcvtn2
4108 // FP16
4109 {ISD::FP_ROUND, MVT::f16, MVT::f32, 1}, // fcvt
4110 {ISD::FP_ROUND, MVT::f16, MVT::f64, 1}, // fcvt
4111 {ISD::FP_ROUND, MVT::v4f16, MVT::v4f32, 1}, // fcvtn
4112 {ISD::FP_ROUND, MVT::v8f16, MVT::v8f32, 2}, // fcvtn+fcvtn2
4113 {ISD::FP_ROUND, MVT::v2f16, MVT::v2f64, 2}, // fcvtn+fcvtn
4114 {ISD::FP_ROUND, MVT::v4f16, MVT::v4f64, 3}, // fcvtn+fcvtn2+fcvtn
4115 {ISD::FP_ROUND, MVT::v8f16, MVT::v8f64, 6}, // 2 * fcvtn+fcvtn2+fcvtn
4116 // BF16 (more complex, with +bf16 is handled above)
4117 {ISD::FP_ROUND, MVT::bf16, MVT::f32, 8}, // Expansion is ~8 insns
4118 {ISD::FP_ROUND, MVT::bf16, MVT::f64, 9}, // fcvtn + above
4119 {ISD::FP_ROUND, MVT::v2bf16, MVT::v2f32, 8},
4120 {ISD::FP_ROUND, MVT::v4bf16, MVT::v4f32, 8},
4121 {ISD::FP_ROUND, MVT::v8bf16, MVT::v8f32, 15},
4122 {ISD::FP_ROUND, MVT::v2bf16, MVT::v2f64, 9},
4123 {ISD::FP_ROUND, MVT::v4bf16, MVT::v4f64, 10},
4124 {ISD::FP_ROUND, MVT::v8bf16, MVT::v8f64, 19},
4125
4126 // LowerVectorINT_TO_FP:
4127 {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i32, 1},
4128 {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i32, 1},
4129 {ISD::SINT_TO_FP, MVT::v2f64, MVT::v2i64, 1},
4130 {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i32, 1},
4131 {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i32, 1},
4132 {ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i64, 1},
4133
4134 // SVE: to nxv2f16
4135 {ISD::SINT_TO_FP, MVT::nxv2f16, MVT::nxv2i8,
4136 SVE_EXT_COST + SVE_FCVT_COST},
4137 {ISD::SINT_TO_FP, MVT::nxv2f16, MVT::nxv2i16, SVE_FCVT_COST},
4138 {ISD::SINT_TO_FP, MVT::nxv2f16, MVT::nxv2i32, SVE_FCVT_COST},
4139 {ISD::SINT_TO_FP, MVT::nxv2f16, MVT::nxv2i64, SVE_FCVT_COST},
4140 {ISD::UINT_TO_FP, MVT::nxv2f16, MVT::nxv2i8,
4141 SVE_EXT_COST + SVE_FCVT_COST},
4142 {ISD::UINT_TO_FP, MVT::nxv2f16, MVT::nxv2i16, SVE_FCVT_COST},
4143 {ISD::UINT_TO_FP, MVT::nxv2f16, MVT::nxv2i32, SVE_FCVT_COST},
4144 {ISD::UINT_TO_FP, MVT::nxv2f16, MVT::nxv2i64, SVE_FCVT_COST},
4145
4146 // SVE: to nxv4f16
4147 {ISD::SINT_TO_FP, MVT::nxv4f16, MVT::nxv4i8,
4148 SVE_EXT_COST + SVE_FCVT_COST},
4149 {ISD::SINT_TO_FP, MVT::nxv4f16, MVT::nxv4i16, SVE_FCVT_COST},
4150 {ISD::SINT_TO_FP, MVT::nxv4f16, MVT::nxv4i32, SVE_FCVT_COST},
4151 {ISD::UINT_TO_FP, MVT::nxv4f16, MVT::nxv4i8,
4152 SVE_EXT_COST + SVE_FCVT_COST},
4153 {ISD::UINT_TO_FP, MVT::nxv4f16, MVT::nxv4i16, SVE_FCVT_COST},
4154 {ISD::UINT_TO_FP, MVT::nxv4f16, MVT::nxv4i32, SVE_FCVT_COST},
4155
4156 // SVE: to nxv8f16
4157 {ISD::SINT_TO_FP, MVT::nxv8f16, MVT::nxv8i8,
4158 SVE_EXT_COST + SVE_FCVT_COST},
4159 {ISD::SINT_TO_FP, MVT::nxv8f16, MVT::nxv8i16, SVE_FCVT_COST},
4160 {ISD::UINT_TO_FP, MVT::nxv8f16, MVT::nxv8i8,
4161 SVE_EXT_COST + SVE_FCVT_COST},
4162 {ISD::UINT_TO_FP, MVT::nxv8f16, MVT::nxv8i16, SVE_FCVT_COST},
4163
4164 // SVE: to nxv16f16
4165 {ISD::SINT_TO_FP, MVT::nxv16f16, MVT::nxv16i8,
4166 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4167 {ISD::UINT_TO_FP, MVT::nxv16f16, MVT::nxv16i8,
4168 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4169
4170 // Complex: to v2f32
4171 {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i8, 3},
4172 {ISD::SINT_TO_FP, MVT::v2f32, MVT::v2i16, 3},
4173 {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i8, 3},
4174 {ISD::UINT_TO_FP, MVT::v2f32, MVT::v2i16, 3},
4175
4176 // SVE: to nxv2f32
4177 {ISD::SINT_TO_FP, MVT::nxv2f32, MVT::nxv2i8,
4178 SVE_EXT_COST + SVE_FCVT_COST},
4179 {ISD::SINT_TO_FP, MVT::nxv2f32, MVT::nxv2i16, SVE_FCVT_COST},
4180 {ISD::SINT_TO_FP, MVT::nxv2f32, MVT::nxv2i32, SVE_FCVT_COST},
4181 {ISD::SINT_TO_FP, MVT::nxv2f32, MVT::nxv2i64, SVE_FCVT_COST},
4182 {ISD::UINT_TO_FP, MVT::nxv2f32, MVT::nxv2i8,
4183 SVE_EXT_COST + SVE_FCVT_COST},
4184 {ISD::UINT_TO_FP, MVT::nxv2f32, MVT::nxv2i16, SVE_FCVT_COST},
4185 {ISD::UINT_TO_FP, MVT::nxv2f32, MVT::nxv2i32, SVE_FCVT_COST},
4186 {ISD::UINT_TO_FP, MVT::nxv2f32, MVT::nxv2i64, SVE_FCVT_COST},
4187
4188 // Complex: to v4f32
4189 {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i8, 4},
4190 {ISD::SINT_TO_FP, MVT::v4f32, MVT::v4i16, 2},
4191 {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i8, 3},
4192 {ISD::UINT_TO_FP, MVT::v4f32, MVT::v4i16, 2},
4193
4194 // SVE: to nxv4f32
4195 {ISD::SINT_TO_FP, MVT::nxv4f32, MVT::nxv4i8,
4196 SVE_EXT_COST + SVE_FCVT_COST},
4197 {ISD::SINT_TO_FP, MVT::nxv4f32, MVT::nxv4i16, SVE_FCVT_COST},
4198 {ISD::SINT_TO_FP, MVT::nxv4f32, MVT::nxv4i32, SVE_FCVT_COST},
4199 {ISD::UINT_TO_FP, MVT::nxv4f32, MVT::nxv4i8,
4200 SVE_EXT_COST + SVE_FCVT_COST},
4201 {ISD::UINT_TO_FP, MVT::nxv4f32, MVT::nxv4i16, SVE_FCVT_COST},
4202 {ISD::SINT_TO_FP, MVT::nxv4f32, MVT::nxv4i32, SVE_FCVT_COST},
4203
4204 // Complex: to v8f32
4205 {ISD::SINT_TO_FP, MVT::v8f32, MVT::v8i8, 10},
4206 {ISD::SINT_TO_FP, MVT::v8f32, MVT::v8i16, 4},
4207 {ISD::UINT_TO_FP, MVT::v8f32, MVT::v8i8, 10},
4208 {ISD::UINT_TO_FP, MVT::v8f32, MVT::v8i16, 4},
4209
4210 // SVE: to nxv8f32
4211 {ISD::SINT_TO_FP, MVT::nxv8f32, MVT::nxv8i8,
4212 SVE_EXT_COST + SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4213 {ISD::SINT_TO_FP, MVT::nxv8f32, MVT::nxv8i16,
4214 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4215 {ISD::UINT_TO_FP, MVT::nxv8f32, MVT::nxv8i8,
4216 SVE_EXT_COST + SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4217 {ISD::UINT_TO_FP, MVT::nxv8f32, MVT::nxv8i16,
4218 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4219
4220 // SVE: to nxv16f32
4221 {ISD::SINT_TO_FP, MVT::nxv16f32, MVT::nxv16i8,
4222 SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4223 {ISD::UINT_TO_FP, MVT::nxv16f32, MVT::nxv16i8,
4224 SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4225
4226 // Complex: to v16f32
4227 {ISD::SINT_TO_FP, MVT::v16f32, MVT::v16i8, 21},
4228 {ISD::UINT_TO_FP, MVT::v16f32, MVT::v16i8, 21},
4229
4230 // Complex: to v2f64
4231 {ISD::SINT_TO_FP, MVT::v2f64, MVT::v2i8, 4},
4232 {ISD::SINT_TO_FP, MVT::v2f64, MVT::v2i16, 4},
4233 {ISD::SINT_TO_FP, MVT::v2f64, MVT::v2i32, 2},
4234 {ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i8, 4},
4235 {ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i16, 4},
4236 {ISD::UINT_TO_FP, MVT::v2f64, MVT::v2i32, 2},
4237
4238 // SVE: to nxv2f64
4239 {ISD::SINT_TO_FP, MVT::nxv2f64, MVT::nxv2i8,
4240 SVE_EXT_COST + SVE_FCVT_COST},
4241 {ISD::SINT_TO_FP, MVT::nxv2f64, MVT::nxv2i16, SVE_FCVT_COST},
4242 {ISD::SINT_TO_FP, MVT::nxv2f64, MVT::nxv2i32, SVE_FCVT_COST},
4243 {ISD::SINT_TO_FP, MVT::nxv2f64, MVT::nxv2i64, SVE_FCVT_COST},
4244 {ISD::UINT_TO_FP, MVT::nxv2f64, MVT::nxv2i8,
4245 SVE_EXT_COST + SVE_FCVT_COST},
4246 {ISD::UINT_TO_FP, MVT::nxv2f64, MVT::nxv2i16, SVE_FCVT_COST},
4247 {ISD::UINT_TO_FP, MVT::nxv2f64, MVT::nxv2i32, SVE_FCVT_COST},
4248 {ISD::UINT_TO_FP, MVT::nxv2f64, MVT::nxv2i64, SVE_FCVT_COST},
4249
4250 // Complex: to v4f64
4251 {ISD::SINT_TO_FP, MVT::v4f64, MVT::v4i32, 4},
4252 {ISD::UINT_TO_FP, MVT::v4f64, MVT::v4i32, 4},
4253
4254 // SVE: to nxv4f64
4255 {ISD::SINT_TO_FP, MVT::nxv4f64, MVT::nxv4i8,
4256 SVE_EXT_COST + SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4257 {ISD::SINT_TO_FP, MVT::nxv4f64, MVT::nxv4i16,
4258 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4259 {ISD::SINT_TO_FP, MVT::nxv4f64, MVT::nxv4i32,
4260 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4261 {ISD::UINT_TO_FP, MVT::nxv4f64, MVT::nxv4i8,
4262 SVE_EXT_COST + SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4263 {ISD::UINT_TO_FP, MVT::nxv4f64, MVT::nxv4i16,
4264 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4265 {ISD::UINT_TO_FP, MVT::nxv4f64, MVT::nxv4i32,
4266 SVE_UNPACK_ONCE + 2 * SVE_FCVT_COST},
4267
4268 // SVE: to nxv8f64
4269 {ISD::SINT_TO_FP, MVT::nxv8f64, MVT::nxv8i8,
4270 SVE_EXT_COST + SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4271 {ISD::SINT_TO_FP, MVT::nxv8f64, MVT::nxv8i16,
4272 SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4273 {ISD::UINT_TO_FP, MVT::nxv8f64, MVT::nxv8i8,
4274 SVE_EXT_COST + SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4275 {ISD::UINT_TO_FP, MVT::nxv8f64, MVT::nxv8i16,
4276 SVE_UNPACK_TWICE + 4 * SVE_FCVT_COST},
4277
4278 // LowerVectorFP_TO_INT
4279 {ISD::FP_TO_SINT, MVT::v2i32, MVT::v2f32, 1},
4280 {ISD::FP_TO_SINT, MVT::v4i32, MVT::v4f32, 1},
4281 {ISD::FP_TO_SINT, MVT::v2i64, MVT::v2f64, 1},
4282 {ISD::FP_TO_UINT, MVT::v2i32, MVT::v2f32, 1},
4283 {ISD::FP_TO_UINT, MVT::v4i32, MVT::v4f32, 1},
4284 {ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f64, 1},
4285
4286 // Complex, from v2f32: legal type is v2i32 (no cost) or v2i64 (1 ext).
4287 {ISD::FP_TO_SINT, MVT::v2i64, MVT::v2f32, 2},
4288 {ISD::FP_TO_SINT, MVT::v2i16, MVT::v2f32, 1},
4289 {ISD::FP_TO_SINT, MVT::v2i8, MVT::v2f32, 1},
4290 {ISD::FP_TO_UINT, MVT::v2i64, MVT::v2f32, 2},
4291 {ISD::FP_TO_UINT, MVT::v2i16, MVT::v2f32, 1},
4292 {ISD::FP_TO_UINT, MVT::v2i8, MVT::v2f32, 1},
4293
4294 // Complex, from v4f32: legal type is v4i16, 1 narrowing => ~2
4295 {ISD::FP_TO_SINT, MVT::v4i16, MVT::v4f32, 2},
4296 {ISD::FP_TO_SINT, MVT::v4i8, MVT::v4f32, 2},
4297 {ISD::FP_TO_UINT, MVT::v4i16, MVT::v4f32, 2},
4298 {ISD::FP_TO_UINT, MVT::v4i8, MVT::v4f32, 2},
4299
4300 // Complex, from v2f64: legal type is v2i32, 1 narrowing => ~2.
4301 {ISD::FP_TO_SINT, MVT::v2i32, MVT::v2f64, 2},
4302 {ISD::FP_TO_SINT, MVT::v2i16, MVT::v2f64, 2},
4303 {ISD::FP_TO_SINT, MVT::v2i8, MVT::v2f64, 2},
4304 {ISD::FP_TO_UINT, MVT::v2i32, MVT::v2f64, 2},
4305 {ISD::FP_TO_UINT, MVT::v2i16, MVT::v2f64, 2},
4306 {ISD::FP_TO_UINT, MVT::v2i8, MVT::v2f64, 2},
4307
4308 // Complex, from nxv2f32.
4309 {ISD::FP_TO_SINT, MVT::nxv2i64, MVT::nxv2f32, 1},
4310 {ISD::FP_TO_SINT, MVT::nxv2i32, MVT::nxv2f32, 1},
4311 {ISD::FP_TO_SINT, MVT::nxv2i16, MVT::nxv2f32, 1},
4312 {ISD::FP_TO_SINT, MVT::nxv2i8, MVT::nxv2f32, 1},
4313 {ISD::FP_TO_UINT, MVT::nxv2i64, MVT::nxv2f32, 1},
4314 {ISD::FP_TO_UINT, MVT::nxv2i32, MVT::nxv2f32, 1},
4315 {ISD::FP_TO_UINT, MVT::nxv2i16, MVT::nxv2f32, 1},
4316 {ISD::FP_TO_UINT, MVT::nxv2i8, MVT::nxv2f32, 1},
4317
4318 // Complex, from nxv2f64.
4319 {ISD::FP_TO_SINT, MVT::nxv2i64, MVT::nxv2f64, 1},
4320 {ISD::FP_TO_SINT, MVT::nxv2i32, MVT::nxv2f64, 1},
4321 {ISD::FP_TO_SINT, MVT::nxv2i16, MVT::nxv2f64, 1},
4322 {ISD::FP_TO_SINT, MVT::nxv2i8, MVT::nxv2f64, 1},
4323 {ISD::FP_TO_SINT, MVT::nxv2i1, MVT::nxv2f64, 1},
4324 {ISD::FP_TO_UINT, MVT::nxv2i64, MVT::nxv2f64, 1},
4325 {ISD::FP_TO_UINT, MVT::nxv2i32, MVT::nxv2f64, 1},
4326 {ISD::FP_TO_UINT, MVT::nxv2i16, MVT::nxv2f64, 1},
4327 {ISD::FP_TO_UINT, MVT::nxv2i8, MVT::nxv2f64, 1},
4328 {ISD::FP_TO_UINT, MVT::nxv2i1, MVT::nxv2f64, 1},
4329
4330 // Complex, from nxv4f32.
4331 {ISD::FP_TO_SINT, MVT::nxv4i64, MVT::nxv4f32, 4},
4332 {ISD::FP_TO_SINT, MVT::nxv4i32, MVT::nxv4f32, 1},
4333 {ISD::FP_TO_SINT, MVT::nxv4i16, MVT::nxv4f32, 1},
4334 {ISD::FP_TO_SINT, MVT::nxv4i8, MVT::nxv4f32, 1},
4335 {ISD::FP_TO_SINT, MVT::nxv4i1, MVT::nxv4f32, 1},
4336 {ISD::FP_TO_UINT, MVT::nxv4i64, MVT::nxv4f32, 4},
4337 {ISD::FP_TO_UINT, MVT::nxv4i32, MVT::nxv4f32, 1},
4338 {ISD::FP_TO_UINT, MVT::nxv4i16, MVT::nxv4f32, 1},
4339 {ISD::FP_TO_UINT, MVT::nxv4i8, MVT::nxv4f32, 1},
4340 {ISD::FP_TO_UINT, MVT::nxv4i1, MVT::nxv4f32, 1},
4341
4342 // Complex, from nxv8f64. Illegal -> illegal conversions not required.
4343 {ISD::FP_TO_SINT, MVT::nxv8i16, MVT::nxv8f64, 7},
4344 {ISD::FP_TO_SINT, MVT::nxv8i8, MVT::nxv8f64, 7},
4345 {ISD::FP_TO_UINT, MVT::nxv8i16, MVT::nxv8f64, 7},
4346 {ISD::FP_TO_UINT, MVT::nxv8i8, MVT::nxv8f64, 7},
4347
4348 // Complex, from nxv4f64. Illegal -> illegal conversions not required.
4349 {ISD::FP_TO_SINT, MVT::nxv4i32, MVT::nxv4f64, 3},
4350 {ISD::FP_TO_SINT, MVT::nxv4i16, MVT::nxv4f64, 3},
4351 {ISD::FP_TO_SINT, MVT::nxv4i8, MVT::nxv4f64, 3},
4352 {ISD::FP_TO_UINT, MVT::nxv4i32, MVT::nxv4f64, 3},
4353 {ISD::FP_TO_UINT, MVT::nxv4i16, MVT::nxv4f64, 3},
4354 {ISD::FP_TO_UINT, MVT::nxv4i8, MVT::nxv4f64, 3},
4355
4356 // Complex, from nxv8f32. Illegal -> illegal conversions not required.
4357 {ISD::FP_TO_SINT, MVT::nxv8i16, MVT::nxv8f32, 3},
4358 {ISD::FP_TO_SINT, MVT::nxv8i8, MVT::nxv8f32, 3},
4359 {ISD::FP_TO_UINT, MVT::nxv8i16, MVT::nxv8f32, 3},
4360 {ISD::FP_TO_UINT, MVT::nxv8i8, MVT::nxv8f32, 3},
4361
4362 // Complex, from nxv8f16.
4363 {ISD::FP_TO_SINT, MVT::nxv8i64, MVT::nxv8f16, 10},
4364 {ISD::FP_TO_SINT, MVT::nxv8i32, MVT::nxv8f16, 4},
4365 {ISD::FP_TO_SINT, MVT::nxv8i16, MVT::nxv8f16, 1},
4366 {ISD::FP_TO_SINT, MVT::nxv8i8, MVT::nxv8f16, 1},
4367 {ISD::FP_TO_SINT, MVT::nxv8i1, MVT::nxv8f16, 1},
4368 {ISD::FP_TO_UINT, MVT::nxv8i64, MVT::nxv8f16, 10},
4369 {ISD::FP_TO_UINT, MVT::nxv8i32, MVT::nxv8f16, 4},
4370 {ISD::FP_TO_UINT, MVT::nxv8i16, MVT::nxv8f16, 1},
4371 {ISD::FP_TO_UINT, MVT::nxv8i8, MVT::nxv8f16, 1},
4372 {ISD::FP_TO_UINT, MVT::nxv8i1, MVT::nxv8f16, 1},
4373
4374 // Complex, from nxv4f16.
4375 {ISD::FP_TO_SINT, MVT::nxv4i64, MVT::nxv4f16, 4},
4376 {ISD::FP_TO_SINT, MVT::nxv4i32, MVT::nxv4f16, 1},
4377 {ISD::FP_TO_SINT, MVT::nxv4i16, MVT::nxv4f16, 1},
4378 {ISD::FP_TO_SINT, MVT::nxv4i8, MVT::nxv4f16, 1},
4379 {ISD::FP_TO_UINT, MVT::nxv4i64, MVT::nxv4f16, 4},
4380 {ISD::FP_TO_UINT, MVT::nxv4i32, MVT::nxv4f16, 1},
4381 {ISD::FP_TO_UINT, MVT::nxv4i16, MVT::nxv4f16, 1},
4382 {ISD::FP_TO_UINT, MVT::nxv4i8, MVT::nxv4f16, 1},
4383
4384 // Complex, from nxv2f16.
4385 {ISD::FP_TO_SINT, MVT::nxv2i64, MVT::nxv2f16, 1},
4386 {ISD::FP_TO_SINT, MVT::nxv2i32, MVT::nxv2f16, 1},
4387 {ISD::FP_TO_SINT, MVT::nxv2i16, MVT::nxv2f16, 1},
4388 {ISD::FP_TO_SINT, MVT::nxv2i8, MVT::nxv2f16, 1},
4389 {ISD::FP_TO_UINT, MVT::nxv2i64, MVT::nxv2f16, 1},
4390 {ISD::FP_TO_UINT, MVT::nxv2i32, MVT::nxv2f16, 1},
4391 {ISD::FP_TO_UINT, MVT::nxv2i16, MVT::nxv2f16, 1},
4392 {ISD::FP_TO_UINT, MVT::nxv2i8, MVT::nxv2f16, 1},
4393
4394 // Truncate from nxvmf32 to nxvmf16.
4395 {ISD::FP_ROUND, MVT::nxv2f16, MVT::nxv2f32, 1},
4396 {ISD::FP_ROUND, MVT::nxv4f16, MVT::nxv4f32, 1},
4397 {ISD::FP_ROUND, MVT::nxv8f16, MVT::nxv8f32, 3},
4398
4399 // Truncate from nxvmf32 to nxvmbf16.
4400 {ISD::FP_ROUND, MVT::nxv2bf16, MVT::nxv2f32, 8},
4401 {ISD::FP_ROUND, MVT::nxv4bf16, MVT::nxv4f32, 8},
4402 {ISD::FP_ROUND, MVT::nxv8bf16, MVT::nxv8f32, 17},
4403
4404 // Truncate from nxvmf64 to nxvmf16.
4405 {ISD::FP_ROUND, MVT::nxv2f16, MVT::nxv2f64, 1},
4406 {ISD::FP_ROUND, MVT::nxv4f16, MVT::nxv4f64, 3},
4407 {ISD::FP_ROUND, MVT::nxv8f16, MVT::nxv8f64, 7},
4408
4409 // Truncate from nxvmf64 to nxvmbf16.
4410 {ISD::FP_ROUND, MVT::nxv2bf16, MVT::nxv2f64, 9},
4411 {ISD::FP_ROUND, MVT::nxv4bf16, MVT::nxv4f64, 19},
4412 {ISD::FP_ROUND, MVT::nxv8bf16, MVT::nxv8f64, 39},
4413
4414 // Truncate from nxvmf64 to nxvmf32.
4415 {ISD::FP_ROUND, MVT::nxv2f32, MVT::nxv2f64, 1},
4416 {ISD::FP_ROUND, MVT::nxv4f32, MVT::nxv4f64, 3},
4417 {ISD::FP_ROUND, MVT::nxv8f32, MVT::nxv8f64, 6},
4418
4419 // Extend from nxvmf16 to nxvmf32.
4420 {ISD::FP_EXTEND, MVT::nxv2f32, MVT::nxv2f16, 1},
4421 {ISD::FP_EXTEND, MVT::nxv4f32, MVT::nxv4f16, 1},
4422 {ISD::FP_EXTEND, MVT::nxv8f32, MVT::nxv8f16, 2},
4423
4424 // Extend from nxvmbf16 to nxvmf32.
4425 {ISD::FP_EXTEND, MVT::nxv2f32, MVT::nxv2bf16, 1}, // lsl
4426 {ISD::FP_EXTEND, MVT::nxv4f32, MVT::nxv4bf16, 1}, // lsl
4427 {ISD::FP_EXTEND, MVT::nxv8f32, MVT::nxv8bf16, 4}, // unpck+unpck+lsl+lsl
4428
4429 // Extend from nxvmf16 to nxvmf64.
4430 {ISD::FP_EXTEND, MVT::nxv2f64, MVT::nxv2f16, 1},
4431 {ISD::FP_EXTEND, MVT::nxv4f64, MVT::nxv4f16, 2},
4432 {ISD::FP_EXTEND, MVT::nxv8f64, MVT::nxv8f16, 4},
4433
4434 // Extend from nxvmbf16 to nxvmf64.
4435 {ISD::FP_EXTEND, MVT::nxv2f64, MVT::nxv2bf16, 2}, // lsl+fcvt
4436 {ISD::FP_EXTEND, MVT::nxv4f64, MVT::nxv4bf16, 6}, // 2*unpck+2*lsl+2*fcvt
4437 {ISD::FP_EXTEND, MVT::nxv8f64, MVT::nxv8bf16, 14}, // 6*unpck+4*lsl+4*fcvt
4438
4439 // Extend from nxvmf32 to nxvmf64.
4440 {ISD::FP_EXTEND, MVT::nxv2f64, MVT::nxv2f32, 1},
4441 {ISD::FP_EXTEND, MVT::nxv4f64, MVT::nxv4f32, 2},
4442 {ISD::FP_EXTEND, MVT::nxv8f64, MVT::nxv8f32, 6},
4443
4444 // Bitcasts from float to integer
4445 {ISD::BITCAST, MVT::nxv2f16, MVT::nxv2i16, 0},
4446 {ISD::BITCAST, MVT::nxv4f16, MVT::nxv4i16, 0},
4447 {ISD::BITCAST, MVT::nxv2f32, MVT::nxv2i32, 0},
4448
4449 // Bitcasts from integer to float
4450 {ISD::BITCAST, MVT::nxv2i16, MVT::nxv2f16, 0},
4451 {ISD::BITCAST, MVT::nxv4i16, MVT::nxv4f16, 0},
4452 {ISD::BITCAST, MVT::nxv2i32, MVT::nxv2f32, 0},
4453
4454 // Add cost for extending to illegal -too wide- scalable vectors.
4455 // zero/sign extend are implemented by multiple unpack operations,
4456 // where each operation has a cost of 1.
4457 {ISD::ZERO_EXTEND, MVT::nxv16i16, MVT::nxv16i8, 2},
4458 {ISD::ZERO_EXTEND, MVT::nxv16i32, MVT::nxv16i8, 6},
4459 {ISD::ZERO_EXTEND, MVT::nxv16i64, MVT::nxv16i8, 14},
4460 {ISD::ZERO_EXTEND, MVT::nxv8i32, MVT::nxv8i16, 2},
4461 {ISD::ZERO_EXTEND, MVT::nxv8i64, MVT::nxv8i16, 6},
4462 {ISD::ZERO_EXTEND, MVT::nxv4i64, MVT::nxv4i32, 2},
4463
4464 {ISD::SIGN_EXTEND, MVT::nxv16i16, MVT::nxv16i8, 2},
4465 {ISD::SIGN_EXTEND, MVT::nxv16i32, MVT::nxv16i8, 6},
4466 {ISD::SIGN_EXTEND, MVT::nxv16i64, MVT::nxv16i8, 14},
4467 {ISD::SIGN_EXTEND, MVT::nxv8i32, MVT::nxv8i16, 2},
4468 {ISD::SIGN_EXTEND, MVT::nxv8i64, MVT::nxv8i16, 6},
4469 {ISD::SIGN_EXTEND, MVT::nxv4i64, MVT::nxv4i32, 2},
4470 };
4471
4472 if (const auto *Entry = ConvertCostTableLookup(
4473 ConversionTbl, ISD, DstTy.getSimpleVT(), SrcTy.getSimpleVT()))
4474 return Entry->Cost;
4475
4476 static const TypeConversionCostTblEntry FP16Tbl[] = {
4477 {ISD::FP_TO_SINT, MVT::v4i8, MVT::v4f16, 1}, // fcvtzs
4478 {ISD::FP_TO_UINT, MVT::v4i8, MVT::v4f16, 1},
4479 {ISD::FP_TO_SINT, MVT::v4i16, MVT::v4f16, 1}, // fcvtzs
4480 {ISD::FP_TO_UINT, MVT::v4i16, MVT::v4f16, 1},
4481 {ISD::FP_TO_SINT, MVT::v4i32, MVT::v4f16, 2}, // fcvtl+fcvtzs
4482 {ISD::FP_TO_UINT, MVT::v4i32, MVT::v4f16, 2},
4483 {ISD::FP_TO_SINT, MVT::v8i8, MVT::v8f16, 2}, // fcvtzs+xtn
4484 {ISD::FP_TO_UINT, MVT::v8i8, MVT::v8f16, 2},
4485 {ISD::FP_TO_SINT, MVT::v8i16, MVT::v8f16, 1}, // fcvtzs
4486 {ISD::FP_TO_UINT, MVT::v8i16, MVT::v8f16, 1},
4487 {ISD::FP_TO_SINT, MVT::v8i32, MVT::v8f16, 4}, // 2*fcvtl+2*fcvtzs
4488 {ISD::FP_TO_UINT, MVT::v8i32, MVT::v8f16, 4},
4489 {ISD::FP_TO_SINT, MVT::v16i8, MVT::v16f16, 3}, // 2*fcvtzs+xtn
4490 {ISD::FP_TO_UINT, MVT::v16i8, MVT::v16f16, 3},
4491 {ISD::FP_TO_SINT, MVT::v16i16, MVT::v16f16, 2}, // 2*fcvtzs
4492 {ISD::FP_TO_UINT, MVT::v16i16, MVT::v16f16, 2},
4493 {ISD::FP_TO_SINT, MVT::v16i32, MVT::v16f16, 8}, // 4*fcvtl+4*fcvtzs
4494 {ISD::FP_TO_UINT, MVT::v16i32, MVT::v16f16, 8},
4495 {ISD::UINT_TO_FP, MVT::v8f16, MVT::v8i8, 2}, // ushll + ucvtf
4496 {ISD::SINT_TO_FP, MVT::v8f16, MVT::v8i8, 2}, // sshll + scvtf
4497 {ISD::UINT_TO_FP, MVT::v16f16, MVT::v16i8, 4}, // 2 * ushl(2) + 2 * ucvtf
4498 {ISD::SINT_TO_FP, MVT::v16f16, MVT::v16i8, 4}, // 2 * sshl(2) + 2 * scvtf
4499 };
4500
4501 if (ST->hasFullFP16())
4502 if (const auto *Entry = ConvertCostTableLookup(
4503 FP16Tbl, ISD, DstTy.getSimpleVT(), SrcTy.getSimpleVT()))
4504 return Entry->Cost;
4505
4506 // INT_TO_FP of i64->f32 will scalarize, which is required to avoid
4507 // double-rounding issues.
4508 if ((ISD == ISD::SINT_TO_FP || ISD == ISD::UINT_TO_FP) &&
4509 DstTy.getScalarType() == MVT::f32 && SrcTy.getScalarSizeInBits() > 32 &&
4511 return cast<FixedVectorType>(Dst)->getNumElements() *
4512 getCastInstrCost(Opcode, Dst->getScalarType(),
4513 Src->getScalarType(), CCH, CostKind) +
4515 true, CostKind) +
4517 false, CostKind);
4518
4519 if ((ISD == ISD::ZERO_EXTEND || ISD == ISD::SIGN_EXTEND) &&
4521 ST->isSVEorStreamingSVEAvailable() &&
4522 TLI->getTypeAction(Src->getContext(), SrcTy) ==
4524 TLI->getTypeAction(Dst->getContext(), DstTy) ==
4526 // The standard behaviour in the backend for these cases is to split the
4527 // extend up into two parts:
4528 // 1. Perform an extending load or masked load up to the legal type.
4529 // 2. Extend the loaded data to the final type.
4530 std::pair<InstructionCost, MVT> SrcLT = getTypeLegalizationCost(Src);
4531 Type *LegalTy = EVT(SrcLT.second).getTypeForEVT(Src->getContext());
4533 Opcode, LegalTy, Src, CCH, CostKind, I);
4535 Opcode, Dst, LegalTy, TTI::CastContextHint::None, CostKind, I);
4536 return Part1 + Part2;
4537 }
4538
4539 // The BasicTTIImpl version only deals with CCH==TTI::CastContextHint::Normal,
4540 // but we also want to include the TTI::CastContextHint::Masked case too.
4541 if ((ISD == ISD::ZERO_EXTEND || ISD == ISD::SIGN_EXTEND) &&
4543 ST->isSVEorStreamingSVEAvailable() && TLI->isTypeLegal(DstTy))
4545
4546 return BaseT::getCastInstrCost(Opcode, Dst, Src, CCH, CostKind, I);
4547}
4548
4551 VectorType *VecTy, unsigned Index,
4553
4554 // Make sure we were given a valid extend opcode.
4555 assert((Opcode == Instruction::SExt || Opcode == Instruction::ZExt) &&
4556 "Invalid opcode");
4557
4558 // We are extending an element we extract from a vector, so the source type
4559 // of the extend is the element type of the vector.
4560 auto *Src = VecTy->getElementType();
4561
4562 // Sign- and zero-extends are for integer types only.
4563 assert(isa<IntegerType>(Dst) && isa<IntegerType>(Src) && "Invalid type");
4564
4565 // Get the cost for the extract. We compute the cost (if any) for the extend
4566 // below.
4567 InstructionCost Cost = getVectorInstrCost(Instruction::ExtractElement, VecTy,
4568 CostKind, Index, nullptr, nullptr);
4569
4570 // Legalize the types.
4571 auto VecLT = getTypeLegalizationCost(VecTy);
4572 auto DstVT = TLI->getValueType(DL, Dst);
4573 auto SrcVT = TLI->getValueType(DL, Src);
4574
4575 // If the resulting type is still a vector and the destination type is legal,
4576 // we may get the extension for free. If not, get the default cost for the
4577 // extend.
4578 if (!VecLT.second.isVector() || !TLI->isTypeLegal(DstVT))
4579 return Cost + getCastInstrCost(Opcode, Dst, Src, TTI::CastContextHint::None,
4580 CostKind);
4581
4582 // The destination type should be larger than the element type. If not, get
4583 // the default cost for the extend.
4584 if (DstVT.getFixedSizeInBits() < SrcVT.getFixedSizeInBits())
4585 return Cost + getCastInstrCost(Opcode, Dst, Src, TTI::CastContextHint::None,
4586 CostKind);
4587
4588 switch (Opcode) {
4589 default:
4590 llvm_unreachable("Opcode should be either SExt or ZExt");
4591
4592 // For sign-extends, we only need a smov, which performs the extension
4593 // automatically.
4594 case Instruction::SExt:
4595 return Cost;
4596
4597 // For zero-extends, the extend is performed automatically by a umov unless
4598 // the destination type is i64 and the element type is i8 or i16.
4599 case Instruction::ZExt:
4600 if (DstVT.getSizeInBits() != 64u || SrcVT.getSizeInBits() == 32u)
4601 return Cost;
4602 }
4603
4604 // If we are unable to perform the extend for free, get the default cost.
4605 return Cost + getCastInstrCost(Opcode, Dst, Src, TTI::CastContextHint::None,
4606 CostKind);
4607}
4608
4611 const Instruction *I) const {
4613 return Opcode == Instruction::PHI ? 0 : 1;
4614 assert(CostKind == TTI::TCK_RecipThroughput && "unexpected CostKind");
4615 // Branches are assumed to be predicted.
4616 return 0;
4617}
4618
4619InstructionCost AArch64TTIImpl::getVectorInstrCostHelper(
4620 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index,
4621 const Instruction *I, Value *Scalar,
4622 ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx,
4623 TTI::VectorInstrContext VIC) const {
4624 assert(Ty->isVectorTy() && "This must be a vector type");
4625
4626 if (Index != -1U) {
4627 // Legalize the type.
4628 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);
4629
4630 // This type is legalized to a scalar type.
4631 if (!LT.second.isVector())
4632 return 0;
4633
4634 // The type may be split. For fixed-width vectors we can normalize the
4635 // index to the new type.
4636 if (LT.second.isFixedLengthVector()) {
4637 unsigned Width = LT.second.getVectorNumElements();
4638 Index = Index % Width;
4639 }
4640
4641 // The element at index zero is already inside the vector.
4642 // - For a insert-element or extract-element
4643 // instruction that extracts integers, an explicit FPR -> GPR move is
4644 // needed. So it has non-zero cost.
4645 if (Index == 0 && !Ty->getScalarType()->isIntegerTy())
4646 return 0;
4647
4648 // SVE has no scalar move to an arbitrary lane above the low 128-bit portion
4649 // of a Z register, e.g. there is no equivalent of "mov z0.d[9], d0".
4650 // Fixed-length vectors wider than 128 bits therefore need
4651 // [splice]/index/pred/splat/cmp/pred-mov when scalarizing inserts for those
4652 // lanes, so model them as more expensive than ordinary NEON lane accesses.
4653 if (ST->useSVEForFixedLengthVectors()) {
4655 ? 1
4657 if (Index * Ty->getScalarSizeInBits() < 128)
4658 return Cost;
4659 if (Index * Ty->getScalarSizeInBits() < 512 &&
4660 Opcode == Instruction::ExtractElement)
4661 // Integer extracts (>128b, <512b) require extra mov from FPR -> GPR.
4662 return Ty->getScalarType()->isIntegerTy() ? Cost + 1 : Cost;
4663 if (Opcode == Instruction::ExtractElement)
4664 return Cost + 2; // cost of mov imm + whilels + lastb
4665 if (Opcode == Instruction::InsertElement)
4666 return Cost + 3; // cost of insert with cmp/splice
4667 llvm_unreachable("unexpected opcode");
4668 }
4669
4670 // This is recognising a LD1 single-element structure to one lane of one
4671 // register instruction. I.e., if this is an `insertelement` instruction,
4672 // and its second operand is a load, then we will generate a LD1, which
4673 // are expensive instructions on some uArchs.
4674 if (VIC == TTI::VectorInstrContext::Load) {
4675 if (ST->hasFastLD1Single())
4676 return 0;
4677 return CostKind == TTI::TCK_CodeSize
4678 ? 0
4679 : ST->getVectorInsertExtractBaseCost() + 1;
4680 }
4681
4682 // i1 inserts and extract will include an extra cset or cmp of the vector
4683 // value. Increase the cost by 1 to account.
4684 if (Ty->getScalarSizeInBits() == 1)
4685 return CostKind == TTI::TCK_CodeSize
4686 ? 2
4687 : ST->getVectorInsertExtractBaseCost() + 1;
4688
4689 // FIXME:
4690 // If the extract-element and insert-element instructions could be
4691 // simplified away (e.g., could be combined into users by looking at use-def
4692 // context), they have no cost. This is not done in the first place for
4693 // compile-time considerations.
4694 }
4695
4696 // In case of Neon, if there exists extractelement from lane != 0 such that
4697 // 1. extractelement does not necessitate a move from vector_reg -> GPR.
4698 // 2. extractelement result feeds into fmul.
4699 // 3. Other operand of fmul is an extractelement from lane 0 or lane
4700 // equivalent to 0.
4701 // then the extractelement can be merged with fmul in the backend and it
4702 // incurs no cost.
4703 // e.g.
4704 // define double @foo(<2 x double> %a) {
4705 // %1 = extractelement <2 x double> %a, i32 0
4706 // %2 = extractelement <2 x double> %a, i32 1
4707 // %res = fmul double %1, %2
4708 // ret double %res
4709 // }
4710 // %2 and %res can be merged in the backend to generate fmul d0, d0, v1.d[1]
4711 auto ExtractCanFuseWithFmul = [&]() {
4712 // We bail out if the extract is from lane 0.
4713 if (Index == 0)
4714 return false;
4715
4716 // Check if the scalar element type of the vector operand of ExtractElement
4717 // instruction is one of the allowed types.
4718 auto IsAllowedScalarTy = [&](const Type *T) {
4719 return T->isFloatTy() || T->isDoubleTy() ||
4720 (T->isHalfTy() && ST->hasFullFP16());
4721 };
4722
4723 // Check if the extractelement user is scalar fmul.
4724 auto IsUserFMulScalarTy = [](const Value *EEUser) {
4725 // Check if the user is scalar fmul.
4726 const auto *BO = dyn_cast<BinaryOperator>(EEUser);
4727 return BO && BO->getOpcode() == BinaryOperator::FMul &&
4728 !BO->getType()->isVectorTy();
4729 };
4730
4731 // Check if the extract index is from lane 0 or lane equivalent to 0 for a
4732 // certain scalar type and a certain vector register width.
4733 auto IsExtractLaneEquivalentToZero = [&](unsigned Idx, unsigned EltSz) {
4734 auto RegWidth =
4736 .getFixedValue();
4737 return Idx == 0 || (RegWidth != 0 && (Idx * EltSz) % RegWidth == 0);
4738 };
4739
4740 // Check if the type constraints on input vector type and result scalar type
4741 // of extractelement instruction are satisfied.
4742 if (!isa<FixedVectorType>(Ty) || !IsAllowedScalarTy(Ty->getScalarType()))
4743 return false;
4744
4745 if (Scalar) {
4746 DenseMap<User *, unsigned> UserToExtractIdx;
4747 for (auto *U : Scalar->users()) {
4748 if (!IsUserFMulScalarTy(U))
4749 return false;
4750 // Recording entry for the user is important. Index value is not
4751 // important.
4752 UserToExtractIdx[U];
4753 }
4754 if (UserToExtractIdx.empty())
4755 return false;
4756 for (auto &[S, U, L] : ScalarUserAndIdx) {
4757 for (auto *U : S->users()) {
4758 if (UserToExtractIdx.contains(U)) {
4759 auto *FMul = cast<BinaryOperator>(U);
4760 auto *Op0 = FMul->getOperand(0);
4761 auto *Op1 = FMul->getOperand(1);
4762 if ((Op0 == S && Op1 == S) || Op0 != S || Op1 != S) {
4763 UserToExtractIdx[U] = L;
4764 break;
4765 }
4766 }
4767 }
4768 }
4769 for (auto &[U, L] : UserToExtractIdx) {
4770 if (!IsExtractLaneEquivalentToZero(Index, Ty->getScalarSizeInBits()) &&
4771 !IsExtractLaneEquivalentToZero(L, Ty->getScalarSizeInBits()))
4772 return false;
4773 }
4774 } else {
4775 const auto *EE = cast<ExtractElementInst>(I);
4776
4777 const auto *IdxOp = dyn_cast<ConstantInt>(EE->getIndexOperand());
4778 if (!IdxOp)
4779 return false;
4780
4781 return !EE->users().empty() && all_of(EE->users(), [&](const User *U) {
4782 if (!IsUserFMulScalarTy(U))
4783 return false;
4784
4785 // Check if the other operand of extractelement is also extractelement
4786 // from lane equivalent to 0.
4787 const auto *BO = cast<BinaryOperator>(U);
4788 const auto *OtherEE = dyn_cast<ExtractElementInst>(
4789 BO->getOperand(0) == EE ? BO->getOperand(1) : BO->getOperand(0));
4790 if (OtherEE) {
4791 const auto *IdxOp = dyn_cast<ConstantInt>(OtherEE->getIndexOperand());
4792 if (!IdxOp)
4793 return false;
4794 return IsExtractLaneEquivalentToZero(
4795 cast<ConstantInt>(OtherEE->getIndexOperand())
4796 ->getValue()
4797 .getZExtValue(),
4798 OtherEE->getType()->getScalarSizeInBits());
4799 }
4800 return true;
4801 });
4802 }
4803 return true;
4804 };
4805
4806 if (Opcode == Instruction::ExtractElement && (I || Scalar) &&
4807 ExtractCanFuseWithFmul())
4808 return 0;
4809
4810 // All other insert/extracts cost this much.
4811 return CostKind == TTI::TCK_CodeSize ? 1
4812 : ST->getVectorInsertExtractBaseCost();
4813}
4814
4816 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index,
4817 const Value *Op0, const Value *Op1, TTI::VectorInstrContext VIC) const {
4818 // Treat insert at lane 0 into a poison vector as having zero cost. This
4819 // ensures vector broadcasts via an insert + shuffle (and will be lowered to a
4820 // single dup) are treated as cheap.
4821 if (Opcode == Instruction::InsertElement && Index == 0 && Op0 &&
4822 isa<PoisonValue>(Op0))
4823 return 0;
4824 return getVectorInstrCostHelper(Opcode, Ty, CostKind, Index, nullptr, nullptr,
4825 {}, VIC);
4826}
4827
4829 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index,
4830 Value *Scalar, ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx,
4831 TTI::VectorInstrContext VIC) const {
4832 return getVectorInstrCostHelper(Opcode, Ty, CostKind, Index, nullptr, Scalar,
4833 ScalarUserAndIdx, VIC);
4834}
4835
4838 TTI::TargetCostKind CostKind, unsigned Index,
4839 TTI::VectorInstrContext VIC) const {
4840 return getVectorInstrCostHelper(I.getOpcode(), Ty, CostKind, Index, &I,
4841 nullptr, {}, VIC);
4842}
4843
4847 unsigned Index) const {
4848 if (isa<FixedVectorType>(Ty))
4849 return BaseT::getIndexedVectorInstrCostFromEnd(Opcode, Ty, CostKind, Index);
4850
4851 // This typically requires both while and lastb instructions in order
4852 // to extract the last element. If this is in a loop the while
4853 // instruction can at least be hoisted out, although it will consume a
4854 // predicate register. The cost should be more expensive than the base
4855 // extract cost, which is 2 for most CPUs.
4856 return CostKind == TTI::TCK_CodeSize
4857 ? 2
4858 : ST->getVectorInsertExtractBaseCost() + 1;
4859}
4860
4862 VectorType *Ty, const APInt &DemandedElts, bool Insert, bool Extract,
4863 TTI::TargetCostKind CostKind, bool ForPoisonSrc, ArrayRef<Value *> VL,
4864 TTI::VectorInstrContext VIC) const {
4867 if (Ty->getElementType()->isFloatingPointTy())
4868 return BaseT::getScalarizationOverhead(Ty, DemandedElts, Insert, Extract,
4869 CostKind);
4870 unsigned VecInstCost =
4871 CostKind == TTI::TCK_CodeSize ? 1 : ST->getVectorInsertExtractBaseCost();
4872 return DemandedElts.popcount() * (Insert + Extract) * VecInstCost;
4873}
4874
4875std::optional<InstructionCost> AArch64TTIImpl::getFP16BF16PromoteCost(
4877 TTI::OperandValueInfo Op2Info, bool IncludeTrunc, bool CanUseSVE,
4878 std::function<InstructionCost(Type *)> InstCost) const {
4879 if (!Ty->getScalarType()->isHalfTy() && !Ty->getScalarType()->isBFloatTy())
4880 return std::nullopt;
4881 if (Ty->getScalarType()->isHalfTy() && ST->hasFullFP16())
4882 return std::nullopt;
4883 // If we have +sve-b16b16 the operation can be promoted to SVE.
4884 if (CanUseSVE && ST->hasSVEB16B16() && ST->isNonStreamingSVEorSME2Available())
4885 return std::nullopt;
4886
4887 Type *PromotedTy = Ty->getWithNewType(Type::getFloatTy(Ty->getContext()));
4888 InstructionCost Cost = getCastInstrCost(Instruction::FPExt, PromotedTy, Ty,
4890 if (!Op1Info.isConstant() && !Op2Info.isConstant())
4891 Cost *= 2;
4892 Cost += InstCost(PromotedTy);
4893 if (IncludeTrunc)
4894 Cost += getCastInstrCost(Instruction::FPTrunc, Ty, PromotedTy,
4896 return Cost;
4897}
4898
4900 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
4902 ArrayRef<const Value *> Args, const Instruction *CxtI) const {
4903
4904 // The code-generator is currently not able to handle scalable vectors
4905 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
4906 // it. This change will be removed when code-generation for these types is
4907 // sufficiently reliable.
4908 if (auto *VTy = dyn_cast<ScalableVectorType>(Ty))
4909 if (VTy->getElementCount() == ElementCount::getScalable(1))
4911
4912 // Legalize the type.
4913 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);
4914 int ISD = TLI->InstructionOpcodeToISD(Opcode);
4915
4916 // TODO: Handle more cost kinds for floating point operations.
4917 if (ISD == ISD::FADD || ISD == ISD::FSUB || ISD == ISD::FMUL ||
4918 ISD == ISD::FDIV || ISD == ISD::FREM || ISD == ISD::FNEG)
4920 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,
4921 Op2Info, Args, CxtI);
4922
4923 if (ISD == ISD::FADD || ISD == ISD::FSUB || ISD == ISD::FMUL ||
4924 ISD == ISD::FDIV || ISD == ISD::FREM) {
4925 // Increase the cost for half and bfloat types if not architecturally
4926 // supported.
4927 if (auto PromotedCost = getFP16BF16PromoteCost(
4928 Ty, CostKind, Op1Info, Op2Info, /*IncludeTrunc=*/true,
4929 // There is not native support for fdiv/frem even with +sve-b16b16.
4930 /*CanUseSVE=*/ISD != ISD::FDIV && ISD != ISD::FREM,
4931 [&](Type *PromotedTy) {
4932 return getArithmeticInstrCost(Opcode, PromotedTy, CostKind,
4933 Op1Info, Op2Info);
4934 }))
4935 return *PromotedCost;
4936
4937 // fp128 all go via libcalls
4938 if (Ty->getScalarType()->isFP128Ty())
4939 return (CostKind == TTI::TCK_CodeSize ? 1 : 10) * LT.first;
4940 }
4941
4942 // If the operation is a widening instruction (smull or umull) and both
4943 // operands are extends the cost can be cheaper by considering that the
4944 // operation will operate on the narrowest type size possible (double the
4945 // largest input size) and a further extend.
4946 if (Type *ExtTy = isBinExtWideningInstruction(Opcode, Ty, Args)) {
4947 if (ExtTy != Ty)
4948 return getArithmeticInstrCost(Opcode, ExtTy, CostKind) +
4949 getCastInstrCost(Instruction::ZExt, Ty, ExtTy,
4951 return LT.first;
4952 }
4953
4954 switch (ISD) {
4955 default:
4956 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,
4957 Op2Info);
4958 case ISD::ADD:
4959 case ISD::SUB:
4960 return LT.first; // Also works for i128
4961 case ISD::MUL: {
4962 // i128 multiply is umulh + 2*madd + mul and grows ~O(Bitwidth^2). For
4963 // scalable vectors the cost of LT.first will be invalid, leading to an
4964 // invalid cost overall.
4965 unsigned Mul64CostFactor = (CostKind == TTI::TCK_RecipThroughput &&
4966 ST->hasLimited64bitVectorMulBandwidth())
4967 ? 4
4968 : 1;
4969 if (Ty->getScalarSizeInBits() > 64) {
4970 unsigned NumLanes = isa<FixedVectorType>(Ty)
4971 ? cast<FixedVectorType>(Ty)->getNumElements()
4972 : 1;
4973 InstructionCost CostPerLane = LT.first / NumLanes;
4974 return CostPerLane * CostPerLane * NumLanes * Mul64CostFactor;
4975 }
4976
4977 if (LT.second == MVT::v2i64) {
4978 // When SVE is available, then we can lower the v2i64 operation using
4979 // the SVE mul instruction, which has a lower cost.
4980 if (ST->hasSVE())
4981 return LT.first * Mul64CostFactor;
4982
4983 // When SVE is not available, there is no MUL.2d instruction,
4984 // which means mul <2 x i64> is expensive as elements are extracted
4985 // from the vectors and the muls scalarized.
4986 // As getScalarizationOverhead is a bit too pessimistic, we
4987 // estimate the cost for a i64 vector directly here, which is:
4988 // - four 2-cost i64 extracts,
4989 // - two 2-cost i64 inserts, and
4990 // - two 1-cost muls.
4991 // So, for a v2i64 with LT.First = 1 the cost is 14, and for a v4i64 with
4992 // LT.first = 2 the cost is 28.
4993 return cast<VectorType>(Ty)->getElementCount().getKnownMinValue() *
4994 (getArithmeticInstrCost(Opcode, Ty->getScalarType(), CostKind) +
4995 getVectorInstrCost(Instruction::ExtractElement, Ty, CostKind, -1,
4996 nullptr, nullptr) *
4997 2 +
4998 getVectorInstrCost(Instruction::InsertElement, Ty, CostKind, -1,
4999 nullptr, nullptr));
5000 }
5001
5002 if (LT.second == MVT::nxv2i64)
5003 return LT.first * Mul64CostFactor;
5004
5005 return LT.first;
5006 }
5007 case ISD::SREM:
5008 case ISD::SDIV:
5009 /*
5010 Notes for sdiv/srem specific costs:
5011 1. This only considers the cases where the divisor is constant, uniform and
5012 (pow-of-2/non-pow-of-2). Other cases are not important since they either
5013 result in some form of (ldr + adrp), corresponding to constant vectors, or
5014 scalarization of the division operation.
5015 2. Constant divisors, either negative in whole or partially, don't result in
5016 significantly different codegen as compared to positive constant divisors.
5017 So, we don't consider negative divisors separately.
5018 3. If the codegen is significantly different with SVE, it has been indicated
5019 using comments at appropriate places.
5020
5021 sdiv specific cases:
5022 -----------------------------------------------------------------------
5023 codegen | pow-of-2 | Type
5024 -----------------------------------------------------------------------
5025 add + cmp + csel + asr | Y | i64
5026 add + cmp + csel + asr | Y | i32
5027 -----------------------------------------------------------------------
5028
5029 srem specific cases:
5030 -----------------------------------------------------------------------
5031 codegen | pow-of-2 | Type
5032 -----------------------------------------------------------------------
5033 negs + and + and + csneg | Y | i64
5034 negs + and + and + csneg | Y | i32
5035 -----------------------------------------------------------------------
5036
5037 other sdiv/srem cases:
5038 -------------------------------------------------------------------------
5039 common codegen | + srem | + sdiv | pow-of-2 | Type
5040 -------------------------------------------------------------------------
5041 smulh + asr + add + add | - | - | N | i64
5042 smull + lsr + add + add | - | - | N | i32
5043 usra | and + sub | sshr | Y | <2 x i64>
5044 2 * (scalar code) | - | - | N | <2 x i64>
5045 usra | bic + sub | sshr + neg | Y | <4 x i32>
5046 smull2 + smull + uzp2 | mls | - | N | <4 x i32>
5047 + sshr + usra | | | |
5048 -------------------------------------------------------------------------
5049 */
5050 if (Op2Info.isConstant() && Op2Info.isUniform()) {
5051 InstructionCost AddCost =
5052 getArithmeticInstrCost(Instruction::Add, Ty, CostKind,
5053 Op1Info.getNoProps(), Op2Info.getNoProps());
5054 InstructionCost AsrCost =
5055 getArithmeticInstrCost(Instruction::AShr, Ty, CostKind,
5056 Op1Info.getNoProps(), Op2Info.getNoProps());
5057 InstructionCost MulCost =
5058 getArithmeticInstrCost(Instruction::Mul, Ty, CostKind,
5059 Op1Info.getNoProps(), Op2Info.getNoProps());
5060 // add/cmp/csel/csneg should have similar cost while asr/negs/and should
5061 // have similar cost.
5062 auto VT = TLI->getValueType(DL, Ty);
5063 if (VT.isScalarInteger() && VT.getSizeInBits() <= 64) {
5064 if (Op2Info.isPowerOf2() || Op2Info.isNegatedPowerOf2()) {
5065 // Neg can be folded into the asr instruction.
5066 return ISD == ISD::SDIV ? (3 * AddCost + AsrCost)
5067 : (3 * AsrCost + AddCost);
5068 } else {
5069 return MulCost + AsrCost + 2 * AddCost;
5070 }
5071 } else if (VT.isVector()) {
5072 InstructionCost UsraCost = 2 * AsrCost;
5073 if (Op2Info.isPowerOf2() || Op2Info.isNegatedPowerOf2()) {
5074 // Division with scalable types corresponds to native 'asrd'
5075 // instruction when SVE is available.
5076 // e.g. %1 = sdiv <vscale x 4 x i32> %a, splat (i32 8)
5077
5078 // One more for the negation in SDIV
5080 (Op2Info.isNegatedPowerOf2() && ISD == ISD::SDIV) ? AsrCost : 0;
5081 if (Ty->isScalableTy() && ST->hasSVE())
5082 Cost += 2 * AsrCost;
5083 else {
5084 Cost +=
5085 UsraCost +
5086 (ISD == ISD::SDIV
5087 ? (LT.second.getScalarType() == MVT::i64 ? 1 : 2) * AsrCost
5088 : 2 * AddCost);
5089 }
5090 return Cost;
5091 } else if (LT.second == MVT::v2i64) {
5092 return VT.getVectorNumElements() *
5093 getArithmeticInstrCost(Opcode, Ty->getScalarType(), CostKind,
5094 Op1Info.getNoProps(),
5095 Op2Info.getNoProps());
5096 } else {
5097 // When SVE is available, we get:
5098 // smulh + lsr + add/sub + asr + add/sub.
5099 if (Ty->isScalableTy() && ST->hasSVE())
5100 return MulCost /*smulh cost*/ + 2 * AddCost + 2 * AsrCost;
5101 return 2 * MulCost + AddCost /*uzp2 cost*/ + AsrCost + UsraCost;
5102 }
5103 }
5104 }
5105 if (Op2Info.isConstant() && !Op2Info.isUniform() &&
5106 LT.second.isFixedLengthVector()) {
5107 // FIXME: When the constant vector is non-uniform, this may result in
5108 // loading the vector from constant pool or in some cases, may also result
5109 // in scalarization. For now, we are approximating this with the
5110 // scalarization cost.
5111 auto ExtractCost = 2 * getVectorInstrCost(Instruction::ExtractElement, Ty,
5112 CostKind, -1, nullptr, nullptr);
5113 auto InsertCost = getVectorInstrCost(Instruction::InsertElement, Ty,
5114 CostKind, -1, nullptr, nullptr);
5115 unsigned NElts = cast<FixedVectorType>(Ty)->getNumElements();
5116 return ExtractCost + InsertCost +
5117 NElts * getArithmeticInstrCost(Opcode, Ty->getScalarType(),
5118 CostKind, Op1Info.getNoProps(),
5119 Op2Info.getNoProps());
5120 }
5121 [[fallthrough]];
5122 case ISD::UDIV:
5123 case ISD::UREM: {
5124 auto VT = TLI->getValueType(DL, Ty);
5125 if (Op2Info.isConstant()) {
5126 // If the operand is a power of 2 we can use the shift or and cost.
5127 if (ISD == ISD::UDIV && Op2Info.isPowerOf2())
5128 return getArithmeticInstrCost(Instruction::LShr, Ty, CostKind,
5129 Op1Info.getNoProps(),
5130 Op2Info.getNoProps());
5131 if (ISD == ISD::UREM && Op2Info.isPowerOf2())
5132 return getArithmeticInstrCost(Instruction::And, Ty, CostKind,
5133 Op1Info.getNoProps(),
5134 Op2Info.getNoProps());
5135
5136 if (ISD == ISD::UDIV || ISD == ISD::UREM) {
5137 // Divides by a constant are expanded to MULHU + SUB + SRL + ADD + SRL.
5138 // The MULHU will be expanded to UMULL for the types not listed below,
5139 // and will become a pair of UMULL+MULL2 for 128bit vectors.
5140 bool HasMULH = VT == MVT::i64 || LT.second == MVT::nxv2i64 ||
5141 LT.second == MVT::nxv4i32 || LT.second == MVT::nxv8i16 ||
5142 LT.second == MVT::nxv16i8;
5143 bool Is128bit = LT.second.is128BitVector();
5144
5145 InstructionCost MulCost =
5146 getArithmeticInstrCost(Instruction::Mul, Ty, CostKind,
5147 Op1Info.getNoProps(), Op2Info.getNoProps());
5148 InstructionCost AddCost =
5149 getArithmeticInstrCost(Instruction::Add, Ty, CostKind,
5150 Op1Info.getNoProps(), Op2Info.getNoProps());
5151 InstructionCost ShrCost =
5152 getArithmeticInstrCost(Instruction::AShr, Ty, CostKind,
5153 Op1Info.getNoProps(), Op2Info.getNoProps());
5154 InstructionCost DivCost = MulCost * (Is128bit ? 2 : 1) + // UMULL/UMULH
5155 (HasMULH ? 0 : ShrCost) + // UMULL shift
5156 AddCost * 2 + ShrCost;
5157 return DivCost + (ISD == ISD::UREM ? MulCost + AddCost : 0);
5158 }
5159 }
5160
5161 // div i128's are lowered as libcalls. Pass nullptr as (u)divti3 calls are
5162 // emitted by the backend even when those functions are not declared in the
5163 // module.
5164 if (!VT.isVector() && VT.getSizeInBits() > 64)
5165 return getCallInstrCost(/*Function*/ nullptr, Ty, {Ty, Ty}, CostKind);
5166
5168 Opcode, Ty, CostKind, Op1Info, Op2Info);
5169 if (Ty->isVectorTy() && (ISD == ISD::SDIV || ISD == ISD::UDIV)) {
5170 if (TLI->isOperationLegalOrCustom(ISD, LT.second) && ST->hasSVE()) {
5171 // SDIV/UDIV operations are lowered using SVE, then we can have less
5172 // costs.
5173 if (VT.isSimple() && isa<FixedVectorType>(Ty) &&
5174 Ty->getPrimitiveSizeInBits().getFixedValue() < 128) {
5175 static const CostTblEntry DivTbl[]{
5176 {ISD::SDIV, MVT::v2i8, 5}, {ISD::SDIV, MVT::v4i8, 8},
5177 {ISD::SDIV, MVT::v8i8, 8}, {ISD::SDIV, MVT::v2i16, 5},
5178 {ISD::SDIV, MVT::v4i16, 5}, {ISD::SDIV, MVT::v2i32, 1},
5179 {ISD::UDIV, MVT::v2i8, 5}, {ISD::UDIV, MVT::v4i8, 8},
5180 {ISD::UDIV, MVT::v8i8, 8}, {ISD::UDIV, MVT::v2i16, 5},
5181 {ISD::UDIV, MVT::v4i16, 5}, {ISD::UDIV, MVT::v2i32, 1}};
5182
5183 const auto *Entry = CostTableLookup(DivTbl, ISD, VT.getSimpleVT());
5184 if (nullptr != Entry)
5185 return Entry->Cost;
5186 }
5187 // A non-power-of-2 count can't divide as a single whole-register op
5188 // (an inactive lane's leftover value could be a zero divisor and
5189 // trap), so the legalizer emits one div per whole register plus one
5190 // per set bit of the remainder (e.g. <7 x i32> emits 3 divs, not 2).
5191 if (auto *FVTy = dyn_cast<FixedVectorType>(Ty);
5192 FVTy && LT.second.isFixedLengthVector()) {
5193 unsigned NumElts = FVTy->getNumElements();
5194 unsigned RegElts = LT.second.getVectorNumElements();
5195 if (RegElts > 0)
5196 Cost = (NumElts / RegElts + popcount(NumElts % RegElts)) * 2;
5197 }
5198 // For 8/16-bit elements, the cost is higher because the type
5199 // requires promotion and possibly splitting:
5200 if (LT.second.getScalarType() == MVT::i8)
5201 Cost *= 8;
5202 else if (LT.second.getScalarType() == MVT::i16)
5203 Cost *= 4;
5204 return Cost;
5205 } else {
5206 // If one of the operands is a uniform constant then the cost for each
5207 // element is Cost for insertion, extraction and division.
5208 // Insertion cost = 2, Extraction Cost = 2, Division = cost for the
5209 // operation with scalar type
5210 if ((Op1Info.isConstant() && Op1Info.isUniform()) ||
5211 (Op2Info.isConstant() && Op2Info.isUniform())) {
5212 if (auto *VTy = dyn_cast<FixedVectorType>(Ty)) {
5214 Opcode, Ty->getScalarType(), CostKind, Op1Info, Op2Info);
5215 return (4 + DivCost) * VTy->getNumElements();
5216 }
5217 }
5218 // On AArch64, without SVE, vector divisions are expanded
5219 // into scalar divisions of each pair of elements.
5220 Cost += getVectorInstrCost(Instruction::ExtractElement, Ty, CostKind,
5221 -1, nullptr, nullptr);
5222 Cost += getVectorInstrCost(Instruction::InsertElement, Ty, CostKind, -1,
5223 nullptr, nullptr);
5224 }
5225
5226 // TODO: if one of the arguments is scalar, then it's not necessary to
5227 // double the cost of handling the vector elements.
5228 Cost += Cost;
5229 }
5230 return Cost;
5231 }
5232 case ISD::XOR:
5233 case ISD::OR:
5234 case ISD::AND:
5235 // TODO: revisit these costs as it's not accurate enough for non-uniform
5236 // constant.
5237 return LT.first;
5238 case ISD::SRL:
5239 case ISD::SRA:
5240 case ISD::SHL: {
5241 // Immediate vector shifts require uniform shift amounts. Non-uniform
5242 // constants therefore use variable shifts and require materializing the
5243 // shift vector. Account for a shift and materialization per legalized
5244 // vector, together with shared setup.
5245 // This cost is for (ldr, shl) + adrp
5246 // TODO: These costs are based on CodeSize only, consider other CostKinds.
5247 if (Op2Info.isConstant() && !Op2Info.isUniform() &&
5248 LT.second.isFixedLengthVector())
5249 return 2 * LT.first + 1;
5250
5251 // Marked 'custom' for combining purposes; a uniform shift amount still
5252 // lowers to a single legal instruction.
5253 return LT.first;
5254 }
5255
5256 case ISD::FNEG:
5257 // Scalar fmul(fneg) or fneg(fmul) can be converted to fnmul
5258 if ((Ty->isFloatTy() || Ty->isDoubleTy() ||
5259 (Ty->isHalfTy() && ST->hasFullFP16())) &&
5260 CxtI &&
5261 ((CxtI->hasOneUse() &&
5262 match(*CxtI->user_begin(), m_FMul(m_Value(), m_Value()))) ||
5263 match(CxtI->getOperand(0), m_FMul(m_Value(), m_Value()))))
5264 return 0;
5265 [[fallthrough]];
5266 case ISD::FADD:
5267 case ISD::FSUB:
5268 if (!Ty->getScalarType()->isFP128Ty())
5269 return LT.first;
5270 [[fallthrough]];
5271 case ISD::FMUL:
5272 case ISD::FDIV:
5273 // These nodes are marked as 'custom' just to lower them to SVE.
5274 // We know said lowering will incur no additional cost.
5275 if (!Ty->getScalarType()->isFP128Ty())
5276 return 2 * LT.first;
5277
5278 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,
5279 Op2Info);
5280 case ISD::FREM:
5281 // Pass nullptr as fmod/fmodf calls are emitted by the backend even when
5282 // those functions are not declared in the module.
5283 if (!Ty->isVectorTy())
5284 return getCallInstrCost(/*Function*/ nullptr, Ty, {Ty, Ty}, CostKind);
5285 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Op1Info,
5286 Op2Info);
5287 }
5288}
5289
5292 const SCEV *Ptr,
5294 // Address computations in vectorized code with non-consecutive addresses will
5295 // likely result in more instructions compared to scalar code where the
5296 // computation can more often be merged into the index mode. The resulting
5297 // extra micro-ops can significantly decrease throughput.
5298 unsigned NumVectorInstToHideOverhead = NeonNonConstStrideOverhead;
5299 int MaxMergeDistance = 64;
5300
5301 if (PtrTy->isVectorTy() && SE &&
5302 !BaseT::isConstantStridedAccessLessThan(SE, Ptr, MaxMergeDistance + 1))
5303 return NumVectorInstToHideOverhead;
5304
5305 // In many cases the address computation is not merged into the instruction
5306 // addressing mode.
5307 return 1;
5308}
5309
5310/// Check whether Opcode1 has less throughput according to the scheduling
5311/// model than Opcode2.
5313 unsigned Opcode1, unsigned Opcode2) const {
5314 const MCSchedModel &Sched = ST->getSchedModel();
5315 const TargetInstrInfo *TII = ST->getInstrInfo();
5316 if (!Sched.hasInstrSchedModel())
5317 return false;
5318
5319 const MCSchedClassDesc *SCD1 =
5320 Sched.getSchedClassDesc(TII->get(Opcode1).getSchedClass());
5321 const MCSchedClassDesc *SCD2 =
5322 Sched.getSchedClassDesc(TII->get(Opcode2).getSchedClass());
5323 // We cannot handle variant scheduling classes without an MI. If we need to
5324 // support them for any of the instructions we query the information of we
5325 // might need to add a way to resolve them without a MI or not use the
5326 // scheduling info.
5327 assert(!SCD1->isVariant() && !SCD2->isVariant() &&
5328 "Cannot handle variant scheduling classes without an MI");
5329 if (!SCD1->isValid() || !SCD2->isValid())
5330 return false;
5331
5332 return MCSchedModel::getReciprocalThroughput(*ST, *SCD1) >
5334}
5335
5337 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
5339 TTI::OperandValueInfo Op2Info, const Instruction *I) const {
5340 // We don't lower some vector selects well that are wider than the register
5341 // width. TODO: Improve this with different cost kinds.
5342 if (isa<FixedVectorType>(ValTy) && Opcode == Instruction::Select) {
5343 // We would need this many instructions to hide the scalarization happening.
5344 const int AmortizationCost = 20;
5345
5346 // If VecPred is not set, check if we can get a predicate from the context
5347 // instruction, if its type matches the requested ValTy.
5348 if (VecPred == CmpInst::BAD_ICMP_PREDICATE && I && I->getType() == ValTy) {
5349 CmpPredicate CurrentPred;
5350 if (match(I, m_Select(m_Cmp(CurrentPred, m_Value(), m_Value()), m_Value(),
5351 m_Value())))
5352 VecPred = CurrentPred;
5353 }
5354 // Check if we have a compare/select chain that can be lowered using
5355 // a (F)CMxx & BFI pair.
5356 if (CmpInst::isIntPredicate(VecPred) || VecPred == CmpInst::FCMP_OLE ||
5357 VecPred == CmpInst::FCMP_OLT || VecPred == CmpInst::FCMP_OGT ||
5358 VecPred == CmpInst::FCMP_OGE || VecPred == CmpInst::FCMP_OEQ ||
5359 VecPred == CmpInst::FCMP_UNE) {
5360 static const auto ValidMinMaxTys = {
5361 MVT::v8i8, MVT::v16i8, MVT::v4i16, MVT::v8i16, MVT::v2i32,
5362 MVT::v4i32, MVT::v2i64, MVT::v2f32, MVT::v4f32, MVT::v2f64};
5363 static const auto ValidFP16MinMaxTys = {MVT::v4f16, MVT::v8f16};
5364
5365 auto LT = getTypeLegalizationCost(ValTy);
5366 if (any_of(ValidMinMaxTys, equal_to(LT.second)) ||
5367 (ST->hasFullFP16() &&
5368 any_of(ValidFP16MinMaxTys, equal_to(LT.second))))
5369 return LT.first;
5370 }
5371
5372 static const TypeConversionCostTblEntry VectorSelectTbl[] = {
5373 {Instruction::Select, MVT::v2i1, MVT::v2f32, 2},
5374 {Instruction::Select, MVT::v2i1, MVT::v2f64, 2},
5375 {Instruction::Select, MVT::v4i1, MVT::v4f32, 2},
5376 {Instruction::Select, MVT::v4i1, MVT::v4f16, 2},
5377 {Instruction::Select, MVT::v8i1, MVT::v8f16, 2},
5378 {Instruction::Select, MVT::v16i1, MVT::v16i16, 16},
5379 {Instruction::Select, MVT::v8i1, MVT::v8i32, 8},
5380 {Instruction::Select, MVT::v16i1, MVT::v16i32, 16},
5381 {Instruction::Select, MVT::v4i1, MVT::v4i64, 4 * AmortizationCost},
5382 {Instruction::Select, MVT::v8i1, MVT::v8i64, 8 * AmortizationCost},
5383 {Instruction::Select, MVT::v16i1, MVT::v16i64, 16 * AmortizationCost}};
5384
5385 EVT SelCondTy = TLI->getValueType(DL, CondTy);
5386 EVT SelValTy = TLI->getValueType(DL, ValTy);
5387 if (SelCondTy.isSimple() && SelValTy.isSimple()) {
5388 if (const auto *Entry = ConvertCostTableLookup(VectorSelectTbl, Opcode,
5389 SelCondTy.getSimpleVT(),
5390 SelValTy.getSimpleVT()))
5391 return Entry->Cost;
5392 }
5393 }
5394
5395 if (Opcode == Instruction::FCmp) {
5396 if (auto PromotedCost = getFP16BF16PromoteCost(
5397 ValTy, CostKind, Op1Info, Op2Info, /*IncludeTrunc=*/false,
5398 // TODO: Consider costing SVE FCMPs.
5399 /*CanUseSVE=*/false, [&](Type *PromotedTy) {
5401 getCmpSelInstrCost(Opcode, PromotedTy, CondTy, VecPred,
5402 CostKind, Op1Info, Op2Info);
5403 if (isa<VectorType>(PromotedTy))
5405 Instruction::Trunc,
5409 return Cost;
5410 }))
5411 return *PromotedCost;
5412
5413 auto LT = getTypeLegalizationCost(ValTy);
5414 // Model unknown fp compares as a libcall.
5415 if (LT.second.getScalarType() != MVT::f64 &&
5416 LT.second.getScalarType() != MVT::f32 &&
5417 LT.second.getScalarType() != MVT::f16)
5418 return LT.first * getCallInstrCost(/*Function*/ nullptr, ValTy,
5419 {ValTy, ValTy}, CostKind);
5420
5421 // Some comparison operators require expanding to multiple compares + or.
5422 unsigned Factor = 1;
5423 if (!CondTy->isVectorTy() &&
5424 (VecPred == FCmpInst::FCMP_ONE || VecPred == FCmpInst::FCMP_UEQ))
5425 Factor = 2; // fcmp with 2 selects
5426 else if (isa<FixedVectorType>(ValTy) &&
5427 (VecPred == FCmpInst::FCMP_ONE || VecPred == FCmpInst::FCMP_UEQ ||
5428 VecPred == FCmpInst::FCMP_ORD || VecPred == FCmpInst::FCMP_UNO))
5429 Factor = 3; // fcmxx+fcmyy+or
5430 else if (isa<ScalableVectorType>(ValTy) &&
5431 (VecPred == FCmpInst::FCMP_ONE || VecPred == FCmpInst::FCMP_UEQ))
5432 Factor = 3; // fcmxx+fcmyy+or
5433
5434 if (isa<ScalableVectorType>(ValTy) &&
5436 hasKnownLowerThroughputFromSchedulingModel(AArch64::FCMEQ_PPzZZ_S,
5437 AArch64::FCMEQv4f32))
5438 Factor *= 2;
5439
5440 return Factor * (CostKind == TTI::TCK_Latency ? 2 : LT.first);
5441 }
5442
5443 // Treat the icmp in icmp(and, 0) or icmp(and, -1/1) when it can be folded to
5444 // icmp(and, 0) as free, as we can make use of ands, but only if the
5445 // comparison is not unsigned. FIXME: Enable for non-throughput cost kinds
5446 // providing it will not cause performance regressions.
5447 if (CostKind == TTI::TCK_RecipThroughput && ValTy->isIntegerTy() &&
5448 Opcode == Instruction::ICmp && I && !CmpInst::isUnsigned(VecPred) &&
5449 TLI->isTypeLegal(TLI->getValueType(DL, ValTy)) &&
5450 match(I->getOperand(0), m_And(m_Value(), m_Value()))) {
5451 if (match(I->getOperand(1), m_Zero()))
5452 return 0;
5453
5454 // x >= 1 / x < 1 -> x > 0 / x <= 0
5455 if (match(I->getOperand(1), m_One()) &&
5456 (VecPred == CmpInst::ICMP_SLT || VecPred == CmpInst::ICMP_SGE))
5457 return 0;
5458
5459 // x <= -1 / x > -1 -> x > 0 / x <= 0
5460 if (match(I->getOperand(1), m_AllOnes()) &&
5461 (VecPred == CmpInst::ICMP_SLE || VecPred == CmpInst::ICMP_SGT))
5462 return 0;
5463 }
5464
5465 // The base case handles scalable vectors fine for now, since it treats the
5466 // cost as 1 * legalization cost.
5467 return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, VecPred, CostKind,
5468 Op1Info, Op2Info, I);
5469}
5470
5472AArch64TTIImpl::enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const {
5474 if (ST->requiresStrictAlign()) {
5475 // TODO: Add cost modeling for strict align. Misaligned loads expand to
5476 // a bunch of instructions when strict align is enabled.
5477 return Options;
5478 }
5479 Options.AllowOverlappingLoads = true;
5480 Options.MaxNumLoads = TLI->getMaxExpandSizeMemcmp(OptSize);
5481 Options.NumLoadsPerBlock = IsZeroCmp ? Options.MaxNumLoads : 1;
5482 // TODO: Though vector loads usually perform well on AArch64, in some targets
5483 // they may wake up the FP unit, which raises the power consumption. Perhaps
5484 // they could be used with no holds barred (-O3).
5485 Options.LoadSizes = {8, 4, 2, 1};
5486 Options.AllowedTailExpansions = {3, 5, 6};
5487 return Options;
5488}
5489
5491 return ST->hasSVE();
5492}
5493
5497 switch (MICA.getID()) {
5498 case Intrinsic::masked_scatter:
5499 case Intrinsic::masked_gather:
5500 return getGatherScatterOpCost(MICA, CostKind);
5501 case Intrinsic::masked_load:
5502 case Intrinsic::masked_store:
5503 case Intrinsic::masked_expandload:
5504 case Intrinsic::masked_compressstore:
5505 return getMaskedMemoryOpCost(MICA, CostKind);
5506 }
5508}
5509
5513 Type *Src = MICA.getDataType();
5514
5515 if (useNeonVector(Src))
5517 auto LT = getTypeLegalizationCost(Src);
5518 if (!LT.first.isValid())
5520
5521 // Return an invalid cost for element types that we are unable to lower.
5522 auto *VT = cast<VectorType>(Src);
5523 if (VT->getElementType()->isIntegerTy(1))
5525
5526 // The code-generator is currently not able to handle scalable vectors
5527 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
5528 // it. This change will be removed when code-generation for these types is
5529 // sufficiently reliable.
5530 if (VT->getElementCount() == ElementCount::getScalable(1))
5532
5533 InstructionCost MemOpCost = LT.first;
5534 if (MICA.getID() == Intrinsic::masked_expandload) {
5535 if (!isLegalMaskedExpandLoad(Src, MICA.getAlignment()))
5537
5538 // Operation will be split into expand of masked.load
5539 MemOpCost *= 2;
5540 }
5541
5542 if (MICA.getID() == Intrinsic::masked_compressstore) {
5543 if (!isLegalMaskedCompressStore(Src, MICA.getAlignment()))
5545
5546 // A compress store lowers to something like:
5547 // ptrue p1.s
5548 // compact z0.s, p0, z0.s
5549 // cntp x8, p1, p0.s
5550 // whilelo p0.s, xzr, x8
5551 // st1w { z0.s }, p0, [x0]
5552 MemOpCost *= 2;
5553 }
5554
5555 // If we need to split the memory operation, we will also need to split the
5556 // mask. This will likely lead to overestimating the cost in some cases if
5557 // multiple memory operations use the same mask, but we often don't have
5558 // enough context to figure that out here.
5559 //
5560 // If the elements being loaded are bytes then the mask will already be split,
5561 // since the number of bits in a P register matches the number of bytes in a
5562 // Z register.
5563 if (LT.first > 1 && LT.second.getScalarSizeInBits() > 8)
5564 return MemOpCost * 2;
5565
5566 return MemOpCost;
5567}
5568
5569// This function returns gather/scatter overhead either from
5570// user-provided value or specialized values per-target from \p ST.
5571static unsigned getSVEGatherScatterOverhead(unsigned Opcode,
5572 const AArch64Subtarget *ST) {
5573 assert((Opcode == Instruction::Load || Opcode == Instruction::Store) &&
5574 "Should be called on only load or stores.");
5575 switch (Opcode) {
5576 case Instruction::Load:
5577 if (SVEGatherOverhead.getNumOccurrences() > 0)
5578 return SVEGatherOverhead;
5579 return ST->getGatherOverhead();
5580 break;
5581 case Instruction::Store:
5582 if (SVEScatterOverhead.getNumOccurrences() > 0)
5583 return SVEScatterOverhead;
5584 return ST->getScatterOverhead();
5585 break;
5586 default:
5587 llvm_unreachable("Shouldn't have reached here");
5588 }
5589}
5590
5594
5595 unsigned Opcode = (MICA.getID() == Intrinsic::masked_gather ||
5596 MICA.getID() == Intrinsic::vp_gather)
5597 ? Instruction::Load
5598 : Instruction::Store;
5599
5600 Type *DataTy = MICA.getDataType();
5601 Align Alignment = MICA.getAlignment();
5602 const Instruction *I = MICA.getInst();
5603
5604 if (useNeonVector(DataTy) || !isLegalMaskedGatherScatter(DataTy))
5606 auto *VT = cast<VectorType>(DataTy);
5607 auto LT = getTypeLegalizationCost(DataTy);
5608 if (!LT.first.isValid())
5610
5611 // Return an invalid cost for element types that we are unable to lower.
5612 if (!LT.second.isVector() ||
5613 !isElementTypeLegalForScalableVector(VT->getElementType()) ||
5614 VT->getElementType()->isIntegerTy(1))
5616
5617 // The code-generator is currently not able to handle scalable vectors
5618 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
5619 // it. This change will be removed when code-generation for these types is
5620 // sufficiently reliable.
5621 if (VT->getElementCount() == ElementCount::getScalable(1))
5623
5624 ElementCount LegalVF = LT.second.getVectorElementCount();
5625 InstructionCost MemOpCost =
5626 getMemoryOpCost(Opcode, VT->getElementType(), Alignment, 0, CostKind,
5627 {TTI::OK_AnyValue, TTI::OP_None}, I);
5628 // Add on an overhead cost for using gathers/scatters.
5629 MemOpCost *= getSVEGatherScatterOverhead(Opcode, ST);
5630 return LT.first * MemOpCost * getMaxNumElements(LegalVF);
5631}
5632
5634 return isa<FixedVectorType>(Ty) && !ST->useSVEForFixedLengthVectors();
5635}
5636
5638 Align Alignment,
5639 unsigned AddressSpace,
5641 TTI::OperandValueInfo OpInfo,
5642 const Instruction *I) const {
5643 EVT VT = TLI->getValueType(DL, Ty, true);
5644 // Type legalization can't handle structs
5645 if (VT == MVT::Other)
5646 return BaseT::getMemoryOpCost(Opcode, Ty, Alignment, AddressSpace,
5647 CostKind);
5648
5649 auto LT = getTypeLegalizationCost(Ty);
5650 if (!LT.first.isValid())
5652
5653 // The code-generator is currently not able to handle scalable vectors
5654 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
5655 // it. This change will be removed when code-generation for these types is
5656 // sufficiently reliable.
5657 // We also only support full register predicate loads and stores.
5658 if (auto *VTy = dyn_cast<ScalableVectorType>(Ty))
5659 if (VTy->getElementCount() == ElementCount::getScalable(1) ||
5660 (VTy->getElementType()->isIntegerTy(1) &&
5661 !VTy->getElementCount().isKnownMultipleOf(
5664
5665 // TODO: consider latency as well for TCK_SizeAndLatency.
5667 return LT.first;
5668
5669 if (CostKind == TTI::TCK_Latency) {
5670 // Latency doesn't make much sense for stores, so just return 1
5671 if (Opcode == Instruction::Store)
5672 return 1;
5673 // If the subtarget has overridden the load latency then use that instead of
5674 // querying the SchedModel.
5675 if (ST->getFixedLoadLatency())
5676 return (LT.first - 1) + ST->getFixedLoadLatency();
5677 // We expect the load to become LT.first loads of type LT.second. The
5678 // latency will be the latency of the last load plus the time it gets to get
5679 // there, which will be the amount of other loads before that (i.e. total
5680 // loads - 1) multiplied by how long it takes to get through them (the
5681 // reciprocal of the throughput). We get the latency and reciprocal
5682 // throughput from the SchedModel, and assume that the loads become the
5683 // variant with unsigned integer offset.
5684 unsigned Inst = 0;
5685 if (LT.second.isScalableVector() ||
5686 ST->useSVEForFixedLengthVectors(LT.second)) {
5687 Inst = AArch64::LDR_ZXI;
5688 } else if (LT.second.isVector() || LT.second.isFloatingPoint()) {
5689 switch (LT.second.getSizeInBits()) {
5690 case 8:
5691 Inst = AArch64::LDRBui;
5692 break;
5693 case 16:
5694 Inst = AArch64::LDRHui;
5695 break;
5696 case 32:
5697 Inst = AArch64::LDRSui;
5698 break;
5699 case 64:
5700 Inst = AArch64::LDRDui;
5701 break;
5702 case 128:
5703 Inst = AArch64::LDRQui;
5704 break;
5705 default:
5706 llvm_unreachable("Unexpected float or vector type");
5707 }
5708 } else {
5709 switch (LT.second.getSizeInBits()) {
5710 case 8:
5711 Inst = AArch64::LDRBBui;
5712 break;
5713 case 16:
5714 Inst = AArch64::LDRHHui;
5715 break;
5716 case 32:
5717 Inst = AArch64::LDRWui;
5718 break;
5719 case 64:
5720 Inst = AArch64::LDRXui;
5721 break;
5722 default:
5723 llvm_unreachable("Unexpected integer type");
5724 }
5725 }
5726 const MCSchedModel &Sched = ST->getSchedModel();
5727 const TargetInstrInfo *TII = ST->getInstrInfo();
5728 unsigned SchedClass = TII->get(Inst).getSchedClass();
5729 const MCSchedClassDesc *SCD = Sched.hasInstrSchedModel()
5730 ? Sched.getSchedClassDesc(SchedClass)
5731 : nullptr;
5732 // If the cpu has no scheduling model, or it doesn't describe the load, then
5733 // fall back to the default load latency. Variant scheduling classes can't
5734 // be resolved without a MachineInstr, so treat them the same way.
5735 if (!SCD || !SCD->isValid() || SCD->isVariant())
5736 return (LT.first - 1) + ST->getLoadLatency();
5737 // We need to convert the number of loads before the last to a float here,
5738 // as the reciprocal throughput may be fractional.
5739 float NumLoads = (LT.first - 1).getValue();
5740 return NumLoads * Sched.getReciprocalThroughput(*ST, *SCD) +
5741 Sched.computeInstrLatency(*ST, *SCD);
5742 }
5743
5744 if (ST->isMisaligned128StoreSlow() && Opcode == Instruction::Store &&
5745 LT.second.is128BitVector() && Alignment < Align(16)) {
5746 // Unaligned stores are extremely inefficient. We don't split all
5747 // unaligned 128-bit stores because the negative impact that has shown in
5748 // practice on inlined block copy code.
5749 // We make such stores expensive so that we will only vectorize if there
5750 // are 6 other instructions getting vectorized.
5751 const int AmortizationCost = 6;
5752
5753 return LT.first * 2 * AmortizationCost;
5754 }
5755
5756 // Opaque ptr or ptr vector types are i64s and can be lowered to STP/LDPs.
5757 if (Ty->isPtrOrPtrVectorTy())
5758 return LT.first;
5759
5760 if (useNeonVector(Ty)) {
5761 // Check truncating stores and extending loads.
5762 if (Ty->getScalarSizeInBits() != LT.second.getScalarSizeInBits()) {
5763 // v4i8 types are lowered to scalar a load/store and sshll/xtn.
5764 if (VT == MVT::v4i8)
5765 return 2;
5766 // Otherwise we need to scalarize.
5767 return cast<FixedVectorType>(Ty)->getNumElements() * 2;
5768 }
5769 EVT EltVT = VT.getVectorElementType();
5770 unsigned EltSize = EltVT.getScalarSizeInBits();
5771 if (!isPowerOf2_32(EltSize) || EltSize < 8 || EltSize > 64 ||
5772 Alignment != Align(1))
5773 return LT.first;
5774 // FIXME: v3i8 lowering currently is very inefficient, due to automatic
5775 // widening to v4i8, which produces suboptimal results.
5776 if (VT.getVectorNumElements() == 3 && EltVT == MVT::i8)
5777 return LT.first;
5778
5779 // Check non-power-of-2 loads/stores for legal vector element types with
5780 // NEON. Non-power-of-2 memory ops will get broken down to a set of
5781 // operations on smaller power-of-2 ops, including ld1/st1.
5782 InstructionCost Cost = VT.getVectorNumElements() / (128 / EltSize);
5783 unsigned Remainder = VT.getVectorNumElements() % (128 / EltSize);
5784 if (Remainder != 0) {
5786 TypeWorklist.push_back({Remainder, 0});
5787 while (!TypeWorklist.empty()) {
5788 auto [CurrNumElements, Offset] = TypeWorklist.pop_back_val();
5789 if (isPowerOf2_32(CurrNumElements)) {
5790 // 1 per load/store + possible lane insert.
5791 Cost += 1 + (Offset == 0 ? 0 : 1);
5792 continue;
5793 }
5794
5795 unsigned PrevPow2 = NextPowerOf2(CurrNumElements) / 2;
5796 TypeWorklist.push_back({PrevPow2, Offset});
5797 TypeWorklist.push_back({CurrNumElements - PrevPow2, Offset + PrevPow2});
5798 }
5799 }
5800 return Cost;
5801 }
5802
5803 return LT.first;
5804}
5805
5807 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
5808 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
5809 bool UseMaskForCond, bool UseMaskForGaps) const {
5810 assert(Factor >= 2 && "Invalid interleave factor");
5811 auto *VecVTy = cast<VectorType>(VecTy);
5812
5813 if (VecTy->isScalableTy() && !ST->hasSVE())
5815
5816 // Scalable VFs emit vector.[de]interleave intrinsics, for which the target
5817 // supports factors up to the maximum supported interleave factor.
5818 if (VecTy->isScalableTy()) {
5819 if (Factor > TLI->getMaxSupportedInterleaveFactor())
5821
5822 if (Factor == 3 &&
5823 DL.getTypeSizeInBits(VecTy).getKnownMinValue() != (3 * 128))
5825 }
5826
5827 auto LT = getTypeLegalizationCost(VecTy);
5828 unsigned MaxNativeInterleaveFactor = TLI->getMaxSupportedInterleaveFactor();
5829 // Vectorization for masked interleaved accesses is only enabled for scalable
5830 // VF. For fixed-length SVE, avoid non-native interleave factor because
5831 // the generic fallback costs wide fixed-vector shuffles too optimistically.
5832 if (!VecTy->isScalableTy() &&
5833 (UseMaskForCond || UseMaskForGaps ||
5834 (Factor > MaxNativeInterleaveFactor &&
5835 TLI->useSVEForFixedLengthVectorVT(LT.second))))
5837
5838 if (!UseMaskForGaps && Factor <= MaxNativeInterleaveFactor) {
5839 ElementCount EC = VecVTy->getElementCount();
5840 auto *SubVecTy = VectorType::get(VecVTy->getElementType(),
5841 EC.divideCoefficientBy(Factor));
5842
5843 // ldN/stN only support legal vector types of size 64 or 128 in bits.
5844 // Accesses having vector types that are a multiple of 128 bits can be
5845 // matched to more than one ldN/stN instruction.
5846 bool UseScalable;
5847 if (EC.isKnownMultipleOf(Factor) &&
5848 TLI->isLegalInterleavedAccessType(SubVecTy, DL, UseScalable))
5849 return Factor * TLI->getNumInterleavedAccesses(SubVecTy, DL, UseScalable);
5850
5851 // Cost the alternative approach for scalable vectors where the interleave
5852 // factor is larger than the VF: use a contiguous load/store of the full
5853 // wide vector followed by deinterleave/interleave shuffles.
5854 if (VecTy->isScalableTy() && EC.isKnownMultipleOf(Factor)) {
5855 if (SubVecTy->getElementCount() == ElementCount::getScalable(1))
5857
5858 // Cost of the contiguous memory operation on the wide vector.
5859 InstructionCost MemCost;
5860 if (UseMaskForCond) {
5861 unsigned IID = Opcode == Instruction::Load ? Intrinsic::masked_load
5862 : Intrinsic::masked_store;
5863 MemCost = getMemIntrinsicInstrCost(
5864 MemIntrinsicCostAttributes(IID, VecTy, Alignment, AddressSpace),
5865 CostKind);
5866 } else {
5867 MemCost =
5868 getMemoryOpCost(Opcode, VecTy, Alignment, AddressSpace, CostKind);
5869 }
5870
5871 // llvm.vector.deinterleaveN is lowered as a binary tree of deinterleave2
5872 // operations. The tree has Log2(Factor) levels, with Factor UZP/ZIP
5873 // operations at each level, giving a total shuffle cost of
5874 // Factor * Log2(Factor).
5875 auto SubVecCost = getTypeLegalizationCost(SubVecTy);
5876 auto ResultCost = getTypeLegalizationCost(VecTy);
5877 llvm::InstructionCost LegalizationCost = SubVecCost.first;
5878
5879 // FIXME: A temporary increase to the cost in cases where the input
5880 // element type is 4x the output type. Otherwise it produces an SVE tail
5881 // loop which is significantly larger than the NEON equivalent.
5882 if (Opcode == Instruction::Store && Factor == 4 &&
5883 SubVecCost.second.getScalarSizeInBits() ==
5884 (4 * ResultCost.second.getScalarSizeInBits()))
5885 LegalizationCost *= 4;
5886
5887 return MemCost + (Factor * LegalizationCost) + (Factor * Log2_64(Factor));
5888 }
5889 }
5890
5891 return BaseT::getInterleavedMemoryOpCost(Opcode, VecTy, Factor, Indices,
5892 Alignment, AddressSpace, CostKind,
5893 UseMaskForCond, UseMaskForGaps);
5894}
5895
5900 for (auto *I : Tys) {
5901 if (!I->isVectorTy())
5902 continue;
5903 if (I->getScalarSizeInBits() * cast<FixedVectorType>(I)->getNumElements() ==
5904 128)
5905 Cost += getMemoryOpCost(Instruction::Store, I, Align(128), 0, CostKind) +
5906 getMemoryOpCost(Instruction::Load, I, Align(128), 0, CostKind);
5907 }
5908 return Cost;
5909}
5910
5912 Align Alignment) const {
5913 // Neon types should be scalarised when we are not choosing to use SVE.
5914 if (useNeonVector(DataTy))
5915 return false;
5916
5917 // Return true only if we are able to lower using the SVE2p2/SME2p2
5918 // expand instruction.
5919 return (ST->isSVEAvailable() && ST->hasSVE2p2()) ||
5920 (ST->isSVEorStreamingSVEAvailable() && ST->hasSME2p2());
5921}
5922
5923unsigned
5925 bool HasUnorderedReductions) const {
5926 if (VF.isScalar() || (HasUnorderedReductions && VF.getKnownMinValue() <= 4))
5927 return 4;
5928 return ST->getMaxInterleaveFactor();
5929}
5930
5931// For Falkor, we want to avoid having too many strided loads in a loop since
5932// that can exhaust the HW prefetcher resources. We adjust the unroller
5933// MaxCount preference below to attempt to ensure unrolling doesn't create too
5934// many strided loads.
5935static void
5938 enum { MaxStridedLoads = 7 };
5939 auto countStridedLoads = [](Loop *L, ScalarEvolution &SE) {
5940 int StridedLoads = 0;
5941 // FIXME? We could make this more precise by looking at the CFG and
5942 // e.g. not counting loads in each side of an if-then-else diamond.
5943 for (const auto BB : L->blocks()) {
5944 for (auto &I : *BB) {
5945 LoadInst *LMemI = dyn_cast<LoadInst>(&I);
5946 if (!LMemI)
5947 continue;
5948
5949 Value *PtrValue = LMemI->getPointerOperand();
5950 if (L->isLoopInvariant(PtrValue))
5951 continue;
5952
5953 const SCEV *LSCEV = SE.getSCEV(PtrValue);
5954 const SCEVAddRecExpr *LSCEVAddRec = dyn_cast<SCEVAddRecExpr>(LSCEV);
5955 if (!LSCEVAddRec || !LSCEVAddRec->isAffine())
5956 continue;
5957
5958 // FIXME? We could take pairing of unrolled load copies into account
5959 // by looking at the AddRec, but we would probably have to limit this
5960 // to loops with no stores or other memory optimization barriers.
5961 ++StridedLoads;
5962 // We've seen enough strided loads that seeing more won't make a
5963 // difference.
5964 if (StridedLoads > MaxStridedLoads / 2)
5965 return StridedLoads;
5966 }
5967 }
5968 return StridedLoads;
5969 };
5970
5971 int StridedLoads = countStridedLoads(L, SE);
5972 LLVM_DEBUG(dbgs() << "falkor-hwpf: detected " << StridedLoads
5973 << " strided loads\n");
5974 // Pick the largest power of 2 unroll count that won't result in too many
5975 // strided loads.
5976 if (StridedLoads) {
5977 UP.MaxCount = 1 << Log2_32(MaxStridedLoads / StridedLoads);
5978 LLVM_DEBUG(dbgs() << "falkor-hwpf: setting unroll MaxCount to "
5979 << UP.MaxCount << '\n');
5980 }
5981}
5982
5983// This function returns true if the loop:
5984// 1. Has a valid cost, and
5985// 2. Has a cost within the supplied budget.
5986// Otherwise it returns false.
5988 InstructionCost Budget,
5989 unsigned *FinalSize) {
5990 // Estimate the size of the loop.
5991 InstructionCost LoopCost = 0;
5992
5993 for (auto *BB : L->getBlocks()) {
5994 for (auto &I : *BB) {
5995 SmallVector<const Value *, 4> Operands(I.operand_values());
5996 InstructionCost Cost =
5997 TTI.getInstructionCost(&I, Operands, TTI::TCK_CodeSize);
5998 // This can happen with intrinsics that don't currently have a cost model
5999 // or for some operations that require SVE.
6000 if (!Cost.isValid())
6001 return false;
6002
6003 LoopCost += Cost;
6004 if (LoopCost > Budget)
6005 return false;
6006 }
6007 }
6008
6009 if (FinalSize)
6010 *FinalSize = LoopCost.getValue();
6011 return true;
6012}
6013
6015 const AArch64TTIImpl &TTI) {
6016 // Only consider loops with unknown trip counts for which we can determine
6017 // a symbolic expression. Multi-exit loops with small known trip counts will
6018 // likely be unrolled anyway.
6019 const SCEV *BTC = SE.getSymbolicMaxBackedgeTakenCount(L);
6021 return false;
6022
6023 // It might not be worth unrolling loops with low max trip counts. Restrict
6024 // this to max trip counts > 32 for now.
6025 unsigned MaxTC = SE.getSmallConstantMaxTripCount(L);
6026 if (MaxTC > 0 && MaxTC <= 32)
6027 return false;
6028
6029 // Make sure the loop size is <= 5.
6030 if (!isLoopSizeWithinBudget(L, TTI, 5, nullptr))
6031 return false;
6032
6033 // Small search loops with multiple exits can be highly beneficial to unroll.
6034 // We only care about loops with exactly two exiting blocks, although each
6035 // block could jump to the same exit block.
6036 ArrayRef<BasicBlock *> Blocks = L->getBlocks();
6037 if (Blocks.size() != 2)
6038 return false;
6039
6040 if (any_of(Blocks, [](BasicBlock *BB) {
6042 }))
6043 return false;
6044
6045 return true;
6046}
6047
6048/// For Apple CPUs, we want to runtime-unroll loops to make better use if the
6049/// OOO engine's wide instruction window and various predictors.
6050static void
6053 const AArch64TTIImpl &TTI) {
6054 // Limit loops with structure that is highly likely to benefit from runtime
6055 // unrolling; that is we exclude outer loops and loops with many blocks (i.e.
6056 // likely with complex control flow). Note that the heuristics here may be
6057 // overly conservative and we err on the side of avoiding runtime unrolling
6058 // rather than unroll excessively. They are all subject to further refinement.
6059 if (!L->isInnermost() || L->getNumBlocks() > 8)
6060 return;
6061
6062 // Loops with multiple exits are handled by common code.
6063 if (!L->getExitBlock())
6064 return;
6065
6066 // Check if the loop contains any reductions that could be parallelized when
6067 // unrolling. If so, enable partial unrolling, if the trip count is know to be
6068 // a multiple of 2.
6069 bool HasParellelizableReductions =
6070 L->getNumBlocks() == 1 &&
6071 any_of(L->getHeader()->phis(),
6072 [&SE, L](PHINode &Phi) {
6073 return canParallelizeReductionWhenUnrolling(Phi, L, &SE);
6074 }) &&
6075 isLoopSizeWithinBudget(L, TTI, 12, nullptr);
6076 if (HasParellelizableReductions &&
6077 SE.getSmallConstantTripMultiple(L, L->getExitingBlock()) % 2 == 0) {
6078 UP.Partial = true;
6079 UP.MaxCount = 4;
6080 UP.AddAdditionalAccumulators = true;
6081 }
6082
6083 const SCEV *BTC = SE.getSymbolicMaxBackedgeTakenCount(L);
6085 (SE.getSmallConstantMaxTripCount(L) > 0 &&
6086 SE.getSmallConstantMaxTripCount(L) <= 32))
6087 return;
6088
6089 if (findStringMetadataForLoop(L, "llvm.loop.isvectorized"))
6090 return;
6091
6093 return;
6094
6095 // Limit to loops with trip counts that are cheap to expand.
6096 UP.SCEVExpansionBudget = 1;
6097
6098 if (HasParellelizableReductions) {
6099 UP.Runtime = true;
6101 UP.AddAdditionalAccumulators = true;
6102 }
6103
6104 // Try to unroll small, single-block loops with low budget, if they have
6105 // load/store dependencies, to expose more parallel memory access streams,
6106 // or if they do little work inside a block (i.e. load -> X -> store pattern).
6107 BasicBlock *Header = L->getHeader();
6108 BasicBlock *Latch = L->getLoopLatch();
6109 if (Header == Latch) {
6110 // Estimate the size of the loop.
6111 unsigned Size;
6112 unsigned Width = 10;
6113 if (!isLoopSizeWithinBudget(L, TTI, Width, &Size))
6114 return;
6115
6116 // Try to find an unroll count that maximizes the use of the instruction
6117 // window, i.e. trying to fetch as many instructions per cycle as possible.
6118 unsigned MaxInstsPerLine = 16;
6119 unsigned UC = 1;
6120 unsigned BestUC = 1;
6121 unsigned SizeWithBestUC = BestUC * Size;
6122 while (UC <= 8) {
6123 unsigned SizeWithUC = UC * Size;
6124 if (SizeWithUC > 48)
6125 break;
6126 if ((SizeWithUC % MaxInstsPerLine) == 0 ||
6127 (SizeWithBestUC % MaxInstsPerLine) < (SizeWithUC % MaxInstsPerLine)) {
6128 BestUC = UC;
6129 SizeWithBestUC = BestUC * Size;
6130 }
6131 UC++;
6132 }
6133
6134 if (BestUC == 1)
6135 return;
6136
6137 SmallPtrSet<Value *, 8> LoadedValuesPlus;
6139 for (auto *BB : L->blocks()) {
6140 for (auto &I : *BB) {
6142 if (!Ptr)
6143 continue;
6144 const SCEV *PtrSCEV = SE.getSCEV(Ptr);
6145 if (SE.isLoopInvariant(PtrSCEV, L))
6146 continue;
6147 if (isa<LoadInst>(&I)) {
6148 LoadedValuesPlus.insert(&I);
6149 // Include in-loop 1st users of loaded values.
6150 for (auto *U : I.users())
6151 if (L->contains(cast<Instruction>(U)))
6152 LoadedValuesPlus.insert(U);
6153 } else
6154 Stores.push_back(cast<StoreInst>(&I));
6155 }
6156 }
6157
6158 if (none_of(Stores, [&LoadedValuesPlus](StoreInst *SI) {
6159 return LoadedValuesPlus.contains(SI->getOperand(0));
6160 }))
6161 return;
6162
6163 UP.Runtime = true;
6164 UP.DefaultUnrollRuntimeCount = BestUC;
6165 return;
6166 }
6167
6168 // Try to runtime-unroll loops with early-continues depending on loop-varying
6169 // loads; this helps with branch-prediction for the early-continues.
6170 auto *Term = dyn_cast<CondBrInst>(Header->getTerminator());
6172 if (!Term || Preds.size() == 1 || !llvm::is_contained(Preds, Header) ||
6173 none_of(Preds, [L](BasicBlock *Pred) { return L->contains(Pred); }))
6174 return;
6175
6176 std::function<bool(Instruction *, unsigned)> DependsOnLoopLoad =
6177 [&](Instruction *I, unsigned Depth) -> bool {
6178 if (isa<PHINode>(I) || L->isLoopInvariant(I) || Depth > 8)
6179 return false;
6180
6181 if (isa<LoadInst>(I))
6182 return true;
6183
6184 return any_of(I->operands(), [&](Value *V) {
6185 auto *I = dyn_cast<Instruction>(V);
6186 return I && DependsOnLoopLoad(I, Depth + 1);
6187 });
6188 };
6189 CmpPredicate Pred;
6190 Instruction *I;
6191 if (match(Term, m_Br(m_ICmp(Pred, m_Instruction(I), m_Value()), m_Value(),
6192 m_Value())) &&
6193 DependsOnLoopLoad(I, 0)) {
6194 UP.Runtime = true;
6195 }
6196}
6197
6200 OptimizationRemarkEmitter *ORE) const {
6201 // Enable partial unrolling and runtime unrolling.
6202 BaseT::getUnrollingPreferences(L, SE, UP, ORE);
6203
6204 UP.UpperBound = true;
6205
6206 // A loop can have a small maximum trip count while SCEV still cannot
6207 // form an exact backedge count - typically a data-dependent exit, e.g.
6208 // shifting a value until it reaches zero. Unlike for counted loops, the
6209 // unrolled body keeps an exit test per iteration, and whether that pays
6210 // off depends on how many iterations the loop usually runs, which is
6211 // unknown at compile time; the code growth and extra branches are certain.
6212 // Be conservative and hold such loops to a lower upper bound; 5 still lets
6213 // smaller early-exit loops unroll. Also disable runtime unrolling, which
6214 // would clamp the unroll count to the known maximum trip count and produce
6215 // the same complete unroll.
6216 if (L->getExitingBlock() && !SE.isBackedgeTakenCountMaxOrZero(L) &&
6218 UP.MaxUpperBound = 5;
6219 UP.Runtime = false;
6220 }
6221
6222 // For inner loop, it is more likely to be a hot one, and the runtime check
6223 // can be promoted out from LICM pass, so the overhead is less, let's try
6224 // a larger threshold to unroll more loops.
6225 if (L->getLoopDepth() > 1)
6226 UP.PartialThreshold *= 2;
6227
6228 // Disable partial & runtime unrolling on -Os.
6230
6231 // Scan the loop: don't unroll loops with calls as this could prevent
6232 // inlining. Don't unroll auto-vectorized loops either, though do allow
6233 // unrolling of the scalar remainder.
6234 bool IsVectorized = getBooleanLoopAttribute(L, "llvm.loop.isvectorized");
6236 for (auto *BB : L->getBlocks()) {
6237 for (auto &I : *BB) {
6238 // Both auto-vectorized loops and the scalar remainder have the
6239 // isvectorized attribute, so differentiate between them by the presence
6240 // of vector instructions.
6241 if (IsVectorized && I.getType()->isVectorTy())
6242 return;
6243 if (isa<CallBase>(I)) {
6246 if (!isLoweredToCall(F))
6247 continue;
6248 return;
6249 }
6250
6251 SmallVector<const Value *, 4> Operands(I.operand_values());
6254 }
6255 }
6256
6257 // Apply subtarget-specific unrolling preferences.
6258 if (ST->isAppleMLike())
6259 getAppleRuntimeUnrollPreferences(L, SE, UP, *this);
6260 else if (ST->getProcFamily() == AArch64Subtarget::Falkor &&
6263
6264 // If this is a small, multi-exit loop similar to something like std::find,
6265 // then there is typically a performance improvement achieved by unrolling.
6266 if (!L->getExitBlock() && shouldUnrollMultiExitLoop(L, SE, *this)) {
6267 UP.RuntimeUnrollMultiExit = true;
6268 UP.Runtime = true;
6269 // Limit unroll count.
6271 // Allow slightly more costly trip-count expansion to catch search loops
6272 // with pointer inductions.
6273 UP.SCEVExpansionBudget = 5;
6274 return;
6275 }
6276
6277 // Enable runtime unrolling for in-order models
6278 // If mcpu is omitted, getProcFamily() returns AArch64Subtarget::Others, so by
6279 // checking for that case, we can ensure that the default behaviour is
6280 // unchanged
6281 if (ST->getProcFamily() != AArch64Subtarget::Generic &&
6282 !ST->getSchedModel().isOutOfOrder()) {
6283 UP.Runtime = true;
6284 UP.Partial = true;
6285 UP.UnrollRemainder = true;
6287
6288 UP.UnrollAndJam = true;
6290 }
6291
6292 // Force unrolling small loops can be very useful because of the branch
6293 // taken cost of the backedge.
6295 UP.Force = true;
6296}
6297
6302
6304 Type *ExpectedType,
6305 bool CanCreate) const {
6306 switch (Inst->getIntrinsicID()) {
6307 default:
6308 return nullptr;
6309 case Intrinsic::aarch64_neon_st1x2:
6310 case Intrinsic::aarch64_neon_st1x3:
6311 case Intrinsic::aarch64_neon_st1x4:
6312 case Intrinsic::aarch64_neon_st2:
6313 case Intrinsic::aarch64_neon_st3:
6314 case Intrinsic::aarch64_neon_st4: {
6315 // Create a struct type
6316 StructType *ST = dyn_cast<StructType>(ExpectedType);
6317 if (!CanCreate || !ST)
6318 return nullptr;
6319 unsigned NumElts = Inst->arg_size() - 1;
6320 if (ST->getNumElements() != NumElts)
6321 return nullptr;
6322 for (unsigned i = 0, e = NumElts; i != e; ++i) {
6323 if (Inst->getArgOperand(i)->getType() != ST->getElementType(i))
6324 return nullptr;
6325 }
6326 Value *Res = PoisonValue::get(ExpectedType);
6327 IRBuilder<> Builder(Inst);
6328 for (unsigned i = 0, e = NumElts; i != e; ++i) {
6329 Value *L = Inst->getArgOperand(i);
6330 Res = Builder.CreateInsertValue(Res, L, i);
6331 }
6332 return Res;
6333 }
6334 case Intrinsic::aarch64_neon_ld1x2:
6335 case Intrinsic::aarch64_neon_ld1x3:
6336 case Intrinsic::aarch64_neon_ld1x4:
6337 case Intrinsic::aarch64_neon_ld2:
6338 case Intrinsic::aarch64_neon_ld3:
6339 case Intrinsic::aarch64_neon_ld4:
6340 if (Inst->getType() == ExpectedType)
6341 return Inst;
6342 return nullptr;
6343 }
6344}
6345
6347 MemIntrinsicInfo &Info) const {
6348 switch (Inst->getIntrinsicID()) {
6349 default:
6350 break;
6351 case Intrinsic::aarch64_neon_ld1x2:
6352 case Intrinsic::aarch64_neon_ld1x3:
6353 case Intrinsic::aarch64_neon_ld1x4:
6354 case Intrinsic::aarch64_neon_ld2:
6355 case Intrinsic::aarch64_neon_ld3:
6356 case Intrinsic::aarch64_neon_ld4:
6357 Info.ReadMem = true;
6358 Info.WriteMem = false;
6359 Info.PtrVal = Inst->getArgOperand(0);
6360 break;
6361 case Intrinsic::aarch64_neon_st1x2:
6362 case Intrinsic::aarch64_neon_st1x3:
6363 case Intrinsic::aarch64_neon_st1x4:
6364 case Intrinsic::aarch64_neon_st2:
6365 case Intrinsic::aarch64_neon_st3:
6366 case Intrinsic::aarch64_neon_st4:
6367 Info.ReadMem = false;
6368 Info.WriteMem = true;
6369 Info.PtrVal = Inst->getArgOperand(Inst->arg_size() - 1);
6370 break;
6371 }
6372
6373 // Use the ID of neon load as the "matching id".
6374 switch (Inst->getIntrinsicID()) {
6375 default:
6376 return false;
6377 case Intrinsic::aarch64_neon_ld1x2:
6378 case Intrinsic::aarch64_neon_st1x2:
6379 Info.MatchingId = Intrinsic::aarch64_neon_ld1x2;
6380 break;
6381 case Intrinsic::aarch64_neon_ld1x3:
6382 case Intrinsic::aarch64_neon_st1x3:
6383 Info.MatchingId = Intrinsic::aarch64_neon_ld1x3;
6384 break;
6385 case Intrinsic::aarch64_neon_ld1x4:
6386 case Intrinsic::aarch64_neon_st1x4:
6387 Info.MatchingId = Intrinsic::aarch64_neon_ld1x4;
6388 break;
6389 case Intrinsic::aarch64_neon_ld2:
6390 case Intrinsic::aarch64_neon_st2:
6391 Info.MatchingId = Intrinsic::aarch64_neon_ld2;
6392 break;
6393 case Intrinsic::aarch64_neon_ld3:
6394 case Intrinsic::aarch64_neon_st3:
6395 Info.MatchingId = Intrinsic::aarch64_neon_ld3;
6396 break;
6397 case Intrinsic::aarch64_neon_ld4:
6398 case Intrinsic::aarch64_neon_st4:
6399 Info.MatchingId = Intrinsic::aarch64_neon_ld4;
6400 break;
6401 }
6402 return true;
6403}
6404
6405/// See if \p I should be considered for address type promotion. We check if \p
6406/// I is a sext with right type and used in memory accesses. If it used in a
6407/// "complex" getelementptr, we allow it to be promoted without finding other
6408/// sext instructions that sign extended the same initial value. A getelementptr
6409/// is considered as "complex" if it has more than 2 operands.
6411 const Instruction &I, bool &AllowPromotionWithoutCommonHeader) const {
6412 bool Considerable = false;
6413 AllowPromotionWithoutCommonHeader = false;
6414 if (!isa<SExtInst>(&I))
6415 return false;
6416 Type *ConsideredSExtType =
6417 Type::getInt64Ty(I.getParent()->getParent()->getContext());
6418 if (I.getType() != ConsideredSExtType)
6419 return false;
6420 // See if the sext is the one with the right type and used in at least one
6421 // GetElementPtrInst.
6422 for (const User *U : I.users()) {
6423 if (const GetElementPtrInst *GEPInst = dyn_cast<GetElementPtrInst>(U)) {
6424 Considerable = true;
6425 // A getelementptr is considered as "complex" if it has more than 2
6426 // operands. We will promote a SExt used in such complex GEP as we
6427 // expect some computation to be merged if they are done on 64 bits.
6428 if (GEPInst->getNumOperands() > 2) {
6429 AllowPromotionWithoutCommonHeader = true;
6430 break;
6431 }
6432 }
6433 }
6434 return Considerable;
6435}
6436
6438 const RecurrenceDescriptor &RdxDesc, ElementCount VF) const {
6439 if (!VF.isScalable())
6440 return true;
6441
6442 Type *Ty = RdxDesc.getRecurrenceType();
6443 if (Ty->isBFloatTy() || !isElementTypeLegalForScalableVector(Ty))
6444 return false;
6445
6446 switch (RdxDesc.getRecurrenceKind()) {
6447 case RecurKind::Sub:
6448 case RecurKind::FSub:
6451 case RecurKind::Add:
6452 case RecurKind::FAdd:
6453 case RecurKind::And:
6454 case RecurKind::Or:
6455 case RecurKind::Xor:
6456 case RecurKind::SMin:
6457 case RecurKind::SMax:
6458 case RecurKind::UMin:
6459 case RecurKind::UMax:
6460 case RecurKind::FMin:
6461 case RecurKind::FMax:
6462 case RecurKind::FMulAdd:
6463 case RecurKind::AnyOf:
6465 return true;
6466 default:
6467 return false;
6468 }
6469}
6470
6473 FastMathFlags FMF,
6475 // The code-generator is currently not able to handle scalable vectors
6476 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
6477 // it. This change will be removed when code-generation for these types is
6478 // sufficiently reliable.
6479 if (auto *VTy = dyn_cast<ScalableVectorType>(Ty))
6480 if (VTy->getElementCount() == ElementCount::getScalable(1))
6482
6483 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);
6484
6485 if (LT.second.getScalarType() == MVT::f16 && !ST->hasFullFP16())
6486 return BaseT::getMinMaxReductionCost(IID, Ty, FMF, CostKind);
6487
6488 InstructionCost LegalizationCost = 0;
6489 if (LT.first > 1) {
6490 Type *LegalVTy = EVT(LT.second).getTypeForEVT(Ty->getContext());
6491 IntrinsicCostAttributes Attrs(IID, LegalVTy, {LegalVTy, LegalVTy}, FMF);
6492 LegalizationCost = getIntrinsicInstrCost(Attrs, CostKind) * (LT.first - 1);
6493 }
6494
6495 return LegalizationCost + /*Cost of horizontal reduction*/ 2;
6496}
6497
6499 unsigned Opcode, VectorType *ValTy, TTI::TargetCostKind CostKind) const {
6500 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(ValTy);
6501 InstructionCost LegalizationCost = 0;
6502 if (LT.first > 1) {
6503 Type *LegalVTy = EVT(LT.second).getTypeForEVT(ValTy->getContext());
6504 LegalizationCost = getArithmeticInstrCost(Opcode, LegalVTy, CostKind);
6505 LegalizationCost *= LT.first - 1;
6506 }
6507
6508 int ISD = TLI->InstructionOpcodeToISD(Opcode);
6509 assert(ISD && "Invalid opcode");
6510 // Add the final reduction cost for the legal horizontal reduction
6511 switch (ISD) {
6512 case ISD::ADD:
6513 case ISD::AND:
6514 case ISD::OR:
6515 case ISD::XOR:
6516 case ISD::FADD:
6517 return LegalizationCost + 2;
6518 default:
6520 }
6521}
6522
6525 std::optional<FastMathFlags> FMF,
6527 // The code-generator is currently not able to handle scalable vectors
6528 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
6529 // it. This change will be removed when code-generation for these types is
6530 // sufficiently reliable.
6531 if (auto *VTy = dyn_cast<ScalableVectorType>(ValTy))
6532 if (VTy->getElementCount() == ElementCount::getScalable(1))
6534
6536 if (auto *FixedVTy = dyn_cast<FixedVectorType>(ValTy)) {
6537 InstructionCost BaseCost =
6538 BaseT::getArithmeticReductionCost(Opcode, ValTy, FMF, CostKind);
6539 // Add on extra cost to reflect the extra overhead on some CPUs. We still
6540 // end up vectorizing for more computationally intensive loops.
6541 return BaseCost + FixedVTy->getNumElements();
6542 }
6543
6544 if (Opcode != Instruction::FAdd || ValTy->getElementType()->isBFloatTy())
6546
6547 auto *VTy = cast<ScalableVectorType>(ValTy);
6549 getArithmeticInstrCost(Opcode, VTy->getScalarType(), CostKind);
6550 Cost *= getMaxNumElements(VTy->getElementCount());
6551 return Cost;
6552 }
6553
6554 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(ValTy);
6555 MVT MTy = LT.second;
6556
6557 if (isa<ScalableVectorType>(ValTy) || TLI->useSVEForFixedLengthVectorVT(MTy))
6558 return getArithmeticReductionCostSVE(Opcode, ValTy, CostKind);
6559
6560 int ISD = TLI->InstructionOpcodeToISD(Opcode);
6561 assert(ISD && "Invalid opcode");
6562
6563 // Horizontal adds can use the 'addv' instruction. We model the cost of these
6564 // instructions as twice a normal vector add, plus 1 for each legalization
6565 // step (LT.first). This is the only arithmetic vector reduction operation for
6566 // which we have an instruction.
6567 // OR, XOR and AND costs should match the codegen from:
6568 // OR: llvm/test/CodeGen/AArch64/reduce-or.ll
6569 // XOR: llvm/test/CodeGen/AArch64/reduce-xor.ll
6570 // AND: llvm/test/CodeGen/AArch64/reduce-and.ll
6571 static const CostTblEntry CostTblNoPairwise[]{
6572 {ISD::ADD, MVT::v8i8, 2},
6573 {ISD::ADD, MVT::v16i8, 2},
6574 {ISD::ADD, MVT::v4i16, 2},
6575 {ISD::ADD, MVT::v8i16, 2},
6576 {ISD::ADD, MVT::v2i32, 2},
6577 {ISD::ADD, MVT::v4i32, 2},
6578 {ISD::ADD, MVT::v2i64, 2},
6579 {ISD::OR, MVT::v8i8, 5}, // fmov + orr_lsr + orr_lsr + lsr + orr
6580 {ISD::OR, MVT::v16i8, 7}, // ext + orr + same as v8i8
6581 {ISD::OR, MVT::v4i16, 4}, // fmov + orr_lsr + lsr + orr
6582 {ISD::OR, MVT::v8i16, 6}, // ext + orr + same as v4i16
6583 {ISD::OR, MVT::v2i32, 3}, // fmov + lsr + orr
6584 {ISD::OR, MVT::v4i32, 5}, // ext + orr + same as v2i32
6585 {ISD::OR, MVT::v2i64, 3}, // ext + orr + fmov
6586 {ISD::XOR, MVT::v8i8, 5}, // Same as above for or...
6587 {ISD::XOR, MVT::v16i8, 7},
6588 {ISD::XOR, MVT::v4i16, 4},
6589 {ISD::XOR, MVT::v8i16, 6},
6590 {ISD::XOR, MVT::v2i32, 3},
6591 {ISD::XOR, MVT::v4i32, 5},
6592 {ISD::XOR, MVT::v2i64, 3},
6593 {ISD::AND, MVT::v8i8, 5}, // Same as above for or...
6594 {ISD::AND, MVT::v16i8, 7},
6595 {ISD::AND, MVT::v4i16, 4},
6596 {ISD::AND, MVT::v8i16, 6},
6597 {ISD::AND, MVT::v2i32, 3},
6598 {ISD::AND, MVT::v4i32, 5},
6599 {ISD::AND, MVT::v2i64, 3},
6600 };
6601 switch (ISD) {
6602 default:
6603 break;
6604 case ISD::FADD:
6605 if (Type *EltTy = ValTy->getScalarType();
6606 // FIXME: For half types without fullfp16 support, this could extend and
6607 // use a fp32 faddp reduction but current codegen unrolls.
6608 MTy.isVector() && (EltTy->isFloatTy() || EltTy->isDoubleTy() ||
6609 (EltTy->isHalfTy() && ST->hasFullFP16()))) {
6610 const unsigned NElts = MTy.getVectorNumElements();
6611 if (ValTy->getElementCount().getFixedValue() >= 2 && NElts >= 2 &&
6612 isPowerOf2_32(NElts))
6613 // Reduction corresponding to series of fadd instructions is lowered to
6614 // series of faddp instructions. faddp has latency/throughput that
6615 // matches fadd instruction and hence, every faddp instruction can be
6616 // considered to have a relative cost = 1 with
6617 // CostKind = TCK_RecipThroughput.
6618 // An faddp will pairwise add vector elements, so the size of input
6619 // vector reduces by half every time, requiring
6620 // #(faddp instructions) = log2_32(NElts).
6621 return (LT.first - 1) + /*No of faddp instructions*/ Log2_32(NElts);
6622 }
6623 break;
6624 case ISD::ADD:
6625 if (const auto *Entry = CostTableLookup(CostTblNoPairwise, ISD, MTy))
6626 return (LT.first - 1) + Entry->Cost;
6627 break;
6628 case ISD::XOR:
6629 case ISD::AND:
6630 case ISD::OR:
6631 const auto *Entry = CostTableLookup(CostTblNoPairwise, ISD, MTy);
6632 if (!Entry)
6633 break;
6634 auto *ValVTy = cast<FixedVectorType>(ValTy);
6635 if (MTy.getVectorNumElements() <= ValVTy->getNumElements() &&
6636 isPowerOf2_32(ValVTy->getNumElements())) {
6637 InstructionCost ExtraCost = 0;
6638 if (LT.first != 1) {
6639 // Type needs to be split, so there is an extra cost of LT.first - 1
6640 // arithmetic ops.
6641 auto *Ty = FixedVectorType::get(ValTy->getElementType(),
6642 MTy.getVectorNumElements());
6643 ExtraCost = getArithmeticInstrCost(Opcode, Ty, CostKind);
6644 ExtraCost *= LT.first - 1;
6645 }
6646 // All and/or/xor of i1 will be lowered with maxv/minv/addv + fmov
6647 auto Cost = ValVTy->getElementType()->isIntegerTy(1) ? 2 : Entry->Cost;
6648 return Cost + ExtraCost;
6649 }
6650 break;
6651 }
6652 return BaseT::getArithmeticReductionCost(Opcode, ValTy, FMF, CostKind);
6653}
6654
6656 unsigned Opcode, bool IsUnsigned, Type *ResTy, VectorType *VecTy,
6657 std::optional<FastMathFlags> FMF, TTI::TargetCostKind CostKind) const {
6658 EVT VecVT = TLI->getValueType(DL, VecTy);
6659 EVT ResVT = TLI->getValueType(DL, ResTy);
6660
6661 if (Opcode == Instruction::Add && VecVT.isSimple() && ResVT.isSimple() &&
6662 VecVT.getSizeInBits() >= 64) {
6663 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(VecTy);
6664
6665 // The legal cases are:
6666 // UADDLV 8/16/32->32
6667 // UADDLP 32->64
6668 unsigned RevVTSize = ResVT.getSizeInBits();
6669 if (((LT.second == MVT::v8i8 || LT.second == MVT::v16i8) &&
6670 RevVTSize <= 32) ||
6671 ((LT.second == MVT::v4i16 || LT.second == MVT::v8i16) &&
6672 RevVTSize <= 32) ||
6673 ((LT.second == MVT::v2i32 || LT.second == MVT::v4i32) &&
6674 RevVTSize <= 64))
6675 return (LT.first - 1) * 2 + 2;
6676 }
6677
6678 return BaseT::getExtendedReductionCost(Opcode, IsUnsigned, ResTy, VecTy, FMF,
6679 CostKind);
6680}
6681
6683AArch64TTIImpl::getMulAccReductionCost(bool IsUnsigned, unsigned RedOpcode,
6684 Type *ResTy, VectorType *VecTy,
6686 EVT VecVT = TLI->getValueType(DL, VecTy);
6687 EVT ResVT = TLI->getValueType(DL, ResTy);
6688
6689 if (ST->hasDotProd() && VecVT.isSimple() && ResVT.isSimple() &&
6690 RedOpcode == Instruction::Add) {
6691 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(VecTy);
6692
6693 // The legal cases with dotprod are
6694 // UDOT 8->32
6695 // Which requires an additional uaddv to sum the i32 values.
6696 if ((LT.second == MVT::v8i8 || LT.second == MVT::v16i8) &&
6697 ResVT == MVT::i32)
6698 return LT.first + 2;
6699 }
6700
6701 return BaseT::getMulAccReductionCost(IsUnsigned, RedOpcode, ResTy, VecTy,
6702 CostKind);
6703}
6704
6708 static const CostTblEntry ShuffleTbl[] = {
6709 { TTI::SK_Splice, MVT::nxv16i8, 1 },
6710 { TTI::SK_Splice, MVT::nxv8i16, 1 },
6711 { TTI::SK_Splice, MVT::nxv4i32, 1 },
6712 { TTI::SK_Splice, MVT::nxv2i64, 1 },
6713 { TTI::SK_Splice, MVT::nxv2f16, 1 },
6714 { TTI::SK_Splice, MVT::nxv4f16, 1 },
6715 { TTI::SK_Splice, MVT::nxv8f16, 1 },
6716 { TTI::SK_Splice, MVT::nxv2bf16, 1 },
6717 { TTI::SK_Splice, MVT::nxv4bf16, 1 },
6718 { TTI::SK_Splice, MVT::nxv8bf16, 1 },
6719 { TTI::SK_Splice, MVT::nxv2f32, 1 },
6720 { TTI::SK_Splice, MVT::nxv4f32, 1 },
6721 { TTI::SK_Splice, MVT::nxv2f64, 1 },
6722 };
6723
6724 // The code-generator is currently not able to handle scalable vectors
6725 // of <vscale x 1 x eltty> yet, so return an invalid cost to avoid selecting
6726 // it. This change will be removed when code-generation for these types is
6727 // sufficiently reliable.
6730
6731 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Tp);
6732 Type *LegalVTy = EVT(LT.second).getTypeForEVT(Tp->getContext());
6733 EVT PromotedVT = LT.second.getScalarType() == MVT::i1
6734 ? TLI->getPromotedVTForPredicate(EVT(LT.second))
6735 : LT.second;
6736 Type *PromotedVTy = EVT(PromotedVT).getTypeForEVT(Tp->getContext());
6737 InstructionCost LegalizationCost = 0;
6738 if (Index < 0) {
6739 LegalizationCost =
6740 getCmpSelInstrCost(Instruction::ICmp, PromotedVTy, PromotedVTy,
6742 getCmpSelInstrCost(Instruction::Select, PromotedVTy, LegalVTy,
6744 }
6745
6746 // Predicated splice are promoted when lowering. See AArch64ISelLowering.cpp
6747 // Cost performed on a promoted type.
6748 if (LT.second.getScalarType() == MVT::i1) {
6749 LegalizationCost +=
6750 getCastInstrCost(Instruction::ZExt, PromotedVTy, LegalVTy,
6752 getCastInstrCost(Instruction::Trunc, LegalVTy, PromotedVTy,
6754 }
6755 const auto *Entry =
6756 CostTableLookup(ShuffleTbl, TTI::SK_Splice, PromotedVT.getSimpleVT());
6757 assert(Entry && "Illegal Type for Splice");
6758 LegalizationCost += Entry->Cost;
6759 return LegalizationCost * LT.first;
6760}
6761
6763 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
6765 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
6766 TTI::TargetCostKind CostKind, std::optional<FastMathFlags> FMF) const {
6768
6770 return Invalid;
6771
6772 if ((Opcode != Instruction::Add && Opcode != Instruction::Sub &&
6773 Opcode != Instruction::FAdd && Opcode != Instruction::FSub))
6774 return Invalid;
6775
6776 // Floating-point partial reductions are invalid if `reassoc` and `contract`
6777 // are not allowed.
6778 if (AccumType->isFloatingPointTy()) {
6779 assert(FMF && "Missing FastMathFlags for floating-point partial reduction");
6780 if (!FMF->allowReassoc() || !FMF->allowContract())
6781 return Invalid;
6782 } else {
6783 assert(!FMF &&
6784 "FastMathFlags only apply to floating-point partial reductions");
6785 }
6786
6787 assert((BinOp || (OpBExtend == TTI::PR_None && !InputTypeB)) &&
6788 (!BinOp || (OpBExtend != TTI::PR_None && InputTypeB)) &&
6789 "Unexpected values for OpBExtend or InputTypeB");
6790
6791 // We only support multiply binary operations for now, and for muls we
6792 // require the types being extended to be the same.
6793 if (BinOp && ((*BinOp != Instruction::Mul && *BinOp != Instruction::FMul) ||
6794 InputTypeA != InputTypeB))
6795 return Invalid;
6796
6797 // We only support the following element sizes.
6798 if (!is_contained({8u, 16u, 32u, 64u}, AccumType->getScalarSizeInBits()))
6799 return Invalid;
6800
6801 // If none of the operands are extended and there's no extra BinOp, just
6802 // cost this as the equivalent arithmetic instruction.
6803 // TODO: Depending on VF and element type, we may be able to improve on this.
6804 if (!OpAExtend) {
6805 assert(!OpBExtend && "Extended second operand without extended first.");
6806 assert(InputTypeA == AccumType && "Type mismatch with no extensions.");
6807
6808 VectorType *VTy = VectorType::get(AccumType, VF);
6809 return getArithmeticInstrCost(Opcode, VTy, CostKind);
6810 }
6811
6812 bool IsUSDot = OpBExtend != TTI::PR_None && OpAExtend != OpBExtend;
6813 // USDot is natively supported with +i8mm. With plain +dotprod, SUMLA is
6814 // lowered to two udots plus an eor and a sub.
6815 if (IsUSDot && !ST->hasMatMulInt8() && !ST->hasDotProd())
6816 // FIXME: Remove this early bailout in favour of expand cost.
6817 return Invalid;
6818
6819 unsigned Ratio =
6820 AccumType->getScalarSizeInBits() / InputTypeA->getScalarSizeInBits();
6821 if (VF.getKnownMinValue() <= Ratio)
6822 return Invalid;
6823
6824 VectorType *InputVectorType = VectorType::get(InputTypeA, VF);
6825 VectorType *AccumVectorType =
6826 VectorType::get(AccumType, VF.divideCoefficientBy(Ratio));
6827 // We don't yet support all kinds of legalization.
6828 auto TC = TLI->getTypeConversion(AccumVectorType->getContext(),
6829 EVT::getEVT(AccumVectorType));
6830 switch (TC.first) {
6831 default:
6832 return Invalid;
6836 // The legalised type (e.g. after splitting) must be legal too.
6837 if (TLI->getTypeAction(AccumVectorType->getContext(), TC.second) !=
6839 return Invalid;
6840 break;
6841 }
6842
6843 std::pair<InstructionCost, MVT> AccumLT =
6844 getTypeLegalizationCost(AccumVectorType);
6845 std::pair<InstructionCost, MVT> InputLT =
6846 getTypeLegalizationCost(InputVectorType);
6847
6848 // Returns true if the subtarget supports the operation for a given type.
6849 auto IsSupported = [&](bool SVEPred, bool NEONPred) -> bool {
6850 return (ST->isSVEorStreamingSVEAvailable() && SVEPred) ||
6851 (AccumLT.second.isFixedLengthVector() &&
6852 AccumLT.second.getSizeInBits() <= 128 && ST->isNeonAvailable() &&
6853 NEONPred);
6854 };
6855
6856 bool IsSub = Opcode == Instruction::Sub || Opcode == Instruction::FSub;
6857 InstructionCost Cost = InputLT.first * TTI::TCC_Basic;
6858 // Integer partial sub-reductions that don't map to a specific instruction,
6859 // carry an extra cost for implementing a double negation:
6860 // partial_reduce_umls acc, lhs, rhs
6861 // <=> -partial_reduce_umla -acc, lhs, rhs
6862 InstructionCost INegCost = IsSub ? 2 * InputLT.first * TTI::TCC_Basic : 0;
6863
6864 if (AccumLT.second.getScalarType() == MVT::i32 &&
6865 InputLT.second.getScalarType() == MVT::i8) {
6866 // i8 -> i32 is natively supported with udot/sdot for both NEON and SVE.
6867 if (!IsUSDot && IsSupported(true, ST->hasDotProd()))
6868 return Cost + INegCost;
6869 // i8 -> i32 usdot requires +i8mm
6870 if (IsUSDot && IsSupported(ST->hasMatMulInt8(), ST->hasMatMulInt8()))
6871 return Cost + INegCost;
6872 // Without +i8mm, lower SUMLA via two udots plus an eor and a sub on plain
6873 // +dotprod targets. Note that this is only implemented for NEON, as all
6874 // modern CPUs with SVE also have +i8mm. Charge an extra factor for the
6875 // expansion.
6876 if (IsUSDot && IsSupported(false, ST->hasDotProd()))
6877 return Cost * 3 + INegCost;
6878 }
6879
6880 if (ST->isSVEorStreamingSVEAvailable() && !IsUSDot) {
6881 // i16 -> i64 is natively supported for udot/sdot
6882 if (AccumLT.second.getScalarType() == MVT::i64 &&
6883 InputLT.second.getScalarType() == MVT::i16)
6884 return Cost + INegCost;
6885 // i16 -> i32 is natively supported with SVE2p1 udot/sdot.
6886 // For sub-reductions, we prefer using the *mlslb/t instructions.
6887 if (AccumLT.second.getScalarType() == MVT::i32 &&
6888 InputLT.second.getScalarType() == MVT::i16 &&
6889 (ST->hasSVE2p1() || ST->hasSME2()) && !IsSub)
6890 return Cost;
6891 // i8 -> i64 is supported with an extra level of extends
6892 if (AccumLT.second.getScalarType() == MVT::i64 &&
6893 InputLT.second.getScalarType() == MVT::i8)
6894 // FIXME: This cost should probably be a little higher, e.g. Cost + 2
6895 // because it requires two extra extends on the inputs. But if we'd change
6896 // that now, a regular reduction would be cheaper because the costs of
6897 // the extends in the IR are still counted. This can be fixed
6898 // after https://github.com/llvm/llvm-project/pull/147302 has landed.
6899 return Cost + INegCost;
6900 // i8 -> i16 is natively supported with SVE2p3 udot/sdot
6901 // For sub-reductions, we prefer using the *mlslb/t instructions.
6902 if (AccumLT.second.getScalarType() == MVT::i16 &&
6903 InputLT.second.getScalarType() == MVT::i8 &&
6904 (ST->hasSVE2p3() || ST->hasSME2p3()) && !IsSub)
6905 return Cost;
6906 }
6907
6908 // f16 -> f32 is natively supported for fdot using either
6909 // SVE or NEON instruction.
6910 if (Opcode == Instruction::FAdd && !IsSub &&
6911 IsSupported(ST->hasSME2() || ST->hasSVE2p1(), ST->hasF16F32DOT()) &&
6912 AccumLT.second.getScalarType() == MVT::f32 &&
6913 InputLT.second.getScalarType() == MVT::f16)
6914 return Cost;
6915
6916 // For a ratio of 2, we can use *mlal and *mlsl top/bottom instructions.
6917 if (Ratio == 2 && !IsUSDot) {
6918 MVT InVT = InputLT.second.getScalarType();
6919
6920 // SVE2 [us]ml[as]lb/t and NEON [us]ml[as]l(2). A pure widening add with a
6921 // ratio of 2 can use [SU]ADALP instead.
6922 if (IsSupported(ST->hasSVE2() || ST->hasSME(), true) &&
6923 llvm::is_contained({MVT::i8, MVT::i16, MVT::i32}, InVT.SimpleTy))
6924 return (BinOp || IsSub) ? Cost * 2 : Cost;
6925
6926 // SVE2 fml[as]lb/t and NEON fml[as]l(2)
6927 if (IsSupported(ST->hasSVE2(), ST->hasFP16FML()) && InVT == MVT::f16)
6928 return Cost * 2;
6929
6930 // SME2/SVE2p1 bfmlslb/t
6931 if (IsSupported(ST->hasSVE2p1() || ST->hasSME2(), false) &&
6932 InVT == MVT::bf16 && IsSub)
6933 return Cost * 2;
6934
6935 // FP partial sub-reductions that don't map to a specific instruction,
6936 // carry an extra cost for implementing an extra negation:
6937 // partial_reduce_fmls acc, lhs, rhs
6938 // <=> partial_reduce_fmla acc, lhs, -rhs
6939 InstructionCost FNegCost = IsSub ? InputLT.first * TTI::TCC_Basic : 0;
6940
6941 // SVE and NEON bfmlalb/t
6942 if (IsSupported(ST->hasBF16(), ST->hasBF16()) && InVT == MVT::bf16)
6943 return Cost * 2 + FNegCost;
6944 }
6945
6946 return BaseT::getPartialReductionCost(Opcode, InputTypeA, InputTypeB,
6947 AccumType, VF, OpAExtend, OpBExtend,
6948 BinOp, CostKind, FMF);
6949}
6950
6954 ArrayRef<int> Mask, int Index, VectorType *SubTp,
6956 const Instruction *CxtI) const {
6957 assert((Mask.empty() || DstTy->isScalableTy() ||
6958 Mask.size() == DstTy->getElementCount().getKnownMinValue()) &&
6959 "Expected the Mask to match the return size if given");
6960 assert(SrcTy->getScalarType() == DstTy->getScalarType() &&
6961 "Expected the same scalar types");
6962 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(SrcTy);
6963
6964 // If we have a Mask, and the LT is being legalized somehow, split the Mask
6965 // into smaller vectors and sum the cost of each shuffle.
6966 if (!Mask.empty() && isa<FixedVectorType>(SrcTy) && LT.second.isVector() &&
6967 LT.second.getScalarSizeInBits() * Mask.size() > 128 &&
6968 SrcTy->getScalarSizeInBits() == LT.second.getScalarSizeInBits() &&
6969 Mask.size() > LT.second.getVectorNumElements() && !Index && !SubTp) {
6970 // Check for LD3/LD4 instructions, which are represented in llvm IR as
6971 // deinterleaving-shuffle(load). The shuffle cost could potentially be free,
6972 // but we model it with a cost of LT.first so that LD3/LD4 have a higher
6973 // cost than just the load.
6974 if (Args.size() >= 1 && isa<LoadInst>(Args[0]) &&
6977 return std::max<InstructionCost>(1, LT.first / 4);
6978
6979 // Check for ST3/ST4 instructions, which are represented in llvm IR as
6980 // store(interleaving-shuffle). The shuffle cost could potentially be free,
6981 // but we model it with a cost of LT.first so that ST3/ST4 have a higher
6982 // cost than just the store.
6983 if (CxtI && CxtI->hasOneUse() && isa<StoreInst>(*CxtI->user_begin()) &&
6985 Mask, 4, SrcTy->getElementCount().getKnownMinValue() * 2) ||
6987 Mask, 3, SrcTy->getElementCount().getKnownMinValue() * 2)))
6988 return LT.first;
6989
6990 unsigned TpNumElts = Mask.size();
6991 unsigned LTNumElts = LT.second.getVectorNumElements();
6992 unsigned NumVecs = (TpNumElts + LTNumElts - 1) / LTNumElts;
6993 VectorType *NTp = VectorType::get(SrcTy->getScalarType(),
6994 LT.second.getVectorElementCount());
6996 std::map<std::tuple<unsigned, unsigned, SmallVector<int>>, InstructionCost>
6997 PreviousCosts;
6998 for (unsigned N = 0; N < NumVecs; N++) {
6999 SmallVector<int> NMask;
7000 // Split the existing mask into chunks of size LTNumElts. Track the source
7001 // sub-vectors to ensure the result has at most 2 inputs.
7002 unsigned Source1 = -1U, Source2 = -1U;
7003 unsigned NumSources = 0;
7004 for (unsigned E = 0; E < LTNumElts; E++) {
7005 int MaskElt = (N * LTNumElts + E < TpNumElts) ? Mask[N * LTNumElts + E]
7007 if (MaskElt < 0) {
7009 continue;
7010 }
7011
7012 // Calculate which source from the input this comes from and whether it
7013 // is new to us.
7014 unsigned Source = MaskElt / LTNumElts;
7015 if (NumSources == 0) {
7016 Source1 = Source;
7017 NumSources = 1;
7018 } else if (NumSources == 1 && Source != Source1) {
7019 Source2 = Source;
7020 NumSources = 2;
7021 } else if (NumSources >= 2 && Source != Source1 && Source != Source2) {
7022 NumSources++;
7023 }
7024
7025 // Add to the new mask. For the NumSources>2 case these are not correct,
7026 // but are only used for the modular lane number.
7027 if (Source == Source1)
7028 NMask.push_back(MaskElt % LTNumElts);
7029 else if (Source == Source2)
7030 NMask.push_back(MaskElt % LTNumElts + LTNumElts);
7031 else
7032 NMask.push_back(MaskElt % LTNumElts);
7033 }
7034 // Check if we have already generated this sub-shuffle, which means we
7035 // will have already generated the output. For example a <16 x i32> splat
7036 // will be the same sub-splat 4 times, which only needs to be generated
7037 // once and reused.
7038 auto Result =
7039 PreviousCosts.insert({std::make_tuple(Source1, Source2, NMask), 0});
7040 // Check if it was already in the map (already costed).
7041 if (!Result.second)
7042 continue;
7043 // If the sub-mask has at most 2 input sub-vectors then re-cost it using
7044 // getShuffleCost. If not then cost it using the worst case as the number
7045 // of element moves into a new vector.
7046 InstructionCost NCost =
7047 NumSources <= 2
7048 ? getShuffleCost(NumSources <= 1 ? TTI::SK_PermuteSingleSrc
7050 NTp, NTp, CostKind, NMask, 0, nullptr, Args,
7051 CxtI)
7052 : LTNumElts;
7053 Result.first->second = NCost;
7054 Cost += NCost;
7055 }
7056 return Cost;
7057 }
7058
7059 Kind = improveShuffleKindFromMask(Kind, Mask, SrcTy, Index, SubTp);
7060 bool IsExtractSubvector = Kind == TTI::SK_ExtractSubvector;
7061 // A subvector extract can be implemented with a NEON/SVE ext (or trivial
7062 // extract, if from lane 0) for 128-bit NEON vectors or legal SVE vectors.
7063 // This currently only handles low or high extracts to prevent SLP vectorizer
7064 // regressions.
7065 // Note that SVE's ext instruction is destructive, but it can be fused with
7066 // a movprfx to act like a constructive instruction.
7067 if (IsExtractSubvector && LT.second.isFixedLengthVector()) {
7068 if (LT.second.getFixedSizeInBits() >= 128 &&
7069 cast<FixedVectorType>(SubTp)->getNumElements() ==
7070 LT.second.getVectorNumElements() / 2) {
7071 if (Index == 0)
7072 return 0;
7073 if (Index == (int)LT.second.getVectorNumElements() / 2)
7074 return 1;
7075 }
7077 }
7078 // FIXME: This was added to keep the costs equal when adding DstTys. Update
7079 // the code to handle length-changing shuffles.
7080 if (Kind == TTI::SK_InsertSubvector) {
7081 LT = getTypeLegalizationCost(DstTy);
7082 SrcTy = DstTy;
7083 }
7084
7085 // Check for identity masks, which we can treat as free for both fixed and
7086 // scalable vector paths.
7087 if (!Mask.empty() && LT.second.isFixedLengthVector() &&
7088 (Kind == TTI::SK_PermuteTwoSrc || Kind == TTI::SK_PermuteSingleSrc) &&
7089 all_of(enumerate(Mask), [](const auto &M) {
7090 return M.value() < 0 || M.value() == (int)M.index();
7091 }))
7092 return 0;
7093
7094 // Segmented shuffle matching.
7095 if (Kind == TTI::SK_PermuteSingleSrc && isa<FixedVectorType>(SrcTy) &&
7096 !Mask.empty() && SrcTy->getPrimitiveSizeInBits().isNonZero() &&
7097 SrcTy->getPrimitiveSizeInBits().isKnownMultipleOf(
7099
7101 unsigned Segments =
7103 unsigned SegmentElts = VTy->getNumElements() / Segments;
7104
7105 // dupq zd.t, zn.t[idx]
7106 if ((ST->hasSVE2p1() || ST->hasSME2p1()) &&
7107 ST->isSVEorStreamingSVEAvailable() &&
7108 isDUPQMask(Mask, Segments, SegmentElts))
7109 return LT.first;
7110
7111 // mov zd.q, vn
7112 if (ST->isSVEorStreamingSVEAvailable() &&
7113 isDUPFirstSegmentMask(Mask, Segments, SegmentElts))
7114 return LT.first;
7115 }
7116
7117 // Check for broadcast loads, which are supported by the LD1R instruction.
7118 // In terms of code-size, the shuffle vector is free when a load + dup get
7119 // folded into a LD1R. That's what we check and return here. For performance
7120 // and reciprocal throughput, a LD1R is not completely free. In this case, we
7121 // return the cost for the broadcast below (i.e. 1 for most/all types), so
7122 // that we model the load + dup sequence slightly higher because LD1R is a
7123 // high latency instruction.
7124 if (CostKind == TTI::TCK_CodeSize && Kind == TTI::SK_Broadcast) {
7125 bool IsLoad = !Args.empty() && isa<LoadInst>(Args[0]);
7126 if (IsLoad && LT.second.isVector() &&
7127 isLegalBroadcastLoad(SrcTy->getElementType(),
7128 LT.second.getVectorElementCount()))
7129 return 0;
7130 }
7131
7132 // If we have 4 elements for the shuffle and a Mask, get the cost straight
7133 // from the perfect shuffle tables.
7134 if (Mask.size() == 4 &&
7135 SrcTy->getElementCount() == ElementCount::getFixed(4) &&
7136 (SrcTy->getScalarSizeInBits() == 16 ||
7137 SrcTy->getScalarSizeInBits() == 32) &&
7138 all_of(Mask, [](int E) { return E < 8; }))
7139 return getPerfectShuffleCost(Mask);
7140
7141 // Check for other shuffles that are not SK_ kinds but we have native
7142 // instructions for, for example ZIP and UZP.
7143 unsigned Unused;
7144 if (LT.second.isFixedLengthVector() &&
7145 LT.second.getVectorNumElements() == Mask.size() &&
7146 (Kind == TTI::SK_PermuteTwoSrc || Kind == TTI::SK_PermuteSingleSrc ||
7147 // Discrepancies between isTRNMask and ShuffleVectorInst::isTransposeMask
7148 // mean that we can end up with shuffles that satisfy isTRNMask, but end
7149 // up labelled as TTI::SK_InsertSubvector. (e.g. {2, 0}).
7150 Kind == TTI::SK_InsertSubvector) &&
7151 (isZIPMask(Mask, LT.second.getVectorNumElements(), Unused, Unused) ||
7152 isTRNMask(Mask, LT.second.getVectorNumElements(), Unused, Unused) ||
7153 isUZPMask(Mask, LT.second.getVectorNumElements(), Unused) ||
7154 isREVMask(Mask, LT.second.getScalarSizeInBits(),
7155 LT.second.getVectorNumElements(), 16) ||
7156 isREVMask(Mask, LT.second.getScalarSizeInBits(),
7157 LT.second.getVectorNumElements(), 32) ||
7158 isREVMask(Mask, LT.second.getScalarSizeInBits(),
7159 LT.second.getVectorNumElements(), 64) ||
7160 // Check for non-zero lane splats
7161 all_of(drop_begin(Mask),
7162 [&Mask](int M) { return M < 0 || M == Mask[0]; })))
7163 return 1;
7164
7165 if (Kind == TTI::SK_Broadcast || Kind == TTI::SK_Transpose ||
7166 Kind == TTI::SK_Select || Kind == TTI::SK_PermuteSingleSrc ||
7167 Kind == TTI::SK_Reverse || Kind == TTI::SK_Splice) {
7168 static const CostTblEntry ShuffleTbl[] = {
7169 // Broadcast shuffle kinds can be performed with 'dup'.
7170 {TTI::SK_Broadcast, MVT::v8i8, 1},
7171 {TTI::SK_Broadcast, MVT::v16i8, 1},
7172 {TTI::SK_Broadcast, MVT::v4i16, 1},
7173 {TTI::SK_Broadcast, MVT::v8i16, 1},
7174 {TTI::SK_Broadcast, MVT::v2i32, 1},
7175 {TTI::SK_Broadcast, MVT::v4i32, 1},
7176 {TTI::SK_Broadcast, MVT::v2i64, 1},
7177 {TTI::SK_Broadcast, MVT::v4f16, 1},
7178 {TTI::SK_Broadcast, MVT::v8f16, 1},
7179 {TTI::SK_Broadcast, MVT::v4bf16, 1},
7180 {TTI::SK_Broadcast, MVT::v8bf16, 1},
7181 {TTI::SK_Broadcast, MVT::v2f32, 1},
7182 {TTI::SK_Broadcast, MVT::v4f32, 1},
7183 {TTI::SK_Broadcast, MVT::v2f64, 1},
7184 // Transpose shuffle kinds can be performed with 'trn1/trn2' and
7185 // 'zip1/zip2' instructions.
7186 {TTI::SK_Transpose, MVT::v8i8, 1},
7187 {TTI::SK_Transpose, MVT::v16i8, 1},
7188 {TTI::SK_Transpose, MVT::v4i16, 1},
7189 {TTI::SK_Transpose, MVT::v8i16, 1},
7190 {TTI::SK_Transpose, MVT::v2i32, 1},
7191 {TTI::SK_Transpose, MVT::v4i32, 1},
7192 {TTI::SK_Transpose, MVT::v2i64, 1},
7193 {TTI::SK_Transpose, MVT::v4f16, 1},
7194 {TTI::SK_Transpose, MVT::v8f16, 1},
7195 {TTI::SK_Transpose, MVT::v4bf16, 1},
7196 {TTI::SK_Transpose, MVT::v8bf16, 1},
7197 {TTI::SK_Transpose, MVT::v2f32, 1},
7198 {TTI::SK_Transpose, MVT::v4f32, 1},
7199 {TTI::SK_Transpose, MVT::v2f64, 1},
7200 // Select shuffle kinds.
7201 // TODO: handle vXi8/vXi16.
7202 {TTI::SK_Select, MVT::v2i32, 1}, // mov.
7203 {TTI::SK_Select, MVT::v4i32, 2}, // rev+trn (or similar).
7204 {TTI::SK_Select, MVT::v2i64, 1}, // mov.
7205 {TTI::SK_Select, MVT::v2f32, 1}, // mov.
7206 {TTI::SK_Select, MVT::v4f32, 2}, // rev+trn (or similar).
7207 {TTI::SK_Select, MVT::v2f64, 1}, // mov.
7208 // PermuteSingleSrc shuffle kinds.
7209 {TTI::SK_PermuteSingleSrc, MVT::v2i32, 1}, // mov.
7210 {TTI::SK_PermuteSingleSrc, MVT::v4i32, 3}, // perfectshuffle worst case.
7211 {TTI::SK_PermuteSingleSrc, MVT::v2i64, 1}, // mov.
7212 {TTI::SK_PermuteSingleSrc, MVT::v2f32, 1}, // mov.
7213 {TTI::SK_PermuteSingleSrc, MVT::v4f32, 3}, // perfectshuffle worst case.
7214 {TTI::SK_PermuteSingleSrc, MVT::v2f64, 1}, // mov.
7215 {TTI::SK_PermuteSingleSrc, MVT::v4i16, 3}, // perfectshuffle worst case.
7216 {TTI::SK_PermuteSingleSrc, MVT::v4f16, 3}, // perfectshuffle worst case.
7217 {TTI::SK_PermuteSingleSrc, MVT::v4bf16, 3}, // same
7218 {TTI::SK_PermuteSingleSrc, MVT::v8i16, 8}, // constpool + load + tbl
7219 {TTI::SK_PermuteSingleSrc, MVT::v8f16, 8}, // constpool + load + tbl
7220 {TTI::SK_PermuteSingleSrc, MVT::v8bf16, 8}, // constpool + load + tbl
7221 {TTI::SK_PermuteSingleSrc, MVT::v8i8, 8}, // constpool + load + tbl
7222 {TTI::SK_PermuteSingleSrc, MVT::v16i8, 8}, // constpool + load + tbl
7223 // Reverse can be lowered with `rev`.
7224 {TTI::SK_Reverse, MVT::v2i32, 1}, // REV64
7225 {TTI::SK_Reverse, MVT::v4i32, 2}, // REV64; EXT
7226 {TTI::SK_Reverse, MVT::v2i64, 1}, // EXT
7227 {TTI::SK_Reverse, MVT::v2f32, 1}, // REV64
7228 {TTI::SK_Reverse, MVT::v4f32, 2}, // REV64; EXT
7229 {TTI::SK_Reverse, MVT::v2f64, 1}, // EXT
7230 {TTI::SK_Reverse, MVT::v8f16, 2}, // REV64; EXT
7231 {TTI::SK_Reverse, MVT::v8bf16, 2}, // REV64; EXT
7232 {TTI::SK_Reverse, MVT::v8i16, 2}, // REV64; EXT
7233 {TTI::SK_Reverse, MVT::v16i8, 2}, // REV64; EXT
7234 {TTI::SK_Reverse, MVT::v4f16, 1}, // REV64
7235 {TTI::SK_Reverse, MVT::v4bf16, 1}, // REV64
7236 {TTI::SK_Reverse, MVT::v4i16, 1}, // REV64
7237 {TTI::SK_Reverse, MVT::v8i8, 1}, // REV64
7238 // Splice can all be lowered as `ext`.
7239 {TTI::SK_Splice, MVT::v2i32, 1},
7240 {TTI::SK_Splice, MVT::v4i32, 1},
7241 {TTI::SK_Splice, MVT::v2i64, 1},
7242 {TTI::SK_Splice, MVT::v2f32, 1},
7243 {TTI::SK_Splice, MVT::v4f32, 1},
7244 {TTI::SK_Splice, MVT::v2f64, 1},
7245 {TTI::SK_Splice, MVT::v8f16, 1},
7246 {TTI::SK_Splice, MVT::v8bf16, 1},
7247 {TTI::SK_Splice, MVT::v8i16, 1},
7248 {TTI::SK_Splice, MVT::v16i8, 1},
7249 {TTI::SK_Splice, MVT::v4f16, 1},
7250 {TTI::SK_Splice, MVT::v4bf16, 1},
7251 {TTI::SK_Splice, MVT::v4i16, 1},
7252 {TTI::SK_Splice, MVT::v8i8, 1},
7253 // Broadcast shuffle kinds for scalable vectors
7254 {TTI::SK_Broadcast, MVT::nxv16i8, 1},
7255 {TTI::SK_Broadcast, MVT::nxv8i16, 1},
7256 {TTI::SK_Broadcast, MVT::nxv4i32, 1},
7257 {TTI::SK_Broadcast, MVT::nxv2i64, 1},
7258 {TTI::SK_Broadcast, MVT::nxv2f16, 1},
7259 {TTI::SK_Broadcast, MVT::nxv4f16, 1},
7260 {TTI::SK_Broadcast, MVT::nxv8f16, 1},
7261 {TTI::SK_Broadcast, MVT::nxv2bf16, 1},
7262 {TTI::SK_Broadcast, MVT::nxv4bf16, 1},
7263 {TTI::SK_Broadcast, MVT::nxv8bf16, 1},
7264 {TTI::SK_Broadcast, MVT::nxv2f32, 1},
7265 {TTI::SK_Broadcast, MVT::nxv4f32, 1},
7266 {TTI::SK_Broadcast, MVT::nxv2f64, 1},
7267 {TTI::SK_Broadcast, MVT::nxv16i1, 1},
7268 {TTI::SK_Broadcast, MVT::nxv8i1, 1},
7269 {TTI::SK_Broadcast, MVT::nxv4i1, 1},
7270 {TTI::SK_Broadcast, MVT::nxv2i1, 1},
7271 // Handle the cases for vector.reverse with scalable vectors
7272 {TTI::SK_Reverse, MVT::nxv16i8, 1},
7273 {TTI::SK_Reverse, MVT::nxv8i16, 1},
7274 {TTI::SK_Reverse, MVT::nxv4i32, 1},
7275 {TTI::SK_Reverse, MVT::nxv2i64, 1},
7276 {TTI::SK_Reverse, MVT::nxv2f16, 1},
7277 {TTI::SK_Reverse, MVT::nxv4f16, 1},
7278 {TTI::SK_Reverse, MVT::nxv8f16, 1},
7279 {TTI::SK_Reverse, MVT::nxv2bf16, 1},
7280 {TTI::SK_Reverse, MVT::nxv4bf16, 1},
7281 {TTI::SK_Reverse, MVT::nxv8bf16, 1},
7282 {TTI::SK_Reverse, MVT::nxv2f32, 1},
7283 {TTI::SK_Reverse, MVT::nxv4f32, 1},
7284 {TTI::SK_Reverse, MVT::nxv2f64, 1},
7285 {TTI::SK_Reverse, MVT::nxv16i1, 1},
7286 {TTI::SK_Reverse, MVT::nxv8i1, 1},
7287 {TTI::SK_Reverse, MVT::nxv4i1, 1},
7288 {TTI::SK_Reverse, MVT::nxv2i1, 1},
7289 };
7290 if (const auto *Entry = CostTableLookup(ShuffleTbl, Kind, LT.second))
7291 return LT.first * Entry->Cost;
7292 }
7293
7294 if (Kind == TTI::SK_Splice && isa<ScalableVectorType>(SrcTy))
7295 return getSpliceCost(SrcTy, Index, CostKind);
7296
7297 // Inserting a subvector can often be done with either a D, S or H register
7298 // move, so long as the inserted vector is "aligned".
7299 if (Kind == TTI::SK_InsertSubvector && LT.second.isFixedLengthVector() &&
7300 LT.second.getSizeInBits() <= 128 && SubTp) {
7301 std::pair<InstructionCost, MVT> SubLT = getTypeLegalizationCost(SubTp);
7302 if (SubLT.second.isVector()) {
7303 int NumElts = LT.second.getVectorNumElements();
7304 int NumSubElts = SubLT.second.getVectorNumElements();
7305 if ((Index % NumSubElts) == 0 && (NumElts % NumSubElts) == 0)
7306 return SubLT.first;
7307 }
7308 }
7309
7310 // Restore optimal kind.
7311 if (IsExtractSubvector)
7313 return BaseT::getShuffleCost(Kind, DstTy, SrcTy, CostKind, Mask, Index, SubTp,
7314 Args, CxtI);
7315}
7316
7319 const DominatorTree &DT) {
7320 const auto &Strides = SymbolicStrideMap();
7321 for (BasicBlock *BB : TheLoop->blocks()) {
7322 // Scan the instructions in the block and look for addresses that are
7323 // consecutive and decreasing.
7324 for (Instruction &I : *BB) {
7325 if (isa<LoadInst>(&I) || isa<StoreInst>(&I)) {
7327 Type *AccessTy = getLoadStoreType(&I);
7328 // Analyze assuming predicates will be added, but discard them; this
7329 // query only guides tail-folding and must not add runtime checks to the
7330 // loop.
7332 if (getPtrStride(*PSE, AccessTy, Ptr, TheLoop, DT, Strides,
7333 /*ShouldCheckWrap=*/false, &Predicates)
7334 .value_or(0) < 0)
7335 return true;
7336 }
7337 }
7338 }
7339 return false;
7340}
7341
7343 if (SVEPreferFixedOverScalableIfEqualCost.getNumOccurrences())
7345 return ST->useFixedOverScalableIfEqualCost();
7346}
7347
7349 return ST->getEpilogueVectorizationMinVF();
7350}
7351
7353 if (!ST->hasSVE())
7354 return false;
7355
7356 // We don't currently support vectorisation with interleaving for SVE - with
7357 // such loops we're better off not using tail-folding. This gives us a chance
7358 // to fall back on fixed-width vectorisation using NEON's ld2/st2/etc.
7359 if (TFI->IAI->hasGroups())
7360 return false;
7361
7363 if (TFI->LVL->getReductionVars().size())
7364 Required |= TailFoldingOpts::Reductions;
7365 if (TFI->LVL->getFixedOrderRecurrences().size())
7366 Required |= TailFoldingOpts::Recurrences;
7367
7368 // We call this to discover whether any load/store pointers in the loop have
7369 // negative strides. This will require extra work to reverse the loop
7370 // predicate, which may be expensive.
7373 *TFI->LVL->getDominatorTree()))
7374 Required |= TailFoldingOpts::Reverse;
7375 if (Required == TailFoldingOpts::Disabled)
7376 Required |= TailFoldingOpts::Simple;
7377
7378 if (!TailFoldingOptionLoc.satisfies(ST->getSVETailFoldingDefaultOpts(),
7379 Required))
7380 return false;
7381
7382 // Don't tail-fold for tight loops where we would be better off interleaving
7383 // with an unpredicated loop.
7384 unsigned NumInsns = 0;
7385 for (BasicBlock *BB : TFI->LVL->getLoop()->blocks()) {
7386 NumInsns += BB->size();
7387 }
7388
7389 // We expect 4 of these to be a IV PHI, IV add, IV compare and branch.
7390 return NumInsns >= SVETailFoldInsnThreshold;
7391}
7392
7395 StackOffset BaseOffset, bool HasBaseReg,
7396 int64_t Scale, unsigned AddrSpace) const {
7397 // Scaling factors are not free at all.
7398 // Operands | Rt Latency
7399 // -------------------------------------------
7400 // Rt, [Xn, Xm] | 4
7401 // -------------------------------------------
7402 // Rt, [Xn, Xm, lsl #imm] | Rn: 4 Rm: 5
7403 // Rt, [Xn, Wm, <extend> #imm] |
7405 AM.BaseGV = BaseGV;
7406 AM.BaseOffs = BaseOffset.getFixed();
7407 AM.HasBaseReg = HasBaseReg;
7408 AM.Scale = Scale;
7409 AM.ScalableOffset = BaseOffset.getScalable();
7410 if (getTLI()->isLegalAddressingMode(DL, AM, Ty, AddrSpace))
7411 // Scale represents reg2 * scale, thus account for 1 if
7412 // it is not equal to 0 or 1.
7413 return AM.Scale != 0 && AM.Scale != 1;
7415}
7416
7418 const Instruction *I) const {
7420 // For the binary operators (e.g. or) we need to be more careful than
7421 // selects, here we only transform them if they are already at a natural
7422 // break point in the code - the end of a block with an unconditional
7423 // terminator.
7424 if (I->getOpcode() == Instruction::Or &&
7425 isa<UncondBrInst>(I->getNextNode()))
7426 return true;
7427
7428 if (I->getOpcode() == Instruction::Add ||
7429 I->getOpcode() == Instruction::Sub)
7430 return true;
7431 }
7433}
7434
7437 const TargetTransformInfo::LSRCost &C2) const {
7438 // AArch64 specific here is adding the number of instructions to the
7439 // comparison (though not as the first consideration, as some targets do)
7440 // along with changing the priority of the base additions.
7441 // TODO: Maybe a more nuanced tradeoff between instruction count
7442 // and number of registers? To be investigated at a later date.
7443 if (EnableLSRCostOpt)
7444 return std::tie(C1.NumRegs, C1.Insns, C1.NumBaseAdds, C1.AddRecCost,
7445 C1.NumIVMuls, C1.ScaleCost, C1.ImmCost, C1.SetupCost) <
7446 std::tie(C2.NumRegs, C2.Insns, C2.NumBaseAdds, C2.AddRecCost,
7447 C2.NumIVMuls, C2.ScaleCost, C2.ImmCost, C2.SetupCost);
7448
7450}
7451
7452static bool isSplatShuffle(Value *V) {
7453 if (auto *Shuf = dyn_cast<ShuffleVectorInst>(V))
7454 return all_equal(Shuf->getShuffleMask());
7455 return false;
7456}
7457
7458/// Check if both Op1 and Op2 are shufflevector extracts of either the lower
7459/// or upper half of the vector elements.
7460static bool areExtractShuffleVectors(Value *Op1, Value *Op2,
7461 bool AllowSplat = false) {
7462 // Scalable types can't be extract shuffle vectors.
7463 if (Op1->getType()->isScalableTy() || Op2->getType()->isScalableTy())
7464 return false;
7465
7466 auto areTypesHalfed = [](Value *FullV, Value *HalfV) {
7467 auto *FullTy = FullV->getType();
7468 auto *HalfTy = HalfV->getType();
7469 return FullTy->getPrimitiveSizeInBits().getFixedValue() ==
7470 2 * HalfTy->getPrimitiveSizeInBits().getFixedValue();
7471 };
7472
7473 auto extractHalf = [](Value *FullV, Value *HalfV) {
7474 auto *FullVT = cast<FixedVectorType>(FullV->getType());
7475 auto *HalfVT = cast<FixedVectorType>(HalfV->getType());
7476 return FullVT->getNumElements() == 2 * HalfVT->getNumElements();
7477 };
7478
7479 ArrayRef<int> M1, M2;
7480 Value *S1Op1 = nullptr, *S2Op1 = nullptr;
7481 if (!match(Op1, m_Shuffle(m_Value(S1Op1), m_Undef(), m_Mask(M1))) ||
7482 !match(Op2, m_Shuffle(m_Value(S2Op1), m_Undef(), m_Mask(M2))))
7483 return false;
7484
7485 // If we allow splats, set S1Op1/S2Op1 to nullptr for the relevant arg so that
7486 // it is not checked as an extract below.
7487 if (AllowSplat && isSplatShuffle(Op1))
7488 S1Op1 = nullptr;
7489 if (AllowSplat && isSplatShuffle(Op2))
7490 S2Op1 = nullptr;
7491
7492 // Check that the operands are half as wide as the result and we extract
7493 // half of the elements of the input vectors.
7494 if ((S1Op1 && (!areTypesHalfed(S1Op1, Op1) || !extractHalf(S1Op1, Op1))) ||
7495 (S2Op1 && (!areTypesHalfed(S2Op1, Op2) || !extractHalf(S2Op1, Op2))))
7496 return false;
7497
7498 // Check the mask extracts either the lower or upper half of vector
7499 // elements.
7500 int M1Start = 0;
7501 int M2Start = 0;
7502 int NumElements = cast<FixedVectorType>(Op1->getType())->getNumElements() * 2;
7503 if ((S1Op1 &&
7504 !ShuffleVectorInst::isExtractSubvectorMask(M1, NumElements, M1Start)) ||
7505 (S2Op1 &&
7506 !ShuffleVectorInst::isExtractSubvectorMask(M2, NumElements, M2Start)))
7507 return false;
7508
7509 if ((M1Start != 0 && M1Start != (NumElements / 2)) ||
7510 (M2Start != 0 && M2Start != (NumElements / 2)))
7511 return false;
7512 if (S1Op1 && S2Op1 && M1Start != M2Start)
7513 return false;
7514
7515 return true;
7516}
7517
7518/// Check if Ext1 and Ext2 are extends of the same type, doubling the bitwidth
7519/// of the vector elements.
7520static bool areExtractExts(Value *Ext1, Value *Ext2) {
7521 auto areExtDoubled = [](Instruction *Ext) {
7522 return Ext->getType()->getScalarSizeInBits() ==
7523 2 * Ext->getOperand(0)->getType()->getScalarSizeInBits();
7524 };
7525
7526 if (!match(Ext1, m_ZExtOrSExt(m_Value())) ||
7527 !match(Ext2, m_ZExtOrSExt(m_Value())) ||
7528 !areExtDoubled(cast<Instruction>(Ext1)) ||
7529 !areExtDoubled(cast<Instruction>(Ext2)))
7530 return false;
7531
7532 return true;
7533}
7534
7535/// Check if Op could be used with vmull_high_p64 intrinsic.
7537 Value *VectorOperand = nullptr;
7538 ConstantInt *ElementIndex = nullptr;
7539 return match(Op, m_ExtractElt(m_Value(VectorOperand),
7540 m_ConstantInt(ElementIndex))) &&
7541 ElementIndex->getValue() == 1 &&
7542 isa<FixedVectorType>(VectorOperand->getType()) &&
7543 cast<FixedVectorType>(VectorOperand->getType())->getNumElements() == 2;
7544}
7545
7546/// Check if Op1 and Op2 could be used with vmull_high_p64 intrinsic.
7547static bool areOperandsOfVmullHighP64(Value *Op1, Value *Op2) {
7549}
7550
7552 // Restrict ourselves to the form CodeGenPrepare typically constructs.
7553 auto *GEP = dyn_cast<GetElementPtrInst>(Ptrs);
7554 if (!GEP || GEP->getNumOperands() != 2)
7555 return false;
7556
7557 Value *Base = GEP->getOperand(0);
7558 Value *Offsets = GEP->getOperand(1);
7559
7560 // We only care about scalar_base+vector_offsets.
7561 if (Base->getType()->isVectorTy() || !Offsets->getType()->isVectorTy())
7562 return false;
7563
7564 // Sink extends that would allow us to use 32-bit offset vectors.
7565 if (isa<SExtInst>(Offsets) || isa<ZExtInst>(Offsets)) {
7566 auto *OffsetsInst = cast<Instruction>(Offsets);
7567 if (OffsetsInst->getType()->getScalarSizeInBits() > 32 &&
7568 OffsetsInst->getOperand(0)->getType()->getScalarSizeInBits() <= 32)
7569 Ops.push_back(&GEP->getOperandUse(1));
7570 }
7571
7572 // Sink the GEP.
7573 return true;
7574}
7575
7576/// We want to sink following cases:
7577/// (add|sub|gep) A, ((mul|shl) vscale, imm); (add|sub|gep) A, vscale;
7578/// (add|sub|gep) A, ((mul|shl) zext(vscale), imm);
7580 if (match(Op, m_VScale()))
7581 return true;
7582 if (match(Op, m_Shl(m_VScale(), m_ConstantInt())) ||
7584 Ops.push_back(&cast<Instruction>(Op)->getOperandUse(0));
7585 return true;
7586 }
7587 if (match(Op, m_Shl(m_ZExt(m_VScale()), m_ConstantInt())) ||
7589 Value *ZExtOp = cast<Instruction>(Op)->getOperand(0);
7590 Ops.push_back(&cast<Instruction>(ZExtOp)->getOperandUse(0));
7591 Ops.push_back(&cast<Instruction>(Op)->getOperandUse(0));
7592 return true;
7593 }
7594 return false;
7595}
7596
7597static bool isFNeg(Value *Op) { return match(Op, m_FNeg(m_Value())); }
7598
7599/// Check if sinking \p I's operands to I's basic block is profitable, because
7600/// the operands can be folded into a target instruction, e.g.
7601/// shufflevectors extracts and/or sext/zext can be folded into (u,s)subl(2).
7605 switch (II->getIntrinsicID()) {
7606 case Intrinsic::aarch64_neon_smull:
7607 case Intrinsic::aarch64_neon_umull:
7608 if (areExtractShuffleVectors(II->getOperand(0), II->getOperand(1),
7609 /*AllowSplat=*/true)) {
7610 Ops.push_back(&II->getOperandUse(0));
7611 Ops.push_back(&II->getOperandUse(1));
7612 return true;
7613 }
7614 [[fallthrough]];
7615
7616 case Intrinsic::fma:
7617 case Intrinsic::fmuladd:
7618 if (isa<VectorType>(I->getType()) &&
7619 cast<VectorType>(I->getType())->getElementType()->isHalfTy() &&
7620 !ST->hasFullFP16())
7621 return false;
7622
7623 if (isFNeg(II->getOperand(0)))
7624 Ops.push_back(&II->getOperandUse(0));
7625 if (isFNeg(II->getOperand(1)))
7626 Ops.push_back(&II->getOperandUse(1));
7627
7628 [[fallthrough]];
7629 case Intrinsic::aarch64_neon_sqdmull:
7630 case Intrinsic::aarch64_neon_sqdmulh:
7631 case Intrinsic::aarch64_neon_sqrdmulh:
7632 // Sink splats for index lane variants
7633 if (isSplatShuffle(II->getOperand(0)))
7634 Ops.push_back(&II->getOperandUse(0));
7635 if (isSplatShuffle(II->getOperand(1)))
7636 Ops.push_back(&II->getOperandUse(1));
7637 return !Ops.empty();
7638 case Intrinsic::aarch64_neon_fmlal:
7639 case Intrinsic::aarch64_neon_fmlal2:
7640 case Intrinsic::aarch64_neon_fmlsl:
7641 case Intrinsic::aarch64_neon_fmlsl2:
7642 // Sink splats for index lane variants
7643 if (isSplatShuffle(II->getOperand(1)))
7644 Ops.push_back(&II->getOperandUse(1));
7645 if (isSplatShuffle(II->getOperand(2)))
7646 Ops.push_back(&II->getOperandUse(2));
7647 return !Ops.empty();
7648 case Intrinsic::aarch64_sve_ptest_first:
7649 case Intrinsic::aarch64_sve_ptest_last:
7650 if (auto *IIOp = dyn_cast<IntrinsicInst>(II->getOperand(0)))
7651 if (IIOp->getIntrinsicID() == Intrinsic::aarch64_sve_ptrue)
7652 Ops.push_back(&II->getOperandUse(0));
7653 return !Ops.empty();
7654 case Intrinsic::aarch64_sme_write_horiz:
7655 case Intrinsic::aarch64_sme_write_vert:
7656 case Intrinsic::aarch64_sme_writeq_horiz:
7657 case Intrinsic::aarch64_sme_writeq_vert: {
7658 auto *Idx = dyn_cast<Instruction>(II->getOperand(1));
7659 if (!Idx || Idx->getOpcode() != Instruction::Add)
7660 return false;
7661 Ops.push_back(&II->getOperandUse(1));
7662 return true;
7663 }
7664 case Intrinsic::aarch64_sme_read_horiz:
7665 case Intrinsic::aarch64_sme_read_vert:
7666 case Intrinsic::aarch64_sme_readq_horiz:
7667 case Intrinsic::aarch64_sme_readq_vert:
7668 case Intrinsic::aarch64_sme_ld1b_vert:
7669 case Intrinsic::aarch64_sme_ld1h_vert:
7670 case Intrinsic::aarch64_sme_ld1w_vert:
7671 case Intrinsic::aarch64_sme_ld1d_vert:
7672 case Intrinsic::aarch64_sme_ld1q_vert:
7673 case Intrinsic::aarch64_sme_st1b_vert:
7674 case Intrinsic::aarch64_sme_st1h_vert:
7675 case Intrinsic::aarch64_sme_st1w_vert:
7676 case Intrinsic::aarch64_sme_st1d_vert:
7677 case Intrinsic::aarch64_sme_st1q_vert:
7678 case Intrinsic::aarch64_sme_ld1b_horiz:
7679 case Intrinsic::aarch64_sme_ld1h_horiz:
7680 case Intrinsic::aarch64_sme_ld1w_horiz:
7681 case Intrinsic::aarch64_sme_ld1d_horiz:
7682 case Intrinsic::aarch64_sme_ld1q_horiz:
7683 case Intrinsic::aarch64_sme_st1b_horiz:
7684 case Intrinsic::aarch64_sme_st1h_horiz:
7685 case Intrinsic::aarch64_sme_st1w_horiz:
7686 case Intrinsic::aarch64_sme_st1d_horiz:
7687 case Intrinsic::aarch64_sme_st1q_horiz: {
7688 auto *Idx = dyn_cast<Instruction>(II->getOperand(3));
7689 if (!Idx || Idx->getOpcode() != Instruction::Add)
7690 return false;
7691 Ops.push_back(&II->getOperandUse(3));
7692 return true;
7693 }
7694 case Intrinsic::aarch64_neon_pmull:
7695 if (!areExtractShuffleVectors(II->getOperand(0), II->getOperand(1)))
7696 return false;
7697 Ops.push_back(&II->getOperandUse(0));
7698 Ops.push_back(&II->getOperandUse(1));
7699 return true;
7700 case Intrinsic::aarch64_neon_pmull64:
7701 if (!areOperandsOfVmullHighP64(II->getArgOperand(0),
7702 II->getArgOperand(1)))
7703 return false;
7704 Ops.push_back(&II->getArgOperandUse(0));
7705 Ops.push_back(&II->getArgOperandUse(1));
7706 return true;
7707 case Intrinsic::masked_gather:
7708 if (!shouldSinkVectorOfPtrs(II->getArgOperand(0), Ops))
7709 return false;
7710 Ops.push_back(&II->getArgOperandUse(0));
7711 return true;
7712 case Intrinsic::masked_scatter:
7713 if (!shouldSinkVectorOfPtrs(II->getArgOperand(1), Ops))
7714 return false;
7715 Ops.push_back(&II->getArgOperandUse(1));
7716 return true;
7717 default:
7718 return false;
7719 }
7720 }
7721
7722 auto ShouldSinkCondition = [](Value *Cond,
7723 SmallVectorImpl<Use *> &Ops) -> bool {
7725 return false;
7727 if (II->getIntrinsicID() != Intrinsic::vector_reduce_or ||
7728 !isa<ScalableVectorType>(II->getOperand(0)->getType()))
7729 return false;
7730 if (isa<CmpInst>(II->getOperand(0)))
7731 Ops.push_back(&II->getOperandUse(0));
7732 return true;
7733 };
7734
7735 switch (I->getOpcode()) {
7736 case Instruction::GetElementPtr:
7737 case Instruction::Add:
7738 case Instruction::Sub:
7739 // Sink vscales closer to uses for better isel
7740 for (unsigned Op = 0; Op < I->getNumOperands(); ++Op) {
7741 if (shouldSinkVScale(I->getOperand(Op), Ops)) {
7742 Ops.push_back(&I->getOperandUse(Op));
7743 return true;
7744 }
7745 }
7746 break;
7747 case Instruction::Select: {
7748 if (!ShouldSinkCondition(I->getOperand(0), Ops))
7749 return false;
7750
7751 Ops.push_back(&I->getOperandUse(0));
7752 return true;
7753 }
7754 case Instruction::UncondBr:
7755 return false;
7756 case Instruction::CondBr: {
7757 if (!ShouldSinkCondition(cast<CondBrInst>(I)->getCondition(), Ops))
7758 return false;
7759
7760 Ops.push_back(&I->getOperandUse(0));
7761 return true;
7762 }
7763 case Instruction::FMul:
7764 // fmul with contract flag can be combined with fadd into fma.
7765 // Sinking fneg into this block enables fmls pattern.
7766 if (cast<FPMathOperator>(I)->hasAllowContract()) {
7767 if (isFNeg(I->getOperand(0)))
7768 Ops.push_back(&I->getOperandUse(0));
7769 if (isFNeg(I->getOperand(1)))
7770 Ops.push_back(&I->getOperandUse(1));
7771 }
7772 break;
7773
7774 // Type | BIC | ORN | EON
7775 // ----------------+-----------+-----------+-----------
7776 // scalar | Base | Base | Base
7777 // scalar w/shift | - | - | -
7778 // fixed vector | NEON/Base | NEON/Base | BSL2N/Base
7779 // scalable vector | SVE | - | BSL2N
7780 case Instruction::Xor:
7781 // EON only for scalars (possibly expanded fixed vectors)
7782 // and vectors using the SVE2/SME BSL2N instruction.
7783 if (I->getType()->isVectorTy() && ST->isNeonAvailable()) {
7784 bool HasBSL2N =
7785 ST->isSVEorStreamingSVEAvailable() && (ST->hasSVE2() || ST->hasSME());
7786 if (!HasBSL2N)
7787 break;
7788 }
7789 [[fallthrough]];
7790 case Instruction::And:
7791 case Instruction::Or:
7792 // Even though we could use the SVE2/SME BSL2N instruction,
7793 // it might pessimize with an extra MOV depending on register allocation.
7794 if (I->getOpcode() == Instruction::Or &&
7795 isa<ScalableVectorType>(I->getType()))
7796 break;
7797 // Shift can be fold into scalar AND/ORR/EOR,
7798 // but not the non-negated operand of BIC/ORN/EON.
7799 if (!(I->getType()->isVectorTy() && ST->hasNEON()) &&
7801 break;
7802 for (auto &Op : I->operands()) {
7803 // (and/or/xor X, (not Y)) -> (bic/orn/eon X, Y)
7804 if (match(Op.get(), m_Not(m_Value()))) {
7805 Ops.push_back(&Op);
7806 return true;
7807 }
7808 // (and/or/xor X, (splat (not Y))) -> (bic/orn/eon X, (splat Y))
7809 if (match(Op.get(),
7811 m_Value(), m_ZeroMask()))) {
7812 Use &InsertElt = cast<Instruction>(Op)->getOperandUse(0);
7813 Use &Not = cast<Instruction>(InsertElt)->getOperandUse(1);
7814 Ops.push_back(&Not);
7815 Ops.push_back(&InsertElt);
7816 Ops.push_back(&Op);
7817 return true;
7818 }
7819 }
7820 break;
7821 default:
7822 break;
7823 }
7824
7825 if (!I->getType()->isVectorTy())
7826 return !Ops.empty();
7827
7828 switch (I->getOpcode()) {
7829 case Instruction::Sub:
7830 case Instruction::Add: {
7831 if (!areExtractExts(I->getOperand(0), I->getOperand(1)))
7832 return false;
7833
7834 // If the exts' operands extract either the lower or upper elements, we
7835 // can sink them too.
7836 auto Ext1 = cast<Instruction>(I->getOperand(0));
7837 auto Ext2 = cast<Instruction>(I->getOperand(1));
7838 if (areExtractShuffleVectors(Ext1->getOperand(0), Ext2->getOperand(0))) {
7839 Ops.push_back(&Ext1->getOperandUse(0));
7840 Ops.push_back(&Ext2->getOperandUse(0));
7841 }
7842
7843 Ops.push_back(&I->getOperandUse(0));
7844 Ops.push_back(&I->getOperandUse(1));
7845
7846 return true;
7847 }
7848 case Instruction::Or: {
7849 // Pattern: Or(And(MaskValue, A), And(Not(MaskValue), B)) ->
7850 // bitselect(MaskValue, A, B) where Not(MaskValue) = Xor(MaskValue, -1)
7851 if (ST->hasNEON()) {
7852 Instruction *OtherAnd, *IA, *IB;
7853 Value *MaskValue;
7854 // MainAnd refers to And instruction that has 'Not' as one of its operands
7855 if (match(I, m_c_Or(m_OneUse(m_Instruction(OtherAnd)),
7856 m_OneUse(m_c_And(m_OneUse(m_Not(m_Value(MaskValue))),
7857 m_Instruction(IA)))))) {
7858 if (match(OtherAnd,
7859 m_c_And(m_Specific(MaskValue), m_Instruction(IB)))) {
7860 Instruction *MainAnd = I->getOperand(0) == OtherAnd
7861 ? cast<Instruction>(I->getOperand(1))
7862 : cast<Instruction>(I->getOperand(0));
7863
7864 // Both Ands should be in same basic block as Or
7865 if (I->getParent() != MainAnd->getParent() ||
7866 I->getParent() != OtherAnd->getParent())
7867 return false;
7868
7869 // Non-mask operands of both Ands should also be in same basic block
7870 if (I->getParent() != IA->getParent() ||
7871 I->getParent() != IB->getParent())
7872 return false;
7873
7874 Ops.push_back(
7875 &MainAnd->getOperandUse(MainAnd->getOperand(0) == IA ? 1 : 0));
7876 Ops.push_back(&I->getOperandUse(0));
7877 Ops.push_back(&I->getOperandUse(1));
7878
7879 return true;
7880 }
7881 }
7882 }
7883
7884 return false;
7885 }
7886 case Instruction::Mul: {
7887 auto ShouldSinkSplatForIndexedVariant = [](Value *V) {
7888 auto *Ty = cast<VectorType>(V->getType());
7889 // For SVE the lane-indexing is within 128-bits, so we can't fold splats.
7890 if (Ty->isScalableTy())
7891 return false;
7892
7893 // Indexed variants of Mul exist for i16 and i32 element types only.
7894 return Ty->getScalarSizeInBits() == 16 || Ty->getScalarSizeInBits() == 32;
7895 };
7896
7897 int NumZExts = 0, NumSExts = 0;
7898 for (auto &Op : I->operands()) {
7899 // Make sure we are not already sinking this operand
7900 if (any_of(Ops, [&](Use *U) { return U->get() == Op; }))
7901 continue;
7902
7903 if (match(&Op, m_ZExtOrSExt(m_Value()))) {
7904 auto *Ext = cast<Instruction>(Op);
7905 auto *ExtOp = Ext->getOperand(0);
7906 if (isSplatShuffle(ExtOp) && ShouldSinkSplatForIndexedVariant(ExtOp))
7907 Ops.push_back(&Ext->getOperandUse(0));
7908 Ops.push_back(&Op);
7909
7910 if (isa<SExtInst>(Ext)) {
7911 NumSExts++;
7912 } else {
7913 NumZExts++;
7914 // A zext(a) is also a sext(zext(a)), if we take more than 2 steps.
7915 if (Ext->getOperand(0)->getType()->getScalarSizeInBits() * 2 <
7916 I->getType()->getScalarSizeInBits())
7917 NumSExts++;
7918 }
7919
7920 continue;
7921 }
7922
7924 if (!Shuffle)
7925 continue;
7926
7927 // If the Shuffle is a splat and the operand is a zext/sext, sinking the
7928 // operand and the s/zext can help create indexed s/umull. This is
7929 // especially useful to prevent i64 mul being scalarized.
7930 if (isSplatShuffle(Shuffle) &&
7931 match(Shuffle->getOperand(0), m_ZExtOrSExt(m_Value()))) {
7932 Ops.push_back(&Shuffle->getOperandUse(0));
7933 Ops.push_back(&Op);
7934 if (match(Shuffle->getOperand(0), m_SExt(m_Value())))
7935 NumSExts++;
7936 else
7937 NumZExts++;
7938 continue;
7939 }
7940
7941 Value *ShuffleOperand = Shuffle->getOperand(0);
7942 InsertElementInst *Insert = dyn_cast<InsertElementInst>(ShuffleOperand);
7943 if (!Insert)
7944 continue;
7945
7946 Instruction *OperandInstr = dyn_cast<Instruction>(Insert->getOperand(1));
7947 if (!OperandInstr)
7948 continue;
7949
7950 ConstantInt *ElementConstant =
7951 dyn_cast<ConstantInt>(Insert->getOperand(2));
7952 // Check that the insertelement is inserting into element 0
7953 if (!ElementConstant || !ElementConstant->isZero())
7954 continue;
7955
7956 unsigned Opcode = OperandInstr->getOpcode();
7957 if (Opcode == Instruction::SExt)
7958 NumSExts++;
7959 else if (Opcode == Instruction::ZExt)
7960 NumZExts++;
7961 else {
7962 // If we find that the top bits are known 0, then we can sink and allow
7963 // the backend to generate a umull.
7964 unsigned Bitwidth = I->getType()->getScalarSizeInBits();
7965 APInt UpperMask = APInt::getHighBitsSet(Bitwidth, Bitwidth / 2);
7966 if (!MaskedValueIsZero(OperandInstr, UpperMask, DL))
7967 continue;
7968 NumZExts++;
7969 }
7970
7971 // And(Load) is excluded to prevent CGP getting stuck in a loop of sinking
7972 // the And, just to hoist it again back to the load.
7973 if (!match(OperandInstr, m_And(m_Load(m_Value()), m_Value())))
7974 Ops.push_back(&Insert->getOperandUse(1));
7975 Ops.push_back(&Shuffle->getOperandUse(0));
7976 Ops.push_back(&Op);
7977 }
7978
7979 // It is profitable to sink if we found two of the same type of extends.
7980 if (!Ops.empty() && (NumSExts == 2 || NumZExts == 2))
7981 return true;
7982
7983 // Otherwise, see if we should sink splats for indexed variants.
7984 if (!ShouldSinkSplatForIndexedVariant(I))
7985 return false;
7986
7987 Ops.clear();
7988 if (isSplatShuffle(I->getOperand(0)))
7989 Ops.push_back(&I->getOperandUse(0));
7990 if (isSplatShuffle(I->getOperand(1)))
7991 Ops.push_back(&I->getOperandUse(1));
7992
7993 return !Ops.empty();
7994 }
7995 case Instruction::FMul: {
7996 // For SVE the lane-indexing is within 128-bits, so we can't fold splats.
7997 if (I->getType()->isScalableTy())
7998 return !Ops.empty();
7999
8000 if (cast<VectorType>(I->getType())->getElementType()->isHalfTy() &&
8001 !ST->hasFullFP16())
8002 return !Ops.empty();
8003
8004 // Sink splats for index lane variants
8005 if (isSplatShuffle(I->getOperand(0)))
8006 Ops.push_back(&I->getOperandUse(0));
8007 if (isSplatShuffle(I->getOperand(1)))
8008 Ops.push_back(&I->getOperandUse(1));
8009 return !Ops.empty();
8010 }
8011 default:
8012 return false;
8013 }
8014 return false;
8015}
static bool isAllActivePredicate(const SelectionDAG &DAG, SDValue N)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static std::optional< Instruction * > instCombinePTrue(InstCombiner &IC, IntrinsicInst &II)
TailFoldingOption TailFoldingOptionLoc
static std::optional< Instruction * > instCombineSVEVectorFAdd(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEVectorFuseMulAddSub(InstCombiner &IC, IntrinsicInst &II, bool MergeIntoAddendOp)
static std::optional< Instruction * > instCombineZExtSVECmpNE(InstCombiner &IC, IntrinsicInst &II)
static void getFalkorUnrollingPreferences(Loop *L, ScalarEvolution &SE, TargetTransformInfo::UnrollingPreferences &UP)
bool SimplifyValuePattern(SmallVector< Value * > &Vec, bool AllowPoison)
static std::optional< Instruction * > instCombineSVESel(InstCombiner &IC, IntrinsicInst &II)
static bool hasPossibleIncompatibleOps(const Function *F, const AArch64TargetLowering &TLI)
Returns true if the function has explicit operations that can only be lowered using incompatible inst...
static bool shouldSinkVScale(Value *Op, SmallVectorImpl< Use * > &Ops)
We want to sink following cases: (add|sub|gep) A, ((mul|shl) vscale, imm); (add|sub|gep) A,...
static InstructionCost getHistogramCost(const AArch64Subtarget *ST, const IntrinsicCostAttributes &ICA)
static std::optional< Instruction * > tryCombineFromSVBoolBinOp(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEUnpack(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< unsigned > SVETailFoldInsnThreshold("sve-tail-folding-insn-threshold", cl::init(15), cl::Hidden)
static cl::opt< bool > EnableFixedwidthAutovecInStreamingMode("enable-fixedwidth-autovec-in-streaming-mode", cl::init(false), cl::Hidden)
static void getAppleRuntimeUnrollPreferences(Loop *L, ScalarEvolution &SE, TargetTransformInfo::UnrollingPreferences &UP, const AArch64TTIImpl &TTI)
For Apple CPUs, we want to runtime-unroll loops to make better use if the OOO engine's wide instructi...
static std::optional< Instruction * > instCombineWhilelo(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEVectorFAddU(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEPairwiseAddLong(InstCombiner &IC, IntrinsicInst &II)
static bool areExtractExts(Value *Ext1, Value *Ext2)
Check if Ext1 and Ext2 are extends of the same type, doubling the bitwidth of the vector elements.
static cl::opt< bool > EnableLSRCostOpt("enable-aarch64-lsr-cost-opt", cl::init(true), cl::Hidden)
static std::optional< Instruction * > instCombineSVEUMin(InstCombiner &IC, IntrinsicInst &II)
static bool shouldSinkVectorOfPtrs(Value *Ptrs, SmallVectorImpl< Use * > &Ops)
static bool shouldUnrollMultiExitLoop(Loop *L, ScalarEvolution &SE, const AArch64TTIImpl &TTI)
static std::optional< Instruction * > simplifySVEIntrinsicBinOp(InstCombiner &IC, IntrinsicInst &II, const SVEIntrinsicInfo &IInfo)
static std::optional< Instruction * > instCombineSVEVectorSub(InstCombiner &IC, IntrinsicInst &II)
static bool isLoopSizeWithinBudget(Loop *L, const AArch64TTIImpl &TTI, InstructionCost Budget, unsigned *FinalSize)
static std::optional< Instruction * > instCombineLD1GatherIndex(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEVectorFSub(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > processPhiNode(InstCombiner &IC, IntrinsicInst &II)
The function will remove redundant reinterprets casting in the presence of the control flow.
static std::optional< Instruction * > instCombineSVEInsr(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSMECntsd(InstCombiner &IC, IntrinsicInst &II, const AArch64Subtarget *ST)
static void extractAttrFeatures(const Function &F, const AArch64TTIImpl *TTI, SmallVectorImpl< StringRef > &Features)
static std::optional< Instruction * > instCombineST1ScatterIndex(InstCombiner &IC, IntrinsicInst &II)
static bool isSMEABIRoutineCall(const CallInst &CI, const AArch64TargetLowering &TLI)
static std::optional< Instruction * > instCombineSVESDIV(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEST1(InstCombiner &IC, IntrinsicInst &II, const DataLayout &DL)
static Value * stripInactiveLanes(Value *V, const Value *Pg)
static cl::opt< bool > SVEPreferFixedOverScalableIfEqualCost("sve-prefer-fixed-over-scalable-if-equal", cl::Hidden)
static bool isUnpackedVectorVT(EVT VecVT)
static std::optional< Instruction * > instCombineSVEDupX(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVECmpNE(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineDMB(InstCombiner &IC, IntrinsicInst &II)
static SVEIntrinsicInfo constructSVEIntrinsicInfo(IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEVectorFSubU(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineRDFFR(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineMaxMinNM(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > simplifySVEIntrinsicCompare(InstCombiner &IC, IntrinsicInst &II, const SVEIntrinsicInfo &IInfo)
static cl::opt< unsigned > SVEGatherOverhead("sve-gather-overhead", cl::init(10), cl::Hidden)
static std::optional< Instruction * > instCombineSVECondLast(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEPTest(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEZip(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< int > Aarch64ForceUnrollThreshold("aarch64-force-unroll-threshold", cl::init(0), cl::Hidden, cl::desc("Threshold for forced unrolling of small loops in AArch64"))
static std::optional< Instruction * > instCombineSVEDup(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< unsigned > BaseHistCntCost("aarch64-base-histcnt-cost", cl::init(8), cl::Hidden, cl::desc("The cost of a histcnt instruction"))
static std::optional< Instruction * > instCombineConvertFromSVBool(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< unsigned > CallPenaltyChangeSM("call-penalty-sm-change", cl::init(5), cl::Hidden, cl::desc("Penalty of calling a function that requires a change to PSTATE.SM"))
static std::optional< Instruction * > instCombineSVEUzp1(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVEVectorBinOp(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< bool > EnableScalableAutovecInStreamingMode("enable-scalable-autovec-in-streaming-mode", cl::init(false), cl::Hidden)
static std::optional< Instruction * > instCombineSVETBL(InstCombiner &IC, IntrinsicInst &II)
static bool areOperandsOfVmullHighP64(Value *Op1, Value *Op2)
Check if Op1 and Op2 could be used with vmull_high_p64 intrinsic.
static bool isFNeg(Value *Op)
static Instruction::BinaryOps intrinsicIDToBinOpCode(unsigned Intrinsic)
static bool containsDecreasingPointers(Loop *TheLoop, PredicatedScalarEvolution *PSE, const DominatorTree &DT)
static std::optional< Instruction * > instCombineSVEAnd(InstCombiner &IC, IntrinsicInst &II)
static bool isSplatShuffle(Value *V)
static cl::opt< unsigned > InlineCallPenaltyChangeSM("inline-call-penalty-sm-change", cl::init(10), cl::Hidden, cl::desc("Penalty of inlining a call that requires a change to PSTATE.SM"))
static std::optional< Instruction * > instCombineSVELD1(InstCombiner &IC, IntrinsicInst &II, const DataLayout &DL)
static std::optional< Instruction * > instCombineSVESrshl(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineXorSVECmpCC(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< unsigned > DMBLookaheadThreshold("dmb-lookahead-threshold", cl::init(10), cl::Hidden, cl::desc("The number of instructions to search for a redundant dmb"))
static std::optional< Instruction * > simplifySVEIntrinsic(InstCombiner &IC, IntrinsicInst &II, const SVEIntrinsicInfo &IInfo)
static unsigned getSVEGatherScatterOverhead(unsigned Opcode, const AArch64Subtarget *ST)
static std::optional< Instruction * > instCombineSVEVectorMlaU(InstCombiner &IC, IntrinsicInst &II)
static bool isOperandOfVmullHighP64(Value *Op)
Check if Op could be used with vmull_high_p64 intrinsic.
static std::optional< Instruction * > instCombineInStreamingMode(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVELast(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< unsigned > NeonNonConstStrideOverhead("neon-nonconst-stride-overhead", cl::init(10), cl::Hidden)
static cl::opt< bool > EnableFalkorHWPFUnrollFix("enable-falkor-hwpf-unroll-fix", cl::init(true), cl::Hidden)
static std::optional< Instruction * > instCombineSVEOrr(InstCombiner &IC, IntrinsicInst &II)
static std::optional< Instruction * > instCombineSVECntElts(InstCombiner &IC, IntrinsicInst &II, unsigned NumElts)
static std::optional< Instruction * > instCombineSVEUxt(InstCombiner &IC, IntrinsicInst &II, unsigned NumBits)
static cl::opt< TailFoldingOption, true, cl::parser< std::string > > SVETailFolding("sve-tail-folding", cl::desc("Control the use of vectorisation using tail-folding for SVE where the" " option is specified in the form (Initial)[+(Flag1|Flag2|...)]:" "\ndisabled (Initial) No loop types will vectorize using " "tail-folding" "\ndefault (Initial) Uses the default tail-folding settings for " "the target CPU" "\nall (Initial) All legal loop types will vectorize using " "tail-folding" "\nsimple (Initial) Use tail-folding for simple loops (not " "reductions or recurrences)" "\nreductions Use tail-folding for loops containing reductions" "\nnoreductions Inverse of above" "\nrecurrences Use tail-folding for loops containing fixed order " "recurrences" "\nnorecurrences Inverse of above" "\nreverse Use tail-folding for loops requiring reversed " "predicates" "\nnoreverse Inverse of above"), cl::location(TailFoldingOptionLoc))
static bool areExtractShuffleVectors(Value *Op1, Value *Op2, bool AllowSplat=false)
Check if both Op1 and Op2 are shufflevector extracts of either the lower or upper half of the vector ...
static std::optional< Instruction * > instCombineSVEVectorAdd(InstCombiner &IC, IntrinsicInst &II)
static cl::opt< bool > EnableOrLikeSelectOpt("enable-aarch64-or-like-select", cl::init(true), cl::Hidden)
static cl::opt< unsigned > SVEScatterOverhead("sve-scatter-overhead", cl::init(10), cl::Hidden)
static std::optional< Instruction * > instCombineSVEDupqLane(InstCombiner &IC, IntrinsicInst &II)
This file a TargetTransformInfoImplBase conforming object specific to the AArch64 target machine.
unsigned Imm
unsigned uint64_t
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file provides a helper that implements much of the TTI interface in terms of the target-independ...
static Error reportError(StringRef Message)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
Cost tables and simple lookup functions.
This file defines the DenseMap class.
@ Default
static Value * getCondition(Instruction *I)
Hexagon Common GEP
const HexagonInstrInfo * TII
#define _
This file provides the interface for the instcombine pass implementation.
static constexpr Value * getValue(Ty &ValueOrUse)
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
static LVOptions Options
Definition LVOptions.cpp:25
This file defines the LoopVectorizationLegality class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
static const Function * getCalledFunction(const Value *V)
#define T
AttributeSet CallAttrs
uint64_t IntrinsicInst * II
#define P(N)
const SmallVectorImpl< MachineOperand > & Cond
static uint64_t getBits(uint64_t Val, int Start, int End)
SI Fold Operands
static unsigned getFastMathFlags(const MachineInstr &I, const SPIRVSubtarget &ST)
#define LLVM_DEBUG(...)
Definition Debug.h:119
static unsigned getScalarSizeInBits(Type *Ty)
static SymbolRef::Type getType(const Symbol *Sym)
Definition TapiFile.cpp:39
This file describes how to lower LLVM code to machine code.
This pass exposes codegen information to IR-level passes.
static unsigned getBitWidth(Type *Ty, const DataLayout &DL)
Returns the bitwidth of the given scalar or pointer type.
Value * RHS
Value * LHS
BinaryOperator * Mul
This file implements the C++20 <bit> header.
unsigned getVectorInsertExtractBaseCost() const
bool useSVEForFixedLengthVectors() const
InstructionCost getArithmeticReductionCost(unsigned Opcode, VectorType *Ty, std::optional< FastMathFlags > FMF, TTI::TargetCostKind CostKind) const override
InstructionCost getScalarizationOverhead(VectorType *Ty, const APInt &DemandedElts, bool Insert, bool Extract, TTI::TargetCostKind CostKind, bool ForPoisonSrc=true, ArrayRef< Value * > VL={}, TTI::VectorInstrContext VIC=TTI::VectorInstrContext::None) const override
InstructionCost getArithmeticInstrCost(unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info={TTI::OK_AnyValue, TTI::OP_None}, TTI::OperandValueInfo Op2Info={TTI::OK_AnyValue, TTI::OP_None}, ArrayRef< const Value * > Args={}, const Instruction *CxtI=nullptr) const override
InstructionCost getCostOfKeepingLiveOverCall(ArrayRef< Type * > Tys) const override
InstructionCost getMaskedMemoryOpCost(const MemIntrinsicCostAttributes &MICA, TTI::TargetCostKind CostKind) const
InstructionCost getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy, TTI::TargetCostKind CostKind, ArrayRef< int > Mask, int Index, VectorType *SubTp, ArrayRef< const Value * > Args={}, const Instruction *CxtI=nullptr) const override
InstructionCost getGatherScatterOpCost(const MemIntrinsicCostAttributes &MICA, TTI::TargetCostKind CostKind) const
bool isLegalBroadcastLoad(Type *ElementTy, ElementCount NumElements) const override
InstructionCost getAddressComputationCost(Type *PtrTy, ScalarEvolution *SE, const SCEV *Ptr, TTI::TargetCostKind CostKind) const override
bool isExtPartOfAvgExpr(const Instruction *ExtUser, Type *Dst, Type *Src) const
InstructionCost getIntImmCost(int64_t Val) const
Calculate the cost of materializing a 64-bit value.
InstructionCost getIndexedVectorInstrCostFromEnd(unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index) const override
std::optional< InstructionCost > getFP16BF16PromoteCost(Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info, TTI::OperandValueInfo Op2Info, bool IncludeTrunc, bool CanUseSVE, std::function< InstructionCost(Type *)> InstCost) const
FP16 and BF16 operations are lowered to fptrunc(op(fpext, fpext) if the architecture features are not...
bool prefersVectorizedAddressing() const override
bool preferFixedOverScalableIfEqualCost() const override
InstructionCost getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, TTI::TargetCostKind CostKind) const override
InstructionCost getMulAccReductionCost(bool IsUnsigned, unsigned RedOpcode, Type *ResTy, VectorType *Ty, TTI::TargetCostKind CostKind=TTI::TCK_RecipThroughput) const override
InstructionCost getVectorInstrCost(unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index, const Value *Op0, const Value *Op1, TTI::VectorInstrContext VIC=TTI::VectorInstrContext::None) const override
InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx, const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind, Instruction *Inst=nullptr) const override
bool isElementTypeLegalForScalableVector(Type *Ty) const override
void getPeelingPreferences(Loop *L, ScalarEvolution &SE, TTI::PeelingPreferences &PP) const override
InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, TTI::PartialReductionExtendKind OpAExtend, TTI::PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const override
InstructionCost getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, TTI::CastContextHint CCH, TTI::TargetCostKind CostKind, const Instruction *I=nullptr) const override
void getUnrollingPreferences(Loop *L, ScalarEvolution &SE, TTI::UnrollingPreferences &UP, OptimizationRemarkEmitter *ORE) const override
bool getTgtMemIntrinsic(IntrinsicInst *Inst, MemIntrinsicInfo &Info) const override
bool preferTailFoldingOverEpilogue(TailFoldingInfo *TFI) const override
InstructionCost getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF, TTI::TargetCostKind CostKind) const override
InstructionCost getMemoryOpCost(unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind, TTI::OperandValueInfo OpInfo={TTI::OK_AnyValue, TTI::OP_None}, const Instruction *I=nullptr) const override
APInt getPriorityMask(const Function &F) const override
bool shouldMaximizeVectorBandwidth(TargetTransformInfo::RegisterKind K) const override
bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1, const TargetTransformInfo::LSRCost &C2) const override
InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind, const Instruction *I=nullptr) const override
bool isProfitableToSinkOperands(Instruction *I, SmallVectorImpl< Use * > &Ops) const override
Check if sinking I's operands to I's basic block is profitable, because the operands can be folded in...
std::optional< Value * > simplifyDemandedVectorEltsIntrinsic(InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts, APInt &UndefElts2, APInt &UndefElts3, std::function< void(Instruction *, unsigned, APInt, APInt &)> SimplifyAndSetOp) const override
bool useNeonVector(const Type *Ty) const
std::optional< Instruction * > instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override
InstructionCost getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info={TTI::OK_AnyValue, TTI::OP_None}, TTI::OperandValueInfo Op2Info={TTI::OK_AnyValue, TTI::OP_None}, const Instruction *I=nullptr) const override
InstructionCost getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy, VectorType *ValTy, std::optional< FastMathFlags > FMF, TTI::TargetCostKind CostKind) const override
bool isLegalMaskedExpandLoad(Type *DataTy, Align Alignment) const override
TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth) const override
InstructionCost getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy, unsigned Index, TTI::TargetCostKind CostKind) const override
unsigned getInlineCallPenalty(const Function *F, const CallBase &Call, unsigned DefaultCallPenalty) const override
bool areInlineCompatible(const Function *Caller, const Function *Callee) const override
unsigned getMaxNumElements(ElementCount VF) const
Try to return an estimate cost factor that can be used as a multiplier when scalarizing an operation ...
bool shouldTreatInstructionLikeSelect(const Instruction *I) const override
bool isMultiversionedFunction(const Function &F) const override
TypeSize getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override
bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc, ElementCount VF) const override
TTI::MemCmpExpansionOptions enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const override
InstructionCost getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind) const override
bool isLegalMaskedGatherScatter(Type *DataType) const
InstructionCost getBranchMispredictPenalty() const override
bool shouldConsiderAddressTypePromotion(const Instruction &I, bool &AllowPromotionWithoutCommonHeader) const override
See if I should be considered for address type promotion.
APInt getFeatureMask(const Function &F) const override
InstructionCost getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef< unsigned > Indices, Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind, bool UseMaskForCond=false, bool UseMaskForGaps=false) const override
bool areTypesABICompatible(const Function *Caller, const Function *Callee, ArrayRef< Type * > Types) const override
bool enableScalableVectorization() const override
InstructionCost getMemIntrinsicInstrCost(const MemIntrinsicCostAttributes &MICA, TTI::TargetCostKind CostKind) const override
Value * getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst, Type *ExpectedType, bool CanCreate=true) const override
bool hasKnownLowerThroughputFromSchedulingModel(unsigned Opcode1, unsigned Opcode2) const
Check whether Opcode1 has less throughput according to the scheduling model than Opcode2.
unsigned getEpilogueVectorizationMinVF() const override
InstructionCost getSpliceCost(VectorType *Tp, int Index, TTI::TargetCostKind CostKind) const
InstructionCost getArithmeticReductionCostSVE(unsigned Opcode, VectorType *ValTy, TTI::TargetCostKind CostKind) const
InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV, StackOffset BaseOffset, bool HasBaseReg, int64_t Scale, unsigned AddrSpace) const override
Return the cost of the scaling factor used in the addressing mode represented by AM for this target,...
bool isLegalMaskedCompressStore(Type *DataType, Align Alignment) const override
unsigned getMaxInterleaveFactor(ElementCount VF, bool HasUnorderedReductions) const override
Class for arbitrary precision integers.
Definition APInt.h:78
bool isNegatedPowerOf2() const
Check if this APInt's negated value is a power of two greater than zero.
Definition APInt.h:445
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
unsigned popcount() const
Count the number of bits set.
Definition APInt.h:1690
void negate()
Negate this APInt in place.
Definition APInt.h:1488
LLVM_ABI APInt sextOrTrunc(unsigned width) const
Sign extend or truncate to width.
Definition APInt.cpp:1086
unsigned logBase2() const
Definition APInt.h:1781
APInt ashr(unsigned ShiftAmt) const
Arithmetic right-shift function.
Definition APInt.h:829
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
Definition APInt.h:436
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getHighBitsSet(unsigned numBits, unsigned hiBitsSet)
Constructs an APInt value that has the top hiBitsSet bits set.
Definition APInt.h:292
int64_t getSExtValue() const
Get sign extended value.
Definition APInt.h:1582
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
LLVM Basic Block Representation.
Definition BasicBlock.h:62
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Definition BasicBlock.h:237
InstructionCost getInterleavedMemoryOpCost(unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef< unsigned > Indices, Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind, bool UseMaskForCond=false, bool UseMaskForGaps=false) const override
InstructionCost getArithmeticInstrCost(unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Opd1Info={TTI::OK_AnyValue, TTI::OP_None}, TTI::OperandValueInfo Opd2Info={TTI::OK_AnyValue, TTI::OP_None}, ArrayRef< const Value * > Args={}, const Instruction *CxtI=nullptr) const override
InstructionCost getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF, TTI::TargetCostKind CostKind) const override
TTI::ShuffleKind improveShuffleKindFromMask(TTI::ShuffleKind Kind, ArrayRef< int > Mask, VectorType *SrcTy, int &Index, VectorType *&SubTy) const
bool isLegalAddressingMode(Type *Ty, GlobalValue *BaseGV, int64_t BaseOffset, bool HasBaseReg, int64_t Scale, unsigned AddrSpace, Instruction *I=nullptr, int64_t ScalableOffset=0) const override
bool areInlineCompatible(const Function *Caller, const Function *Callee) const override
InstructionCost getScalarizationOverhead(VectorType *InTy, const APInt &DemandedElts, bool Insert, bool Extract, TTI::TargetCostKind CostKind, bool ForPoisonSrc=true, ArrayRef< Value * > VL={}, TTI::VectorInstrContext VIC=TTI::VectorInstrContext::None) const override
InstructionCost getArithmeticReductionCost(unsigned Opcode, VectorType *Ty, std::optional< FastMathFlags > FMF, TTI::TargetCostKind CostKind) const override
InstructionCost getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info={TTI::OK_AnyValue, TTI::OP_None}, TTI::OperandValueInfo Op2Info={TTI::OK_AnyValue, TTI::OP_None}, const Instruction *I=nullptr) const override
InstructionCost getCallInstrCost(Function *F, Type *RetTy, ArrayRef< Type * > Tys, TTI::TargetCostKind CostKind) const override
void getUnrollingPreferences(Loop *L, ScalarEvolution &SE, TTI::UnrollingPreferences &UP, OptimizationRemarkEmitter *ORE) const override
void getPeelingPreferences(Loop *L, ScalarEvolution &SE, TTI::PeelingPreferences &PP) const override
InstructionCost getMulAccReductionCost(bool IsUnsigned, unsigned RedOpcode, Type *ResTy, VectorType *Ty, TTI::TargetCostKind CostKind) const override
InstructionCost getIndexedVectorInstrCostFromEnd(unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind, unsigned Index) const override
InstructionCost getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src, TTI::CastContextHint CCH, TTI::TargetCostKind CostKind, const Instruction *I=nullptr) const override
std::pair< InstructionCost, MVT > getTypeLegalizationCost(Type *Ty) const
InstructionCost getPartialReductionCost(unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType, ElementCount VF, TTI::PartialReductionExtendKind OpAExtend, TTI::PartialReductionExtendKind OpBExtend, std::optional< unsigned > BinOp, TTI::TargetCostKind CostKind, std::optional< FastMathFlags > FMF) const override
InstructionCost getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy, VectorType *Ty, std::optional< FastMathFlags > FMF, TTI::TargetCostKind CostKind) const override
InstructionCost getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, TTI::TargetCostKind CostKind) const override
InstructionCost getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy, TTI::TargetCostKind CostKind, ArrayRef< int > Mask, int Index, VectorType *SubTp, ArrayRef< const Value * > Args={}, const Instruction *CxtI=nullptr) const override
InstructionCost getMemIntrinsicInstrCost(const MemIntrinsicCostAttributes &MICA, TTI::TargetCostKind CostKind) const override
InstructionCost getMemoryOpCost(unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind, TTI::OperandValueInfo OpInfo={TTI::OK_AnyValue, TTI::OP_None}, const Instruction *I=nullptr) const override
bool isTypeLegal(Type *Ty) const override
static BinaryOperator * CreateWithCopiedFlags(BinaryOps Opc, Value *V1, Value *V2, Value *CopyO, const Twine &Name="", InsertPosition InsertBefore=nullptr)
Definition InstrTypes.h:254
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Value * getArgOperand(unsigned i) const
unsigned arg_size() const
This class represents a function call, abstracting a target machine's calling convention.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ ICMP_ULE
unsigned less or equal
Definition InstrTypes.h:766
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
static bool isFPPredicate(Predicate P)
Definition InstrTypes.h:833
static bool isIntPredicate(Predicate P)
Definition InstrTypes.h:839
bool isUnsigned() const
Definition InstrTypes.h:999
An abstraction over a floating-point predicate, and a pack of an integer predicate with samesign info...
static LLVM_ABI ConstantAggregateZero * get(Type *Ty)
This is the shared class of boolean and integer constants.
Definition Constants.h:87
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
Definition Constants.h:219
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
static LLVM_ABI ConstantInt * getBool(LLVMContext &Context, bool V)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI Constant * getSplatValue(bool AllowPoison=false) const
If all elements of the vector constant have the same value, return that value.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
TypeSize getTypeSizeInBits(Type *Ty) const
Size examples:
Definition DataLayout.h:791
bool empty() const
Definition DenseMap.h:206
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:249
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:308
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:305
constexpr bool isScalar() const
Exactly one element.
Definition TypeSize.h:316
static ExtractElementInst * Create(Value *Vec, Value *Idx, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
static bool isCommutative(Predicate Pred)
This provides a helper for copying FMF from an instruction or setting specified flags.
Definition IRBuilder.h:93
Convenience struct for specifying and reasoning about fast-math flags.
Definition FMF.h:23
bool noSignedZeros() const
Definition FMF.h:67
bool noInfs() const
Definition FMF.h:66
bool approxFunc() const
Definition FMF.h:70
bool allowContract() const
Definition FMF.h:69
Class to represent fixed width SIMD vectors.
unsigned getNumElements() const
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:843
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static bool isCommutative(Predicate P)
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2677
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition IRBuilder.h:2665
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Definition IRBuilder.h:547
Type * getDoubleTy()
Fetch the type representing a 64-bit floating point value.
Definition IRBuilder.h:567
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
LLVM_ABI CallInst * CreateMaskedLoad(Type *Ty, Value *Ptr, Align Alignment, Value *Mask, Value *PassThru=nullptr, const Twine &Name="")
Create a call to Masked Load intrinsic.
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition IRBuilder.h:534
Type * getHalfTy()
Fetch the type representing a 16-bit floating point value.
Definition IRBuilder.h:552
Value * CreateGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
Definition IRBuilder.h:2019
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
Definition IRBuilder.h:482
Value * CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name="", Instruction *MDFrom=nullptr)
Definition IRBuilder.h:1778
Value * CreateBitOrPointerCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2340
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2555
Value * CreateBinOpFMF(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, FMFSource FMFSource, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:1745
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1447
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2251
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition IRBuilder.h:1914
Value * CreateShuffleVector(Value *V1, Value *V2, Value *Mask, const Twine &Name="")
Definition IRBuilder.h:2699
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition IRBuilder.h:1933
LLVM_ABI CallInst * CreateMaskedStore(Value *Val, Value *Ptr, Align Alignment, Value *Mask)
Create a call to Masked Store intrinsic.
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1430
Type * getFloatTy()
Fetch the type representing a 32-bit floating point value.
Definition IRBuilder.h:562
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
Definition IRBuilder.h:2331
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:181
Value * CreateInsertVector(Type *DstType, Value *SrcVec, Value *SubVec, Value *Idx, const Twine &Name="")
Create a call to the vector.insert intrinsic.
Definition IRBuilder.h:1134
LLVM_ABI Value * CreateElementCount(Type *Ty, ElementCount EC)
Create an expression which evaluates to the number of elements in EC at runtime.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2908
This instruction inserts a single (scalar) element into a VectorType value.
The core instruction combiner logic.
virtual Instruction * eraseInstFromFunction(Instruction &I)=0
Combiner aware instruction erasure.
Instruction * replaceInstUsesWith(Instruction &I, Value *V)
A combiner-aware RAUW-like routine.
Instruction * replaceOperand(Instruction &I, unsigned OpNum, Value *V)
Replace operand of instruction and add old operand to the worklist.
static InstructionCost getInvalid(CostType Val=0)
CostType getValue() const
This function is intended to be used as sparingly as possible, since the class provides the full rang...
LLVM_ABI bool isCommutative() const LLVM_READONLY
Return true if the instruction is commutative:
bool isBinaryOp() const
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
user_iterator user_begin()
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
LLVM_ABI void copyMetadata(const Instruction &SrcInst, ArrayRef< unsigned > WL=ArrayRef< unsigned >())
Copy metadata from SrcInst to this instruction.
Class to represent integer types.
bool hasGroups() const
Returns true if we have any interleave groups.
const SmallVectorImpl< Type * > & getArgTypes() const
const SmallVectorImpl< const Value * > & getArgs() const
const IntrinsicInst * getInst() const
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
An instruction for reading from memory.
Value * getPointerOperand()
iterator_range< block_iterator > blocks() const
RecurrenceSet & getFixedOrderRecurrences()
Return the fixed-order recurrences found in the loop.
PredicatedScalarEvolution * getPredicatedScalarEvolution() const
const ReductionList & getReductionVars() const
Returns the reduction variables found in the loop.
Represents a single loop in the control flow graph.
Definition LoopInfo.h:40
Machine Value Type.
SimpleValueType SimpleTy
uint64_t getScalarSizeInBits() const
unsigned getVectorNumElements() const
bool isVector() const
Return true if this is a vector value type.
static MVT getScalableVectorVT(MVT VT, unsigned NumElements)
bool isFixedLengthVector() const
MVT getVectorElementType() const
size_type size() const
Definition MapVector.h:58
Information for memory intrinsic cost model.
const Instruction * getInst() const
The optimization diagnostic interface.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
An interface layer with SCEV used to manage how we see SCEV expressions for values in the context of ...
The RecurrenceDescriptor is used to identify recurrences variables in a loop.
Type * getRecurrenceType() const
Returns the type of the recurrence.
RecurKind getRecurrenceKind() const
This node represents a polynomial recurrence on the trip count of the specified loop.
bool isAffine() const
Return true if this represents an expression A + B*x where A and B are loop invariant values.
This class represents an analyzed expression in the program.
SMEAttrs is a utility class to parse the SME ACLE attributes on functions.
bool hasStreamingCompatibleInterface() const
bool hasStreamingInterfaceOrBody() const
bool isSMEABIRoutine() const
SMECallAttrs is a utility class to hold the SMEAttrs for a callsite.
static LLVM_ABI ScalableVectorType * get(Type *ElementType, unsigned MinNumElts)
Definition Type.cpp:865
static ScalableVectorType * getDoubleElementsVectorType(ScalableVectorType *VTy)
The main scalar evolution driver.
LLVM_ABI const SCEV * getBackedgeTakenCount(const Loop *L, ExitCountKind Kind=Exact)
If the specified loop has a predictable backedge-taken count, return it, otherwise return a SCEVCould...
LLVM_ABI unsigned getSmallConstantTripMultiple(const Loop *L, const SCEV *ExitCount)
Returns the largest constant divisor of the trip count as a normal unsigned value,...
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
LLVM_ABI bool isBackedgeTakenCountMaxOrZero(const Loop *L)
Return true if the backedge taken count is either the value returned by getConstantMaxBackedgeTakenCo...
LLVM_ABI bool isLoopInvariant(const SCEV *S, const Loop *L)
Return true if the value of the given SCEV is unchanging in the specified loop.
const SCEV * getSymbolicMaxBackedgeTakenCount(const Loop *L)
When successful, this returns a SCEV that is greater than or equal to (i.e.
This instruction constructs a fixed permutation of two input vectors.
static LLVM_ABI bool isDeInterleaveMaskOfFactor(ArrayRef< int > Mask, unsigned Factor, unsigned &Index)
Check if the mask is a DE-interleave mask of the given factor Factor like: <Index,...
static LLVM_ABI bool isExtractSubvectorMask(ArrayRef< int > Mask, int NumSrcElts, int &Index)
Return true if this shuffle mask is an extract subvector mask.
static LLVM_ABI bool isInterleaveMask(ArrayRef< int > Mask, unsigned Factor, unsigned NumInputElts, SmallVectorImpl< unsigned > &StartIndexes)
Return true if the mask interleaves one or more input vectors together.
size_type size() const
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
iterator insert(iterator I, T &&Elt)
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StackOffset holds a fixed and a scalable offset in bytes.
Definition TypeSize.h:30
static StackOffset getScalable(int64_t Scalable)
Definition TypeSize.h:40
static StackOffset getFixed(int64_t Fixed)
Definition TypeSize.h:39
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
Class to represent struct types.
TargetInstrInfo - Interface to description of machine instruction set.
std::pair< LegalizeTypeAction, EVT > LegalizeKind
LegalizeKind holds the legalization kind that needs to happen to EVT in order to type-legalize it.
const RTLIB::RuntimeLibcallsInfo & getRuntimeLibcallsInfo() const
virtual const DataLayout & getDataLayout() const
virtual bool shouldTreatInstructionLikeSelect(const Instruction *I) const
virtual bool isLoweredToCall(const Function *F) const
virtual bool isLSRCostLess(const TTI::LSRCost &C1, const TTI::LSRCost &C2) const
bool isConstantStridedAccessLessThan(ScalarEvolution *SE, const SCEV *Ptr, int64_t MergeDistance) const
virtual bool areTypesABICompatible(const Function *Caller, const Function *Callee, ArrayRef< Type * > Types) const
InstructionCost getInstructionCost(const User *U, ArrayRef< const Value * > Operands, TTI::TargetCostKind CostKind) const override
static LLVM_ABI OperandValueInfo getOperandInfo(const Value *V)
Collect properties of V used in cost analysis, e.g. OP_PowerOf2.
TargetCostKind
The kind of cost model.
@ TCK_RecipThroughput
Reciprocal throughput.
@ TCK_CodeSize
Instruction code size.
@ TCK_SizeAndLatency
The weighted sum of size and latency.
@ TCK_Latency
The latency of instruction.
static bool requiresOrderedReduction(std::optional< FastMathFlags > FMF)
A helper function to determine the type of reduction algorithm used for a given Opcode and set of Fas...
PopcntSupportKind
Flags indicating the kind of support for population count.
llvm::VectorInstrContext VectorInstrContext
@ TCC_Free
Expected to fold away in lowering.
@ TCC_Basic
The cost of a typical 'add' instruction.
ShuffleKind
The various kinds of shuffle patterns for vector queries.
@ SK_InsertSubvector
InsertSubvector. Index indicates start offset.
@ SK_Select
Selects elements from the corresponding lane of either source operand.
@ SK_PermuteSingleSrc
Shuffle elements of single source vector with any shuffle mask.
@ SK_Transpose
Transpose two vectors.
@ SK_Splice
Concatenates elements from the first input vector with elements of the second input vector.
@ SK_Broadcast
Broadcast element 0 to all other elements.
@ SK_PermuteTwoSrc
Merge elements from two source vectors into one with any shuffle mask.
@ SK_Reverse
Reverse the order of the vector.
@ SK_ExtractSubvector
ExtractSubvector Index indicates start offset.
CastContextHint
Represents a hint about the context in which a cast is used.
@ Masked
The cast is used with a masked load/store.
@ None
The cast is not used with a load/store of any kind.
@ Normal
The cast is used with a normal load/store.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:339
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Definition TypeSize.h:342
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:300
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:283
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:277
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition Type.h:155
bool isBFloatTy() const
Return true if this is 'bfloat', a 16-bit bfloat type.
Definition Type.h:147
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Definition Type.cpp:297
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:363
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition Type.h:144
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition Type.h:130
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:222
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition Type.h:158
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Definition Type.cpp:296
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
Definition Type.h:186
LLVM_ABI bool isScalableTy() const
Return true if this is a type whose size is a known multiple of vscale.
Definition Type.cpp:61
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:252
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
const Use & getOperandUse(unsigned i) const
Definition User.h:220
Value * getOperand(unsigned i) const
Definition User.h:207
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
bool hasOneUse() const
Return true if there is exactly one use of this value.
Definition Value.h:441
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
Definition Value.cpp:1002
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:400
Base class of all SIMD vector types.
ElementCount getElementCount() const
Return an ElementCount instance to represent the (possibly scalable) number of elements in the vector...
static VectorType * getInteger(VectorType *VTy)
This static method gets a VectorType with the same number of elements as the input type,...
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Type * getElementType() const
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:200
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition TypeSize.h:168
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
Definition TypeSize.h:252
const ParentTy * getParent() const
Definition ilist_node.h:34
CallInst * Call
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static bool isLogicalImmediate(uint64_t imm, unsigned regSize)
isLogicalImmediate - Return true if the immediate is valid for a logical immediate instruction of the...
void expandMOVImm(uint64_t Imm, unsigned BitSize, SmallVectorImpl< ImmInsnModel > &Insn)
Expand a MOVi32imm or MOVi64imm pseudo instruction to one or more real move-immediate instructions to...
LLVM_ABI APInt getCpuSupportsMask(ArrayRef< StringRef > Features)
static constexpr unsigned SVEBitsPerBlock
LLVM_ABI APInt getFMVPriority(ArrayRef< StringRef > Features)
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
ISD namespace - This namespace contains an enum which represents all of the SelectionDAG node types a...
Definition ISDOpcodes.h:24
@ ADD
Simple integer binary arithmetic operators.
Definition ISDOpcodes.h:264
@ CTTZ_ELTS
Returns the number of number of trailing (least significant) zero elements in a vector.
@ SINT_TO_FP
[SU]INT_TO_FP - These operators convert integers (whose interpreted sign depends on the first letter)...
Definition ISDOpcodes.h:890
@ FADD
Simple binary floating point operators.
Definition ISDOpcodes.h:417
@ BITCAST
BITCAST - This operator converts between integer, vector and FP values, as if the value was stored to...
@ SIGN_EXTEND
Conversion operators.
Definition ISDOpcodes.h:854
@ FNEG
Perform various unary floating-point operations inspired by libm.
@ SHL
Shift and rotation operations.
Definition ISDOpcodes.h:771
@ ZERO_EXTEND
ZERO_EXTEND - Used for integer types, zeroing the new bits.
Definition ISDOpcodes.h:860
@ FP_EXTEND
X = FP_EXTEND(Y) - Extend a smaller FP type into a larger FP type.
Definition ISDOpcodes.h:988
@ FP_TO_SINT
FP_TO_[US]INT - Convert a floating point value to a signed or unsigned integer.
Definition ISDOpcodes.h:936
@ AND
Bitwise operators - logical and, logical or, logical xor.
Definition ISDOpcodes.h:741
@ FP_ROUND
X = FP_ROUND(Y, TRUNC) - Rounding 'Y' from a larger floating point type down to the precision of the ...
Definition ISDOpcodes.h:969
@ TRUNCATE
TRUNCATE - Completely drop the high bits.
Definition ISDOpcodes.h:866
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
AllOnesConstantMatch m_AllOnes()
CheckType m_SpecificType(LLT Ty)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
BinaryOp_match< LHS, RHS, Instruction::And > m_And(const LHS &L, const RHS &R)
auto m_Cmp()
Matches any compare instruction and ignore it.
ap_match< APInt > m_APInt(const APInt *&Res)
Match a ConstantInt or splatted ConstantVector, binding the specified pointer to the contained APInt.
BinaryOp_match< LHS, RHS, Instruction::And, true > m_c_And(const LHS &L, const RHS &R)
Matches an And with LHS and RHS in either order.
LogicalOp_match< LHS, RHS, Instruction::And > m_LogicalAnd(const LHS &L, const RHS &R)
Matches L && R either in the form of L & R or L ?
specific_intval< false > m_SpecificInt(const APInt &V)
Match a specific integer value or vector with all elements equal to the value.
BinaryOp_match< LHS, RHS, Instruction::FMul > m_FMul(const LHS &L, const RHS &R)
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
specificval_ty m_Specific(const Value *V)
Match if we have a specific specified value.
TwoOps_match< Val_t, Idx_t, Instruction::ExtractElement > m_ExtractElt(const Val_t &Val, const Idx_t &Idx)
Matches ExtractElementInst.
cst_pred_ty< is_nonnegative > m_NonNegative()
Match an integer or vector of non-negative values.
cst_pred_ty< is_one > m_One()
Match an integer 1 or a vector with all elements equal to 1.
ThreeOps_match< Cond, LHS, RHS, Instruction::Select > m_Select(const Cond &C, const LHS &L, const RHS &R)
Matches SelectInst.
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
auto m_Value()
Match an arbitrary value and ignore it.
BinaryOp_match< LHS, RHS, Instruction::Xor, true > m_c_Xor(const LHS &L, const RHS &R)
Matches an Xor with LHS and RHS in either order.
BinaryOp_match< LHS, RHS, Instruction::Mul > m_Mul(const LHS &L, const RHS &R)
TwoOps_match< V1_t, V2_t, Instruction::ShuffleVector > m_Shuffle(const V1_t &v1, const V2_t &v2)
Matches ShuffleVectorInst independently of mask value.
auto m_VScale()
Matches a call to llvm.vscale().
OneOps_match< OpTy, Instruction::Load > m_Load(const OpTy &Op)
Matches LoadInst.
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
BinaryOp_match< LHS, RHS, Instruction::Add, true > m_c_Add(const LHS &L, const RHS &R)
Matches a Add with LHS and RHS in either order.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
AnyBinaryOp_match< LHS, RHS, true > m_c_BinOp(const LHS &L, const RHS &R)
Matches a BinaryOperator with LHS and RHS in either order.
CmpClass_match< LHS, RHS, ICmpInst > m_ICmp(CmpPredicate &Pred, const LHS &L, const RHS &R)
match_combine_or< CastInst_match< OpTy, ZExtInst >, CastInst_match< OpTy, SExtInst > > m_ZExtOrSExt(const OpTy &Op)
FNeg_match< OpTy > m_FNeg(const OpTy &X)
Match 'fneg X' as 'fsub -0.0, X'.
BinOpPred_match< LHS, RHS, is_shift_op > m_Shift(const LHS &L, const RHS &R)
Matches shift operations.
BinaryOp_match< LHS, RHS, Instruction::Shl > m_Shl(const LHS &L, const RHS &R)
brc_match< Cond_t, match_bind< BasicBlock >, match_bind< BasicBlock > > m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F)
auto m_Undef()
Match an arbitrary undef constant.
CastInst_match< OpTy, SExtInst > m_SExt(const OpTy &Op)
Matches SExt.
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
BinaryOp_match< LHS, RHS, Instruction::Or, true > m_c_Or(const LHS &L, const RHS &R)
Matches an Or with LHS and RHS in either order.
ThreeOps_match< Val_t, Elt_t, Idx_t, Instruction::InsertElement > m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx)
Matches InsertElementInst.
auto m_ConstantInt()
Match an arbitrary ConstantInt and ignore it.
initializer< Ty > init(const Ty &Val)
LocationClass< Ty > location(Ty &L)
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
std::optional< unsigned > isDUPQMask(ArrayRef< int > Mask, unsigned Segments, unsigned SegmentSize)
isDUPQMask - matches a splat of equivalent lanes within segments of a given number of elements.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1755
const CostTblEntryT< CostType > * CostTableLookup(ArrayRef< CostTblEntryT< CostType > > Tbl, int ISD, MVT Ty)
Find in cost table.
Definition CostTable.h:36
LLVM_ABI bool getBooleanLoopAttribute(const Loop *TheLoop, StringRef Name)
Returns true if Name is applied to TheLoop and enabled.
bool isZIPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for zip1 or zip2 masks of the form: <0, 8, 1, 9, 2, 10, 3, 11> (WhichResultOut = 0,...
TailFoldingOpts
An enum to describe what types of loops we should attempt to tail-fold: Disabled: None Reductions: Lo...
InstructionCost Cost
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
Definition MathExtras.h:166
@ Known
Known to have no common set bits.
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2570
bool isDUPFirstSegmentMask(ArrayRef< int > Mask, unsigned Segments, unsigned SegmentSize)
isDUPFirstSegmentMask - matches a splat of the first 128b segment.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
@ Uninitialized
Definition Threading.h:60
LLVM_ABI std::optional< const MDOperand * > findStringMetadataForLoop(const Loop *TheLoop, StringRef Name)
Find string metadata for loop.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
LLVM_ABI Value * getSplatValue(const Value *V)
Get splat value if the input is a splat vector or return nullptr.
LLVM_ABI std::optional< int64_t > getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr, const Loop *Lp, const DominatorTree &DT, const SymbolicStrideMap &StridesMap=SymbolicStrideMap(), bool ShouldCheckWrap=true, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
If the pointer has a constant stride return it in units of the access type size.
constexpr auto equal_to(T &&Arg)
Functor variant of std::equal_to that can be used as a UnaryPredicate in functional algorithms like a...
Definition STLExtras.h:2189
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:332
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
LLVM_ABI bool MaskedValueIsZero(const Value *V, const APInt &Mask, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if 'V & Mask' is known to be zero.
unsigned M1(unsigned Val)
Definition VE.h:377
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1762
LLVM_ABI bool isSplatValue(const Value *V, int Index=-1, unsigned Depth=0)
Return true if each element of the vector value V is poisoned or equal to every other non-poisoned el...
unsigned getPerfectShuffleCost(llvm::ArrayRef< int > M)
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
DenseMap< Value *, const SCEVUnknown * > SymbolicStrideMap
Maps a pointer to its symbolic (non-constant) stride.
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1769
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
bool isUZPMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut)
Return true for uzp1 or uzp2 masks of the form: <0, 2, 4, 6, 8, 10, 12, 14> or <1,...
bool isREVMask(ArrayRef< int > M, unsigned EltSize, unsigned NumElts, unsigned BlockSize)
isREVMask - Check if a vector shuffle corresponds to a REV instruction with the specified blocksize.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
constexpr int PoisonMaskElem
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
TargetTransformInfo TTI
LLVM_ABI Value * simplifyBinOp(unsigned Opcode, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a BinaryOperator, fold the result or return null.
@ UMin
Unsigned integer min implemented in terms of select(cmp()).
@ Or
Bitwise or logical OR of integers.
@ FSub
Subtraction of floats.
@ FAddChainWithSubs
A chain of fadds and fsubs.
@ AnyOf
AnyOf reduction with select(cmp(),x,y) where one of (x,y) is loop invariant, and both x and y are int...
@ Xor
Bitwise or logical XOR of integers.
@ FindLast
FindLast reduction with select(cmp(),x,y) where x and y.
@ FMax
FP max implemented in terms of select(cmp()).
@ FMulAdd
Sum of float products with llvm.fmuladd(a * b + sum).
@ FMul
Product of floats.
@ SMax
Signed integer max implemented in terms of select(cmp()).
@ And
Bitwise or logical AND of integers.
@ SMin
Signed integer min implemented in terms of select(cmp()).
@ FMin
FP min implemented in terms of select(cmp()).
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
@ AddChainWithSubs
A chain of adds and subs.
@ FAdd
Sum of floats.
@ UMax
Unsigned integer max implemented in terms of select(cmp()).
DWARFExpression::Operation Op
TypeConversionCostTblEntryT< uint16_t > TypeConversionCostTblEntry
Definition CostTable.h:62
CostTblEntryT< uint16_t > CostTblEntry
Definition CostTable.h:31
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
unsigned getNumElementsFromSVEPredPattern(unsigned Pattern)
Return the number of active elements for VL1 to VL256 predicate pattern, zero for all other patterns.
auto predecessors(const MachineBasicBlock *BB)
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
bool all_equal(std::initializer_list< T > Values)
Returns true if all Values in the initializer lists are equal or the list.
Definition STLExtras.h:2182
LLVM_ABI Value * simplifyCmpInst(CmpPredicate Predicate, Value *LHS, Value *RHS, const SimplifyQuery &Q)
Given operands for a CmpInst, fold the result or return null.
Type * toVectorTy(Type *Scalar, ElementCount EC)
A helper function for converting Scalar types to vector types.
const TypeConversionCostTblEntryT< CostType > * ConvertCostTableLookup(ArrayRef< TypeConversionCostTblEntryT< CostType > > Tbl, int ISD, MVT Dst, MVT Src)
Find in type conversion cost table.
Definition CostTable.h:67
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
bool isTRNMask(ArrayRef< int > M, unsigned NumElts, unsigned &WhichResultOut, unsigned &OperandOrderOut)
Return true for trn1 or trn2 masks of the form: <0, 8, 2, 10, 4, 12, 6, 14> (WhichResultOut = 0,...
#define N
static SVEIntrinsicInfo defaultMergingUnaryNarrowingTopOp()
static SVEIntrinsicInfo defaultZeroingOp()
SVEIntrinsicInfo & setOperandIdxInactiveLanesTakenFrom(unsigned Index)
static SVEIntrinsicInfo defaultMergingOp(Intrinsic::ID IID=Intrinsic::not_intrinsic)
SVEIntrinsicInfo & setOperandIdxWithNoActiveLanes(unsigned Index)
unsigned getOperandIdxWithNoActiveLanes() const
CmpInst::Predicate getCmpPredicate() const
SVEIntrinsicInfo & setInactiveLanesAreUnused()
SVEIntrinsicInfo & setInactiveLanesAreNotDefined()
SVEIntrinsicInfo & setGoverningPredicateOperandIdx(unsigned Index)
static SVEIntrinsicInfo defaultUndefOp()
Intrinsic::ID getMatchingUndefIntrinsic() const
SVEIntrinsicInfo & setResultIsZeroInitialized()
static SVEIntrinsicInfo defaultMergingUnaryOp()
SVEIntrinsicInfo & setMatchingUndefIntrinsic(Intrinsic::ID IID)
unsigned getGoverningPredicateOperandIdx() const
SVEIntrinsicInfo & setCmpPredicate(CmpInst::Predicate Pred)
SVEIntrinsicInfo & setMatchingIROpcode(unsigned Opcode)
unsigned getOperandIdxInactiveLanesTakenFrom() const
static SVEIntrinsicInfo defaultVoidOp(unsigned GPIndex)
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
Extended Value Type.
Definition ValueTypes.h:35
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
Definition ValueTypes.h:145
bool bitsGT(EVT VT) const
Return true if this has more bits than VT.
Definition ValueTypes.h:307
TypeSize getSizeInBits() const
Return the size of the specified value type in bits.
Definition ValueTypes.h:396
unsigned getVectorMinNumElements() const
Given a vector type, return the minimum number of elements it contains.
Definition ValueTypes.h:382
uint64_t getScalarSizeInBits() const
Definition ValueTypes.h:408
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
Definition ValueTypes.h:339
bool isFixedLengthVector() const
Definition ValueTypes.h:199
EVT getScalarType() const
If this is a vector type, return the element type, otherwise return this.
Definition ValueTypes.h:346
LLVM_ABI Type * getTypeForEVT(LLVMContext &Context) const
This method returns an LLVM type corresponding to the specified EVT.
bool isScalableVector() const
Return true if this is a vector type where the runtime length is machine dependent.
Definition ValueTypes.h:187
EVT getVectorElementType() const
Given a vector type, return the type of each element.
Definition ValueTypes.h:351
unsigned getVectorNumElements() const
Given a vector type, return the number of elements it contains.
Definition ValueTypes.h:359
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Definition MCSchedule.h:129
bool isVariant() const
Definition MCSchedule.h:150
Machine model for scheduling, bundling, and heuristics.
Definition MCSchedule.h:273
static LLVM_ABI double getReciprocalThroughput(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Matching combinators.
Information about a load/store intrinsic defined by the target.
InterleavedAccessInfo * IAI
LoopVectorizationLegality * LVL
This represents an addressing mode of: BaseGV + BaseOffs + BaseReg + Scale*ScaleReg + ScalableOffset*...
unsigned Insns
TODO: Some of these could be merged.
Returns options for expansion of memcmp. IsZeroCmp is.
Parameters that control the generic loop unrolling transformation.
bool UpperBound
Allow using trip count upper bound to unroll loops.
bool Force
Apply loop unroll on any kind of loop (mainly to loops that fail runtime unrolling).
unsigned PartialOptSizeThreshold
The cost threshold for the unrolled loop when optimizing for size, like OptSizeThreshold,...
unsigned DefaultUnrollRuntimeCount
Default unroll count for loops with run-time trip count.
bool RuntimeUnrollMultiExit
Allow runtime unrolling multi-exit loops.
unsigned SCEVExpansionBudget
Don't allow runtime unrolling if expanding the trip count takes more than SCEVExpansionBudget.
bool AddAdditionalAccumulators
Allow unrolling to add parallel reduction phis.
unsigned UnrollAndJamInnerLoopThreshold
Threshold for unroll and jam, for inner loop size.
bool UnrollAndJam
Allow unroll and jam. Used to enable unroll and jam for the target.
bool UnrollRemainder
Allow unrolling of all the iterations of the runtime loop remainder.
unsigned PartialThreshold
The cost threshold for the unrolled loop, like Threshold, but used for partial/runtime unrolling (set...
bool Runtime
Allow runtime unrolling (unrolling of loops to expand the size of the loop body even when the number ...
bool Partial
Allow partial unrolling (unrolling of loops to expand the size of the loop body, not only to eliminat...
unsigned MaxUpperBound
Set the maximum upper bound of trip count.