1//===- AArch64TargetTransformInfo.h - AArch64 specific TTI ------*- C++ -*-===//
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/// \file
9/// This file a TargetTransformInfoImplBase conforming object specific to the
10/// AArch64 target machine. It uses the target's detailed information to
11/// provide more precise answers to certain TTI queries, while letting the
12/// target independent and default TTI implementations handle the rest.
13///
14//===----------------------------------------------------------------------===//
15
16#ifndef LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
17#define LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
18
19#include "AArch64.h"
20#include "AArch64Subtarget.h"
21#include "AArch64TargetMachine.h"
22#include "llvm/Analysis/TargetTransformInfo.h"
23#include "llvm/CodeGen/BasicTTIImpl.h"
24#include "llvm/IR/FMF.h"
25#include "llvm/IR/Function.h"
26#include "llvm/IR/Intrinsics.h"
27#include "llvm/Support/InstructionCost.h"
28#include <cstdint>
29#include <optional>
30
31namespace llvm {
32
33class APInt;
34class Instruction;
35class IntrinsicInst;
36class Loop;
37class SCEV;
38class ScalarEvolution;
39class Type;
40class Value;
41class VectorType;
42
43class AArch64TTIImpl final : public BasicTTIImplBase<AArch64TTIImpl> {
44 using BaseT = BasicTTIImplBase<AArch64TTIImpl>;
45 using TTI = TargetTransformInfo;
46
47 friend BaseT;
48
49 const AArch64Subtarget *ST;
50 const AArch64TargetLowering *TLI;
51
52 const AArch64Subtarget *getST() const { return ST; }
53 const AArch64TargetLowering *getTLI() const { return TLI; }
54
55 /// Given a add/sub/mul operation, detect a widening addl/subl/mull pattern
56 /// where both operands can be treated like extends. Returns the minimal type
57 /// needed to compute the operation.
58 Type *isBinExtWideningInstruction(unsigned Opcode, Type *DstTy,
59 ArrayRef<const Value *> Args,
60 Type *SrcOverrideTy = nullptr) const;
61 /// Given a add/sub operation with a single extend operand, detect a
62 /// widening addw/subw pattern.
63 bool isSingleExtWideningInstruction(unsigned Opcode, Type *DstTy,
64 ArrayRef<const Value *> Args,
65 Type *SrcOverrideTy = nullptr) const;
66
67 // A helper function called by 'getVectorInstrCost'.
68 //
69 // 'Val' and 'Index' are forwarded from 'getVectorInstrCost';
70 // \param ScalarUserAndIdx encodes the information about extracts from a
71 /// vector with 'Scalar' being the value being extracted,'User' being the user
72 /// of the extract(nullptr if user is not known before vectorization) and
73 /// 'Idx' being the extract lane.
74 InstructionCost getVectorInstrCostHelper(
75 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index,
76 const Instruction *I = nullptr, Value *Scalar = nullptr,
77 ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx = {},
78 TTI::VectorInstrContext VIC = TTI::VectorInstrContext::None) const;
79
80public:
81 explicit AArch64TTIImpl(const AArch64TargetMachine *TM, const Function &F)
82 : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
83 TLI(ST->getTargetLowering()) {}
84
85 bool areInlineCompatible(const Function *Caller,
86 const Function *Callee) const override;
87
88 bool areTypesABICompatible(const Function *Caller, const Function *Callee,
89 ArrayRef<Type *> Types) const override;
90
91 unsigned getInlineCallPenalty(const Function *F, const CallBase &Call,
92 unsigned DefaultCallPenalty) const override;
93
94 APInt getFeatureMask(const Function &F) const override;
95 APInt getPriorityMask(const Function &F) const override;
96
97 bool isMultiversionedFunction(const Function &F) const override;
98
99 /// \name Scalar TTI Implementations
100 /// @{
101
102 using BaseT::getIntImmCost;
103 InstructionCost getIntImmCost(int64_t Val) const;
104 InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
105 TTI::TargetCostKind CostKind) const override;
106 InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
107 const APInt &Imm, Type *Ty,
108 TTI::TargetCostKind CostKind,
109 Instruction *Inst = nullptr) const override;
110 InstructionCost
111 getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx, const APInt &Imm,
112 Type *Ty, TTI::TargetCostKind CostKind) const override;
113 TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth) const override;
114
115 /// @}
116
117 /// \name Vector TTI Implementations
118 /// @{
119
120 bool enableInterleavedAccessVectorization() const override { return true; }
121
122 bool enableMaskedInterleavedAccessVectorization() const override {
123 return ST->hasSVE();
124 }
125
126 unsigned getNumberOfRegisters(unsigned ClassID) const override {
127 bool Vector = (ClassID == 1);
128 if (Vector) {
129 if (ST->hasNEON())
130 return 32;
131 return 0;
132 }
133 return 31;
134 }
135
136 InstructionCost
137 getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
138 TTI::TargetCostKind CostKind) const override;
139
140 std::optional<Instruction *>
141 instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override;
142
143 std::optional<Value *> simplifyDemandedVectorEltsIntrinsic(
144 InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts,
145 APInt &UndefElts2, APInt &UndefElts3,
146 std::function<void(Instruction *, unsigned, APInt, APInt &)>
147 SimplifyAndSetOp) const override;
148
149 TypeSize
150 getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override;
151
152 unsigned getMinVectorRegisterBitWidth() const override {
153 return ST->getMinVectorRegisterBitWidth();
154 }
155
156 std::optional<unsigned> getVScaleForTuning() const override {
157 return ST->getVScaleForTuning();
158 }
159
160 bool shouldMaximizeVectorBandwidth(
161 TargetTransformInfo::RegisterKind K) const override;
162
163 /// Try to return an estimate cost factor that can be used as a multiplier
164 /// when scalarizing an operation for a vector with ElementCount \p VF.
165 /// For scalable vectors this currently takes the most pessimistic view based
166 /// upon the maximum possible value for vscale.
167 unsigned getMaxNumElements(ElementCount VF) const {
168 if (!VF.isScalable())
169 return VF.getFixedValue();
170
171 return VF.getKnownMinValue() * ST->getVScaleForTuning();
172 }
173
174 unsigned getMaxInterleaveFactor(ElementCount VF,
175 bool HasUnorderedReductions) const override;
176
177 bool prefersVectorizedAddressing() const override;
178
179 /// Check whether Opcode1 has less throughput according to the scheduling
180 /// model than Opcode2.
181 bool hasKnownLowerThroughputFromSchedulingModel(unsigned Opcode1,
182 unsigned Opcode2) const;
183
184 InstructionCost
185 getMemIntrinsicInstrCost(const MemIntrinsicCostAttributes &MICA,
186 TTI::TargetCostKind CostKind) const override;
187
188 InstructionCost getMaskedMemoryOpCost(const MemIntrinsicCostAttributes &MICA,
189 TTI::TargetCostKind CostKind) const;
190
191 InstructionCost getGatherScatterOpCost(const MemIntrinsicCostAttributes &MICA,
192 TTI::TargetCostKind CostKind) const;
193
194 bool isExtPartOfAvgExpr(const Instruction *ExtUser, Type *Dst,
195 Type *Src) const;
196
197 InstructionCost
198 getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
199 TTI::CastContextHint CCH, TTI::TargetCostKind CostKind,
200 const Instruction *I = nullptr) const override;
201
202 InstructionCost
203 getExtractWithExtendCost(unsigned Opcode, Type *Dst, VectorType *VecTy,
204 unsigned Index,
205 TTI::TargetCostKind CostKind) const override;
206
207 InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
208 const Instruction *I = nullptr) const override;
209
210 InstructionCost
211 getVectorInstrCost(unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
212 unsigned Index, const Value *Op0, const Value *Op1,
213 TTI::VectorInstrContext VIC =
214 TTI::VectorInstrContext::None) const override;
215
216 /// \param ScalarUserAndIdx encodes the information about extracts from a
217 /// vector with 'Scalar' being the value being extracted,'User' being the user
218 /// of the extract(nullptr if user is not known before vectorization) and
219 /// 'Idx' being the extract lane.
220 InstructionCost getVectorInstrCost(
221 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind, unsigned Index,
222 Value *Scalar,
223 ArrayRef<std::tuple<Value *, User *, int>> ScalarUserAndIdx,
224 TTI::VectorInstrContext VIC =
225 TTI::VectorInstrContext::None) const override;
226
227 InstructionCost
228 getVectorInstrCost(const Instruction &I, Type *Ty,
229 TTI::TargetCostKind CostKind, unsigned Index,
230 TTI::VectorInstrContext VIC =
231 TTI::VectorInstrContext::None) const override;
232
233 InstructionCost
234 getIndexedVectorInstrCostFromEnd(unsigned Opcode, Type *Ty,
235 TTI::TargetCostKind CostKind,
236 unsigned Index) const override;
237
238 InstructionCost
239 getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF,
240 TTI::TargetCostKind CostKind) const override;
241
242 InstructionCost
243 getArithmeticReductionCostSVE(unsigned Opcode, VectorType *ValTy,
244 TTI::TargetCostKind CostKind) const;
245
246 InstructionCost getSpliceCost(VectorType *Tp, int Index,
247 TTI::TargetCostKind CostKind) const;
248
249 InstructionCost getArithmeticInstrCost(
250 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
251 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
252 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
253 ArrayRef<const Value *> Args = {},
254 const Instruction *CxtI = nullptr) const override;
255
256 InstructionCost
257 getAddressComputationCost(Type *PtrTy, ScalarEvolution *SE, const SCEV *Ptr,
258 TTI::TargetCostKind CostKind) const override;
259
260 InstructionCost getCmpSelInstrCost(
261 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
262 TTI::TargetCostKind CostKind,
263 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
264 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
265 const Instruction *I = nullptr) const override;
266
267 TTI::MemCmpExpansionOptions
268 enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const override;
269 bool useNeonVector(const Type *Ty) const;
270
271 InstructionCost getMemoryOpCost(
272 unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace,
273 TTI::TargetCostKind CostKind,
274 TTI::OperandValueInfo OpInfo = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
275 const Instruction *I = nullptr) const override;
276
277 InstructionCost
278 getCostOfKeepingLiveOverCall(ArrayRef<Type *> Tys) const override;
279
280 bool isLegalMaskedExpandLoad(Type *DataTy, Align Alignment) const override;
281
282 void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
283 TTI::UnrollingPreferences &UP,
284 OptimizationRemarkEmitter *ORE) const override;
285
286 void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
287 TTI::PeelingPreferences &PP) const override;
288
289 Value *
290 getOrCreateResultFromMemIntrinsic(IntrinsicInst *Inst, Type *ExpectedType,
291 bool CanCreate = true) const override;
292
293 bool getTgtMemIntrinsic(IntrinsicInst *Inst,
294 MemIntrinsicInfo &Info) const override;
295
296 bool isElementTypeLegalForScalableVector(Type *Ty) const override {
297 if (Ty->isPointerTy())
298 return true;
299
300 if (Ty->isBFloatTy() || Ty->isHalfTy() || Ty->isFloatTy() ||
301 Ty->isDoubleTy())
302 return true;
303
304 if (Ty->isIntegerTy(BitWidth: 1) || Ty->isIntegerTy(BitWidth: 8) || Ty->isIntegerTy(BitWidth: 16) ||
305 Ty->isIntegerTy(BitWidth: 32) || Ty->isIntegerTy(BitWidth: 64))
306 return true;
307
308 return false;
309 }
310
311 bool isLegalMaskedLoadStore(Type *DataType, Align Alignment) const {
312 if (!ST->isSVEorStreamingSVEAvailable())
313 return false;
314
315 if (isa<FixedVectorType>(Val: DataType) && !ST->useSVEForFixedLengthVectors()) {
316 unsigned Bits = DataType->getPrimitiveSizeInBits();
317 if (Bits != 64 && Bits != 128)
318 return false; // Fall back to scalarization of masked operations.
319 }
320
321 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
322 }
323
324 bool isLegalMaskedLoad(Type *DataType, Align Alignment,
325 unsigned /*AddressSpace*/,
326 TTI::MaskKind /*MaskKind*/) const override {
327 return isLegalMaskedLoadStore(DataType, Alignment);
328 }
329
330 bool isLegalMaskedStore(Type *DataType, Align Alignment,
331 unsigned /*AddressSpace*/,
332 TTI::MaskKind /*MaskKind*/) const override {
333 return isLegalMaskedLoadStore(DataType, Alignment);
334 }
335
336 bool isElementTypeLegalForCompressStore(Type *Ty) const {
337 return Ty->isFloatTy() || Ty->isDoubleTy() || Ty->isIntegerTy(BitWidth: 32) ||
338 Ty->isIntegerTy(BitWidth: 64);
339 }
340
341 bool isLegalMaskedCompressStore(Type *DataType,
342 Align Alignment) const override {
343 if (!ST->isSVEAvailable())
344 return false;
345
346 if (isa<FixedVectorType>(Val: DataType) &&
347 DataType->getPrimitiveSizeInBits() < 128)
348 return false;
349
350 return isElementTypeLegalForCompressStore(Ty: DataType->getScalarType());
351 }
352
353 bool isLegalMaskedGatherScatter(Type *DataType) const {
354 if (!ST->isSVEAvailable())
355 return false;
356
357 // For fixed vectors, scalarize if not using SVE for them.
358 auto *DataTypeFVTy = dyn_cast<FixedVectorType>(Val: DataType);
359 if (DataTypeFVTy && (!ST->useSVEForFixedLengthVectors() ||
360 DataTypeFVTy->getNumElements() < 2))
361 return false;
362
363 return isElementTypeLegalForScalableVector(Ty: DataType->getScalarType());
364 }
365
366 bool isLegalMaskedGather(Type *DataType, Align Alignment) const override {
367 return isLegalMaskedGatherScatter(DataType);
368 }
369
370 bool isLegalMaskedScatter(Type *DataType, Align Alignment) const override {
371 return isLegalMaskedGatherScatter(DataType);
372 }
373
374 bool isLegalBroadcastLoad(Type *ElementTy,
375 ElementCount NumElements) const override {
376 // Return true if we can generate a `ld1r` splat load instruction.
377 if (!ST->hasNEON() || NumElements.isScalable())
378 return false;
379 switch (unsigned ElementBits = ElementTy->getScalarSizeInBits()) {
380 case 8:
381 case 16:
382 case 32:
383 case 64: {
384 // We accept bit-widths >= 64bits and elements {8,16,32,64} bits.
385 unsigned VectorBits = NumElements.getFixedValue() * ElementBits;
386 return VectorBits >= 64;
387 }
388 }
389 return false;
390 }
391
392 std::optional<bool> isLegalNTStoreLoad(Type *DataType,
393 Align Alignment) const {
394 // Currently we only support NT load and store lowering for little-endian
395 // targets.
396 //
397 // Coordinated with LDNP and STNP constraints in
398 // `llvm/lib/Target/AArch64/AArch64InstrInfo.td` and
399 // `AArch64ISelLowering.cpp`
400 if (!ST->isLittleEndian())
401 return false;
402
403 // NOTE: The logic below is mostly geared towards LV, which calls it with
404 // vectors with 2 elements. We might want to improve that, if other
405 // users show up.
406 // Nontemporal vector loads/stores can be directly lowered to LDNP/STNP, if
407 // the vector can be halved so that each half fits into a register. That's
408 // the case if the element type fits into a register and the number of
409 // elements is a power of 2 > 1.
410 if (auto *DataTypeTy = dyn_cast<FixedVectorType>(Val: DataType)) {
411 unsigned NumElements = DataTypeTy->getNumElements();
412 unsigned EltSize = DataTypeTy->getElementType()->getScalarSizeInBits();
413 return NumElements > 1 && isPowerOf2_64(Value: NumElements) && EltSize >= 8 &&
414 EltSize <= 128 && isPowerOf2_64(Value: EltSize);
415 }
416 return std::nullopt;
417 }
418
419 bool isLegalNTStore(Type *DataType, Align Alignment) const override {
420 if (auto Result = isLegalNTStoreLoad(DataType, Alignment))
421 return *Result;
422 // Fallback to target independent logic
423 return BaseT::isLegalNTStore(DataType, Alignment);
424 }
425
426 bool isLegalNTLoad(Type *DataType, Align Alignment) const override {
427 if (auto Result = isLegalNTStoreLoad(DataType, Alignment))
428 return *Result;
429 // Fallback to target independent logic
430 return BaseT::isLegalNTLoad(DataType, Alignment);
431 }
432
433 InstructionCost getPartialReductionCost(
434 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
435 ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
436 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
437 TTI::TargetCostKind CostKind,
438 std::optional<FastMathFlags> FMF) const override;
439
440 bool enableOrderedReductions() const override { return true; }
441
442 InstructionCost getInterleavedMemoryOpCost(
443 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
444 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
445 bool UseMaskForCond = false, bool UseMaskForGaps = false) const override;
446
447 bool shouldConsiderAddressTypePromotion(
448 const Instruction &I,
449 bool &AllowPromotionWithoutCommonHeader) const override;
450
451 bool shouldExpandReduction(const IntrinsicInst *II) const override {
452 return false;
453 }
454
455 unsigned getGISelRematGlobalCost() const override { return 2; }
456
457 InstructionCost getBranchMispredictPenalty() const override;
458
459 unsigned getMinTripCountTailFoldingThreshold() const override {
460 return ST->hasSVE() ? 5 : 0;
461 }
462
463 TailFoldingStyle getPreferredTailFoldingStyle() const override {
464 return ST->hasSVE() ? TailFoldingStyle::DataAndControlFlow
465 : TailFoldingStyle::DataWithoutLaneMask;
466 }
467
468 bool preferFixedOverScalableIfEqualCost() const override;
469
470 unsigned getEpilogueVectorizationMinVF() const override;
471
472 bool preferTailFoldingOverEpilogue(TailFoldingInfo *TFI) const override;
473
474 bool supportsScalableVectors() const override {
475 return ST->isSVEorStreamingSVEAvailable();
476 }
477
478 bool enableScalableVectorization() const override;
479
480 bool isLegalToVectorizeReduction(const RecurrenceDescriptor &RdxDesc,
481 ElementCount VF) const override;
482
483 bool preferPredicatedReductionSelect() const override { return ST->hasSVE(); }
484
485 /// FP16 and BF16 operations are lowered to fptrunc(op(fpext, fpext) if the
486 /// architecture features are not present.
487 std::optional<InstructionCost> getFP16BF16PromoteCost(
488 Type *Ty, TTI::TargetCostKind CostKind, TTI::OperandValueInfo Op1Info,
489 TTI::OperandValueInfo Op2Info, bool IncludeTrunc, bool CanUseSVE,
490 std::function<InstructionCost(Type *)> InstCost) const;
491
492 InstructionCost
493 getArithmeticReductionCost(unsigned Opcode, VectorType *Ty,
494 std::optional<FastMathFlags> FMF,
495 TTI::TargetCostKind CostKind) const override;
496
497 InstructionCost
498 getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy,
499 VectorType *ValTy, std::optional<FastMathFlags> FMF,
500 TTI::TargetCostKind CostKind) const override;
501
502 InstructionCost getMulAccReductionCost(
503 bool IsUnsigned, unsigned RedOpcode, Type *ResTy, VectorType *Ty,
504 TTI::TargetCostKind CostKind = TTI::TCK_RecipThroughput) const override;
505
506 InstructionCost
507 getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy,
508 TTI::TargetCostKind CostKind, ArrayRef<int> Mask, int Index,
509 VectorType *SubTp, ArrayRef<const Value *> Args = {},
510 const Instruction *CxtI = nullptr) const override;
511
512 InstructionCost
513 getScalarizationOverhead(VectorType *Ty, const APInt &DemandedElts,
514 bool Insert, bool Extract,
515 TTI::TargetCostKind CostKind,
516 bool ForPoisonSrc = true, ArrayRef<Value *> VL = {},
517 TTI::VectorInstrContext VIC =
518 TTI::VectorInstrContext::None) const override;
519
520 /// Return the cost of the scaling factor used in the addressing
521 /// mode represented by AM for this target, for a load/store
522 /// of the specified type.
523 /// If the AM is supported, the return value must be >= 0.
524 /// If the AM is not supported, it returns an invalid cost.
525 InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
526 StackOffset BaseOffset, bool HasBaseReg,
527 int64_t Scale,
528 unsigned AddrSpace) const override;
529
530 bool enableSelectOptimize() const override {
531 return ST->enableSelectOptimize();
532 }
533
534 bool shouldTreatInstructionLikeSelect(const Instruction *I) const override;
535
536 unsigned getStoreMinimumVF(unsigned VF, Type *ScalarMemTy, Type *ScalarValTy,
537 Align Alignment,
538 unsigned AddrSpace) const override {
539 // We can vectorize store v4i8.
540 if (ScalarMemTy->isIntegerTy(BitWidth: 8) && isPowerOf2_32(Value: VF) && VF >= 4)
541 return 4;
542
543 return BaseT::getStoreMinimumVF(VF, ScalarMemTy, ScalarValTy, Alignment,
544 AddrSpace);
545 }
546
547 std::optional<unsigned> getMinPageSize() const override { return 4096; }
548
549 bool isLSRCostLess(const TargetTransformInfo::LSRCost &C1,
550 const TargetTransformInfo::LSRCost &C2) const override;
551
552 bool isProfitableToSinkOperands(Instruction *I,
553 SmallVectorImpl<Use *> &Ops) const override;
554
555 bool enableAggressiveInterleaving(bool) const override {
556 return ST->enableAggressiveInterleaving();
557 }
558 /// @}
559};
560
561} // end namespace llvm
562
563#endif // LLVM_LIB_TARGET_AARCH64_AARCH64TARGETTRANSFORMINFO_H
564