1//===- ARMTargetTransformInfo.h - ARM 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//
9/// \file
10/// This file a TargetTransformInfoImplBase conforming object specific to the
11/// ARM target machine. It uses the target's detailed information to
12/// provide more precise answers to certain TTI queries, while letting the
13/// target independent and default TTI implementations handle the rest.
14//
15//===----------------------------------------------------------------------===//
16
17#ifndef LLVM_LIB_TARGET_ARM_ARMTARGETTRANSFORMINFO_H
18#define LLVM_LIB_TARGET_ARM_ARMTARGETTRANSFORMINFO_H
19
20#include "ARM.h"
21#include "ARMSubtarget.h"
22#include "ARMTargetMachine.h"
23#include "llvm/ADT/ArrayRef.h"
24#include "llvm/Analysis/TargetTransformInfo.h"
25#include "llvm/CodeGen/BasicTTIImpl.h"
26#include "llvm/IR/Constant.h"
27#include "llvm/IR/Function.h"
28#include "llvm/TargetParser/SubtargetFeature.h"
29#include <optional>
30
31namespace llvm {
32
33class APInt;
34class ARMTargetLowering;
35class Instruction;
36class Loop;
37class SCEV;
38class ScalarEvolution;
39class Type;
40class Value;
41
42namespace TailPredication {
43enum Mode {
44 Disabled = 0,
45 EnabledNoReductions,
46 Enabled,
47 ForceEnabledNoReductions,
48 ForceEnabled
49};
50}
51
52// For controlling conversion of memcpy into Tail Predicated loop.
53namespace TPLoop {
54enum MemTransfer { ForceDisabled = 0, ForceEnabled, Allow };
55}
56
57class ARMTTIImpl final : public BasicTTIImplBase<ARMTTIImpl> {
58 using BaseT = BasicTTIImplBase<ARMTTIImpl>;
59 using TTI = TargetTransformInfo;
60
61 friend BaseT;
62
63 const ARMSubtarget *ST;
64 const ARMTargetLowering *TLI;
65
66 const ARMSubtarget *getST() const { return ST; }
67 const ARMTargetLowering *getTLI() const { return TLI; }
68
69public:
70 explicit ARMTTIImpl(const ARMBaseTargetMachine *TM, const Function &F)
71 : BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
72 TLI(ST->getTargetLowering()) {}
73
74 bool enableInterleavedAccessVectorization() const override { return true; }
75
76 TTI::AddressingModeKind
77 getPreferredAddressingMode(const Loop *L, ScalarEvolution *SE) const override;
78
79 /// Floating-point computation using ARMv8 AArch32 Advanced
80 /// SIMD instructions remains unchanged from ARMv7. Only AArch64 SIMD
81 /// and Arm MVE are IEEE-754 compliant.
82 bool isFPVectorizationPotentiallyUnsafe() const override {
83 return !ST->isTargetDarwin() && !ST->hasMVEFloatOps();
84 }
85
86 std::optional<Instruction *>
87 instCombineIntrinsic(InstCombiner &IC, IntrinsicInst &II) const override;
88 std::optional<Value *> simplifyDemandedVectorEltsIntrinsic(
89 InstCombiner &IC, IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts,
90 APInt &UndefElts2, APInt &UndefElts3,
91 std::function<void(Instruction *, unsigned, APInt, APInt &)>
92 SimplifyAndSetOp) const override;
93
94 /// \name Scalar TTI Implementations
95 /// @{
96
97 InstructionCost getIntImmCodeSizeCost(unsigned Opcode, unsigned Idx,
98 const APInt &Imm,
99 Type *Ty) const override;
100
101 using BaseT::getIntImmCost;
102 InstructionCost getIntImmCost(const APInt &Imm, Type *Ty,
103 TTI::TargetCostKind CostKind) const override;
104
105 InstructionCost getIntImmCostInst(unsigned Opcode, unsigned Idx,
106 const APInt &Imm, Type *Ty,
107 TTI::TargetCostKind CostKind,
108 Instruction *Inst = nullptr) const override;
109
110 /// @}
111
112 /// \name Vector TTI Implementations
113 /// @{
114
115 unsigned getNumberOfRegisters(unsigned ClassID) const override {
116 bool Vector = (ClassID == 1);
117 if (Vector) {
118 if (ST->hasNEON())
119 return 16;
120 if (ST->hasMVEIntegerOps())
121 return 8;
122 return 0;
123 }
124
125 if (ST->isThumb1Only())
126 return 8;
127 return 13;
128 }
129
130 TypeSize
131 getRegisterBitWidth(TargetTransformInfo::RegisterKind K) const override {
132 switch (K) {
133 case TargetTransformInfo::RGK_Scalar:
134 return TypeSize::getFixed(ExactSize: 32);
135 case TargetTransformInfo::RGK_FixedWidthVector:
136 if (ST->hasNEON())
137 return TypeSize::getFixed(ExactSize: 128);
138 if (ST->hasMVEIntegerOps())
139 return TypeSize::getFixed(ExactSize: 128);
140 return TypeSize::getFixed(ExactSize: 0);
141 case TargetTransformInfo::RGK_ScalableVector:
142 return TypeSize::getScalable(MinimumSize: 0);
143 }
144 llvm_unreachable("Unsupported register kind");
145 }
146
147 unsigned getMaxInterleaveFactor(ElementCount VF,
148 bool HasUnorderedReductions) const override {
149 return ST->getMaxInterleaveFactor();
150 }
151
152 bool isProfitableLSRChainElement(Instruction *I) const override;
153
154 bool
155 isLegalMaskedLoad(Type *DataTy, Align Alignment, unsigned AddressSpace,
156 TTI::MaskKind MaskKind =
157 TTI::MaskKind::VariableOrConstantMask) const override;
158
159 bool
160 isLegalMaskedStore(Type *DataTy, Align Alignment, unsigned AddressSpace,
161 TTI::MaskKind MaskKind =
162 TTI::MaskKind::VariableOrConstantMask) const override {
163 return isLegalMaskedLoad(DataTy, Alignment, AddressSpace, MaskKind);
164 }
165
166 bool forceScalarizeMaskedGather(VectorType *VTy,
167 Align Alignment) const override {
168 // For MVE, we have a custom lowering pass that will already have custom
169 // legalised any gathers that we can lower to MVE intrinsics, and want to
170 // expand all the rest. The pass runs before the masked intrinsic lowering
171 // pass.
172 return true;
173 }
174
175 bool forceScalarizeMaskedScatter(VectorType *VTy,
176 Align Alignment) const override {
177 return forceScalarizeMaskedGather(VTy, Alignment);
178 }
179
180 bool isLegalMaskedGather(Type *Ty, Align Alignment) const override;
181
182 bool isLegalMaskedScatter(Type *Ty, Align Alignment) const override {
183 return isLegalMaskedGather(Ty, Alignment);
184 }
185
186 InstructionCost getMemcpyCost(const Instruction *I) const override;
187
188 uint64_t getMaxMemIntrinsicInlineSizeThreshold() const override {
189 return ST->getMaxInlineSizeThreshold();
190 }
191
192 int getNumMemOps(const IntrinsicInst *I) const;
193
194 InstructionCost
195 getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy, VectorType *SrcTy,
196 ArrayRef<int> Mask, TTI::TargetCostKind CostKind, int Index,
197 VectorType *SubTp, ArrayRef<const Value *> Args = {},
198 const Instruction *CxtI = nullptr) const override;
199
200 bool preferInLoopReduction(RecurKind Kind, Type *Ty) const override;
201
202 bool preferPredicatedReductionSelect() const override;
203
204 bool shouldExpandReduction(const IntrinsicInst *II) const override {
205 return false;
206 }
207
208 InstructionCost getCFInstrCost(unsigned Opcode, TTI::TargetCostKind CostKind,
209 const Instruction *I = nullptr) const override;
210
211 InstructionCost
212 getCastInstrCost(unsigned Opcode, Type *Dst, Type *Src,
213 TTI::CastContextHint CCH, TTI::TargetCostKind CostKind,
214 const Instruction *I = nullptr) const override;
215
216 InstructionCost getCmpSelInstrCost(
217 unsigned Opcode, Type *ValTy, Type *CondTy, CmpInst::Predicate VecPred,
218 TTI::TargetCostKind CostKind,
219 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
220 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
221 const Instruction *I = nullptr) const override;
222
223 using BaseT::getVectorInstrCost;
224 InstructionCost
225 getVectorInstrCost(unsigned Opcode, Type *Val, TTI::TargetCostKind CostKind,
226 unsigned Index, const Value *Op0, const Value *Op1,
227 TTI::VectorInstrContext VIC =
228 TTI::VectorInstrContext::None) const override;
229
230 InstructionCost
231 getAddressComputationCost(Type *Val, ScalarEvolution *SE, const SCEV *Ptr,
232 TTI::TargetCostKind CostKind) const override;
233
234 InstructionCost getArithmeticInstrCost(
235 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
236 TTI::OperandValueInfo Op1Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
237 TTI::OperandValueInfo Op2Info = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
238 ArrayRef<const Value *> Args = {},
239 const Instruction *CxtI = nullptr) const override;
240
241 InstructionCost getMemoryOpCost(
242 unsigned Opcode, Type *Src, Align Alignment, unsigned AddressSpace,
243 TTI::TargetCostKind CostKind,
244 TTI::OperandValueInfo OpInfo = {.Kind: TTI::OK_AnyValue, .Properties: TTI::OP_None},
245 const Instruction *I = nullptr) const override;
246
247 InstructionCost
248 getMemIntrinsicInstrCost(const MemIntrinsicCostAttributes &MICA,
249 TTI::TargetCostKind CostKind) const override;
250
251 InstructionCost getMaskedMemoryOpCost(const MemIntrinsicCostAttributes &MICA,
252 TTI::TargetCostKind CostKind) const;
253
254 InstructionCost getInterleavedMemoryOpCost(
255 unsigned Opcode, Type *VecTy, unsigned Factor, ArrayRef<unsigned> Indices,
256 Align Alignment, unsigned AddressSpace, TTI::TargetCostKind CostKind,
257 bool UseMaskForCond = false, bool UseMaskForGaps = false) const override;
258
259 InstructionCost getGatherScatterOpCost(const MemIntrinsicCostAttributes &MICA,
260 TTI::TargetCostKind CostKind) const;
261
262 InstructionCost
263 getArithmeticReductionCost(unsigned Opcode, VectorType *ValTy,
264 std::optional<FastMathFlags> FMF,
265 TTI::TargetCostKind CostKind) const override;
266 InstructionCost
267 getExtendedReductionCost(unsigned Opcode, bool IsUnsigned, Type *ResTy,
268 VectorType *ValTy, std::optional<FastMathFlags> FMF,
269 TTI::TargetCostKind CostKind) const override;
270 InstructionCost
271 getMulAccReductionCost(bool IsUnsigned, unsigned RedOpcode, Type *ResTy,
272 VectorType *ValTy,
273 TTI::TargetCostKind CostKind) const override;
274
275 InstructionCost
276 getMinMaxReductionCost(Intrinsic::ID IID, VectorType *Ty, FastMathFlags FMF,
277 TTI::TargetCostKind CostKind) const override;
278
279 InstructionCost
280 getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
281 TTI::TargetCostKind CostKind) const override;
282
283 InstructionCost getPartialReductionCost(
284 unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
285 ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
286 TTI::PartialReductionExtendKind OpBExtend, std::optional<unsigned> BinOp,
287 TTI::TargetCostKind CostKind,
288 std::optional<FastMathFlags> FMF) const override {
289 return InstructionCost::getInvalid();
290 }
291
292 /// getScalingFactorCost - Return the cost of the scaling used in
293 /// addressing mode represented by AM.
294 /// If the AM is supported, the return value must be >= 0.
295 /// If the AM is not supported, the return value is an invalid cost.
296 InstructionCost getScalingFactorCost(Type *Ty, GlobalValue *BaseGV,
297 StackOffset BaseOffset, bool HasBaseReg,
298 int64_t Scale,
299 unsigned AddrSpace) const override;
300
301 bool maybeLoweredToCall(Instruction &I) const;
302 bool isLoweredToCall(const Function *F) const override;
303 bool isHardwareLoopProfitable(Loop *L, ScalarEvolution &SE,
304 AssumptionCache &AC, TargetLibraryInfo *LibInfo,
305 HardwareLoopInfo &HWLoopInfo) const override;
306 bool preferTailFoldingOverEpilogue(TailFoldingInfo *TFI) const override;
307 void getUnrollingPreferences(Loop *L, ScalarEvolution &SE,
308 TTI::UnrollingPreferences &UP,
309 OptimizationRemarkEmitter *ORE) const override;
310
311 TailFoldingStyle getPreferredTailFoldingStyle() const override;
312
313 void getPeelingPreferences(Loop *L, ScalarEvolution &SE,
314 TTI::PeelingPreferences &PP) const override;
315 bool shouldBuildLookupTablesForConstant(Constant *C) const override {
316 // In the ROPI and RWPI relocation models we can't have pointers to global
317 // variables or functions in constant data, so don't convert switches to
318 // lookup tables if any of the values would need relocation.
319 if (ST->isROPI() || ST->isRWPI())
320 return !C->needsDynamicRelocation();
321
322 return true;
323 }
324
325 bool shouldConsiderVectorizationRegPressure() const override;
326
327 bool hasArmWideBranch(bool Thumb) const override;
328
329 bool isProfitableToSinkOperands(Instruction *I,
330 SmallVectorImpl<Use *> &Ops) const override;
331
332 unsigned getNumBytesToPadGlobalArray(unsigned Size,
333 Type *ArrayType) const override;
334
335 /// @}
336};
337
338/// isVREVMask - Check if a vector shuffle corresponds to a VREV
339/// instruction with the specified blocksize. (The order of the elements
340/// within each block of the vector is reversed.)
341inline bool isVREVMask(ArrayRef<int> M, EVT VT, unsigned BlockSize) {
342 assert((BlockSize == 16 || BlockSize == 32 || BlockSize == 64) &&
343 "Only possible block sizes for VREV are: 16, 32, 64");
344
345 unsigned EltSz = VT.getScalarSizeInBits();
346 if (EltSz != 8 && EltSz != 16 && EltSz != 32)
347 return false;
348
349 unsigned BlockElts = M[0] + 1;
350 // If the first shuffle index is UNDEF, be optimistic.
351 if (M[0] < 0)
352 BlockElts = BlockSize / EltSz;
353
354 if (BlockSize <= EltSz || BlockSize != BlockElts * EltSz)
355 return false;
356
357 for (unsigned i = 0, e = M.size(); i < e; ++i) {
358 if (M[i] < 0)
359 continue; // ignore UNDEF indices
360 if ((unsigned)M[i] != (i - i % BlockElts) + (BlockElts - 1 - i % BlockElts))
361 return false;
362 }
363
364 return true;
365}
366
367} // end namespace llvm
368
369#endif // LLVM_LIB_TARGET_ARM_ARMTARGETTRANSFORMINFO_H
370