1//===-- LoongArchTargetTransformInfo.cpp - LoongArch 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/// \file
9/// This file implements a TargetTransformInfo analysis pass specific to the
10/// LoongArch 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#include "LoongArchTargetTransformInfo.h"
17#include "llvm/Analysis/TargetTransformInfo.h"
18#include "llvm/CodeGen/CostTable.h"
19#include "llvm/CodeGen/ISDOpcodes.h"
20#include "llvm/CodeGenTypes/MachineValueType.h"
21#include "llvm/IR/InstrTypes.h"
22#include "llvm/IR/Intrinsics.h"
23#include "llvm/Support/InstructionCost.h"
24#include <optional>
25
26using namespace llvm;
27
28#define DEBUG_TYPE "loongarchtti"
29
30namespace {
31struct CostKindCosts {
32 unsigned LatencyCost = ~0U;
33 unsigned RecipThroughputCost = ~0U;
34 unsigned CodeSizeCost = ~0U;
35 unsigned SizeAndLatencyCost = ~0U;
36
37 std::optional<unsigned>
38 operator[](TargetTransformInfo::TargetCostKind Kind) const {
39 unsigned Cost = ~0U;
40 switch (Kind) {
41 case llvm::TargetTransformInfo::TCK_Latency:
42 Cost = LatencyCost;
43 break;
44 case TargetTransformInfo::TCK_RecipThroughput:
45 Cost = RecipThroughputCost;
46 break;
47 case TargetTransformInfo::TCK_CodeSize:
48 Cost = CodeSizeCost;
49 break;
50 case TargetTransformInfo::TCK_SizeAndLatency:
51 Cost = SizeAndLatencyCost;
52 break;
53 }
54 if (Cost == ~0U)
55 return std::nullopt;
56 return Cost;
57 }
58};
59} // namespace
60using CostKindTblEntry = CostTblEntryT<CostKindCosts>;
61
62TypeSize LoongArchTTIImpl::getRegisterBitWidth(
63 TargetTransformInfo::RegisterKind K) const {
64 TypeSize DefSize = TargetTransformInfoImplBase::getRegisterBitWidth(K);
65 switch (K) {
66 case TargetTransformInfo::RGK_Scalar:
67 return TypeSize::getFixed(ExactSize: ST->is64Bit() ? 64 : 32);
68 case TargetTransformInfo::RGK_FixedWidthVector:
69 if (ST->hasExtLASX())
70 return TypeSize::getFixed(ExactSize: 256);
71 if (ST->hasExtLSX())
72 return TypeSize::getFixed(ExactSize: 128);
73 [[fallthrough]];
74 case TargetTransformInfo::RGK_ScalableVector:
75 return DefSize;
76 }
77
78 llvm_unreachable("Unsupported register kind");
79}
80
81unsigned LoongArchTTIImpl::getNumberOfRegisters(unsigned ClassID) const {
82 switch (ClassID) {
83 case LoongArchRegisterClass::GPRRC:
84 // 30 = 32 GPRs - r0 (zero register) - r21 (non-allocatable)
85 return 30;
86 case LoongArchRegisterClass::FPRRC:
87 return ST->hasBasicF() ? 32 : 0;
88 case LoongArchRegisterClass::VRRC:
89 return ST->hasExtLSX() ? 32 : 0;
90 }
91 llvm_unreachable("unknown register class");
92}
93
94unsigned LoongArchTTIImpl::getRegisterClassForType(bool Vector,
95 Type *Ty) const {
96 if (Vector)
97 return LoongArchRegisterClass::VRRC;
98 if (!Ty)
99 return LoongArchRegisterClass::GPRRC;
100
101 Type *ScalarTy = Ty->getScalarType();
102 if ((ScalarTy->isFloatTy() && ST->hasBasicF()) ||
103 (ScalarTy->isDoubleTy() && ST->hasBasicD())) {
104 return LoongArchRegisterClass::FPRRC;
105 }
106
107 return LoongArchRegisterClass::GPRRC;
108}
109
110unsigned
111LoongArchTTIImpl::getMaxInterleaveFactor(ElementCount VF,
112 bool HasUnorderedReductions) const {
113 return ST->getMaxInterleaveFactor();
114}
115
116const char *LoongArchTTIImpl::getRegisterClassName(unsigned ClassID) const {
117 switch (ClassID) {
118 case LoongArchRegisterClass::GPRRC:
119 return "LoongArch::GPRRC";
120 case LoongArchRegisterClass::FPRRC:
121 return "LoongArch::FPRRC";
122 case LoongArchRegisterClass::VRRC:
123 return "LoongArch::VRRC";
124 }
125 llvm_unreachable("unknown register class");
126}
127
128TargetTransformInfo::PopcntSupportKind
129LoongArchTTIImpl::getPopcntSupport(unsigned TyWidth) const {
130 assert(isPowerOf2_32(TyWidth) && "Ty width must be power of 2");
131 return ST->hasExtLSX() ? TTI::PSK_FastHardware : TTI::PSK_Software;
132}
133
134unsigned LoongArchTTIImpl::getCacheLineSize() const { return 64; }
135
136unsigned LoongArchTTIImpl::getPrefetchDistance() const { return 200; }
137
138bool LoongArchTTIImpl::enableWritePrefetching() const { return true; }
139
140bool LoongArchTTIImpl::shouldExpandReduction(const IntrinsicInst *II) const {
141 switch (II->getIntrinsicID()) {
142 default:
143 return true;
144 case Intrinsic::vector_reduce_add:
145 case Intrinsic::vector_reduce_and:
146 case Intrinsic::vector_reduce_or:
147 case Intrinsic::vector_reduce_smax:
148 case Intrinsic::vector_reduce_smin:
149 case Intrinsic::vector_reduce_umax:
150 case Intrinsic::vector_reduce_umin:
151 case Intrinsic::vector_reduce_xor:
152 return false;
153 }
154}
155
156LoongArchTTIImpl::TTI::MemCmpExpansionOptions
157LoongArchTTIImpl::enableMemCmpExpansion(bool OptSize, bool IsZeroCmp) const {
158 TTI::MemCmpExpansionOptions Options;
159
160 if (!ST->hasUAL())
161 return Options;
162
163 Options.MaxNumLoads = TLI->getMaxExpandSizeMemcmp(OptSize);
164 Options.NumLoadsPerBlock = IsZeroCmp ? Options.MaxNumLoads : 1;
165 Options.AllowOverlappingLoads = true;
166
167 // TODO: Support for vectors.
168 if (ST->is64Bit()) {
169 Options.LoadSizes = {8, 4, 2, 1};
170 Options.AllowedTailExpansions = {3, 5, 6};
171 } else {
172 Options.LoadSizes = {4, 2, 1};
173 Options.AllowedTailExpansions = {3};
174 }
175
176 return Options;
177}
178
179InstructionCost LoongArchTTIImpl::getArithmeticInstrCost(
180 unsigned Opcode, Type *Ty, TTI::TargetCostKind CostKind,
181 TTI::OperandValueInfo Op1Info, TTI::OperandValueInfo Op2Info,
182 ArrayRef<const Value *> Args, const Instruction *CxtI) const {
183
184 std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Ty);
185 int ISD = TLI->InstructionOpcodeToISD(Opcode);
186
187 // Vector multiply by pow2 will be simplified to shifts.
188 // Vector multiply by -pow2 will be simplified to shifts/negates.
189 if (ISD == ISD::MUL && Op2Info.isConstant() &&
190 (Op2Info.isPowerOf2() || Op2Info.isNegatedPowerOf2())) {
191 InstructionCost Cost =
192 getArithmeticInstrCost(Opcode: Instruction::Shl, Ty, CostKind,
193 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
194 if (Op2Info.isNegatedPowerOf2())
195 Cost += getArithmeticInstrCost(Opcode: Instruction::Sub, Ty, CostKind);
196 return Cost;
197 }
198
199 // On LoongArch, vector signed division by constants power-of-two are
200 // normally expanded to the sequence SRA + SRL + ADD + SRA.
201 // The OperandValue properties may not be the same as that of the previous
202 // operation; conservatively assume OP_None.
203 if ((ISD == ISD::SDIV || ISD == ISD::SREM) && Op2Info.isConstant() &&
204 Op2Info.isPowerOf2()) {
205 InstructionCost Cost =
206 2 * getArithmeticInstrCost(Opcode: Instruction::AShr, Ty, CostKind,
207 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
208 Cost += getArithmeticInstrCost(Opcode: Instruction::LShr, Ty, CostKind,
209 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
210 Cost += getArithmeticInstrCost(Opcode: Instruction::Add, Ty, CostKind,
211 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
212
213 if (ISD == ISD::SREM) {
214 // For SREM: (X % C) is the equivalent of (X - (X/C)*C)
215 Cost +=
216 getArithmeticInstrCost(Opcode: Instruction::Mul, Ty, CostKind,
217 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
218 Cost +=
219 getArithmeticInstrCost(Opcode: Instruction::Sub, Ty, CostKind,
220 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
221 }
222
223 return Cost;
224 }
225 // Vector unsigned division/remainder will be simplified to shifts/masks.
226 if ((ISD == ISD::UDIV || ISD == ISD::UREM) && Op2Info.isConstant() &&
227 Op2Info.isPowerOf2()) {
228 if (ISD == ISD::UDIV)
229 return getArithmeticInstrCost(Opcode: Instruction::LShr, Ty, CostKind,
230 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
231 // UREM
232 return getArithmeticInstrCost(Opcode: Instruction::And, Ty, CostKind,
233 Op1Info: Op1Info.getNoProps(), Op2Info: Op2Info.getNoProps());
234 }
235
236 static const CostKindTblEntry LSXCostTable[]{
237 {.ISD: ISD::ADD, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vaddi.b/vadd.b
238 {.ISD: ISD::ADD, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vaddi.h/vadd.h
239 {.ISD: ISD::ADD, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vaddi.w/vadd.w
240 {.ISD: ISD::ADD, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vaddi.d/vadd.d
241
242 {.ISD: ISD::SUB, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsubi.b/vsub.b
243 {.ISD: ISD::SUB, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsubi.h/vsub.h
244 {.ISD: ISD::SUB, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsubi.w/vsub.w
245 {.ISD: ISD::SUB, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsubi.d/vsub.d
246
247 {.ISD: ISD::MUL, .Type: MVT::v16i8, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // vmul.b
248 {.ISD: ISD::MUL, .Type: MVT::v8i16, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // vmul.h
249 {.ISD: ISD::MUL, .Type: MVT::v4i32, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // vmul.w
250 {.ISD: ISD::MUL, .Type: MVT::v2i64, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // vmul.d
251
252 {.ISD: ISD::SDIV, .Type: MVT::v16i8, .Cost: {.LatencyCost: 29, .RecipThroughputCost: 62}}, // vdiv.b
253 {.ISD: ISD::SDIV, .Type: MVT::v8i16, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 34}}, // vdiv.h
254 {.ISD: ISD::SDIV, .Type: MVT::v4i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // vdiv.w
255 {.ISD: ISD::SDIV, .Type: MVT::v2i64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // vdiv.d
256
257 {.ISD: ISD::UDIV, .Type: MVT::v16i8, .Cost: {.LatencyCost: 29, .RecipThroughputCost: 66}}, // vdiv.bu
258 {.ISD: ISD::UDIV, .Type: MVT::v8i16, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 36}}, // vdiv.hu
259 {.ISD: ISD::UDIV, .Type: MVT::v4i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // vdiv.wu
260 {.ISD: ISD::UDIV, .Type: MVT::v2i64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // vdiv.du
261
262 {.ISD: ISD::SREM, .Type: MVT::v16i8, .Cost: {.LatencyCost: 38, .RecipThroughputCost: 76}}, // vmod.b
263 {.ISD: ISD::SREM, .Type: MVT::v8i16, .Cost: {.LatencyCost: 24, .RecipThroughputCost: 44}}, // vmod.h
264 {.ISD: ISD::SREM, .Type: MVT::v4i32, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 27}}, // vmod.w
265 {.ISD: ISD::SREM, .Type: MVT::v2i64, .Cost: {.LatencyCost: 14, .RecipThroughputCost: 19}}, // vmod.d
266
267 {.ISD: ISD::UREM, .Type: MVT::v16i8, .Cost: {.LatencyCost: 38, .RecipThroughputCost: 80}}, // vmod.bu
268 {.ISD: ISD::UREM, .Type: MVT::v8i16, .Cost: {.LatencyCost: 24, .RecipThroughputCost: 44}}, // vmod.hu
269 {.ISD: ISD::UREM, .Type: MVT::v4i32, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 28}}, // vmod.wu
270 {.ISD: ISD::UREM, .Type: MVT::v2i64, .Cost: {.LatencyCost: 14, .RecipThroughputCost: 19}}, // vmod.du
271
272 {.ISD: ISD::SHL, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vslli.b/vsll.b
273 {.ISD: ISD::SHL, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vslli.h/vsll.h
274 {.ISD: ISD::SHL, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vslli.w/vsll.w
275 {.ISD: ISD::SHL, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vslli.d/vsll.d
276
277 {.ISD: ISD::SRL, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrli.b/vsrl.b
278 {.ISD: ISD::SRL, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrli.h/vsrl.h
279 {.ISD: ISD::SRL, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrli.w/vsrl.w
280 {.ISD: ISD::SRL, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrli.d/vsrl.d
281
282 {.ISD: ISD::SRA, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrai.b/vsra.b
283 {.ISD: ISD::SRA, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrai.h/vsra.h
284 {.ISD: ISD::SRA, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrai.w/vsra.w
285 {.ISD: ISD::SRA, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vsrai.d/vsra.d
286
287 {.ISD: ISD::AND, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vand.b/vand.v
288 {.ISD: ISD::AND, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vand.v
289 {.ISD: ISD::AND, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vand.v
290 {.ISD: ISD::AND, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vand.v
291
292 {.ISD: ISD::OR, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vori.b/vor.v
293 {.ISD: ISD::OR, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vor.v
294 {.ISD: ISD::OR, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vor.v
295 {.ISD: ISD::OR, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vor.v
296
297 {.ISD: ISD::XOR, .Type: MVT::v16i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vxori.b/vxor.v
298 {.ISD: ISD::XOR, .Type: MVT::v8i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vxor.v
299 {.ISD: ISD::XOR, .Type: MVT::v4i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vxor.v
300 {.ISD: ISD::XOR, .Type: MVT::v2i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // vxor.v
301
302 {.ISD: ISD::FADD, .Type: MVT::v4f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // vfadd.s
303 {.ISD: ISD::FADD, .Type: MVT::v2f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // vfadd.d
304
305 {.ISD: ISD::FSUB, .Type: MVT::v4f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // vfsub.s
306 {.ISD: ISD::FSUB, .Type: MVT::v2f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // vfsub.d
307
308 {.ISD: ISD::FMUL, .Type: MVT::v4f32, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // vfmul.s
309 {.ISD: ISD::FMUL, .Type: MVT::v2f64, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // vfmul.d
310
311 {.ISD: ISD::FDIV, .Type: MVT::v4f32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // vfdiv.s
312 {.ISD: ISD::FDIV, .Type: MVT::v2f64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // vfdiv.d
313 };
314
315 if (ST->hasExtLSX()) {
316 if (const auto *Entry = CostTableLookup(Table: LSXCostTable, ISD, Ty: LT.second))
317 if (auto KindCost = Entry->Cost[CostKind])
318 return LT.first * *KindCost;
319 }
320
321 static const CostKindTblEntry LASXUniformConstCostTable[]{
322 {.ISD: ISD::ADD, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvaddi.b/xvadd.b
323 {.ISD: ISD::ADD, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvaddi.h/xvadd.h
324 {.ISD: ISD::ADD, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvaddi.w/xvadd.w
325 {.ISD: ISD::ADD, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvaddi.d/xvadd.d
326
327 {.ISD: ISD::SUB, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsubi.b/xvsub.b
328 {.ISD: ISD::SUB, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsubi.h/xvsub.h
329 {.ISD: ISD::SUB, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsubi.w/xvsub.w
330 {.ISD: ISD::SUB, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsubi.d/xvsub.d
331
332 {.ISD: ISD::MUL, .Type: MVT::v32i8, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // xvmul.b
333 {.ISD: ISD::MUL, .Type: MVT::v16i16, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // xvmul.h
334 {.ISD: ISD::MUL, .Type: MVT::v8i32, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // xvmul.w
335 {.ISD: ISD::MUL, .Type: MVT::v4i64, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // xvmul.d
336
337 {.ISD: ISD::SDIV, .Type: MVT::v32i8, .Cost: {.LatencyCost: 29, .RecipThroughputCost: 62}}, // xvdiv.b
338 {.ISD: ISD::SDIV, .Type: MVT::v16i16, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 34}}, // xvdiv.h
339 {.ISD: ISD::SDIV, .Type: MVT::v8i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // xvdiv.w
340 {.ISD: ISD::SDIV, .Type: MVT::v4i64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // xvdiv.d
341
342 {.ISD: ISD::UDIV, .Type: MVT::v32i8, .Cost: {.LatencyCost: 29, .RecipThroughputCost: 66}}, // xvdiv.bu
343 {.ISD: ISD::UDIV, .Type: MVT::v16i16, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 36}}, // xvdiv.hu
344 {.ISD: ISD::UDIV, .Type: MVT::v8i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // xvdiv.wu
345 {.ISD: ISD::UDIV, .Type: MVT::v4i64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // xvdiv.du
346
347 {.ISD: ISD::SREM, .Type: MVT::v32i8, .Cost: {.LatencyCost: 38, .RecipThroughputCost: 76}}, // xvmod.b
348 {.ISD: ISD::SREM, .Type: MVT::v16i16, .Cost: {.LatencyCost: 24, .RecipThroughputCost: 44}}, // xvmod.h
349 {.ISD: ISD::SREM, .Type: MVT::v8i32, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 28}}, // xvmod.w
350 {.ISD: ISD::SREM, .Type: MVT::v4i64, .Cost: {.LatencyCost: 14, .RecipThroughputCost: 19}}, // xvmod.d
351
352 {.ISD: ISD::UREM, .Type: MVT::v32i8, .Cost: {.LatencyCost: 38, .RecipThroughputCost: 76}}, // xvmod.bu
353 {.ISD: ISD::UREM, .Type: MVT::v16i16, .Cost: {.LatencyCost: 24, .RecipThroughputCost: 43}}, // xvmod.hu
354 {.ISD: ISD::UREM, .Type: MVT::v8i32, .Cost: {.LatencyCost: 17, .RecipThroughputCost: 28}}, // xvmod.wu
355 {.ISD: ISD::UREM, .Type: MVT::v4i64, .Cost: {.LatencyCost: 14, .RecipThroughputCost: 19}}, // xvmod.du
356
357 {.ISD: ISD::SHL, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvslli.b/xvsll.b
358 {.ISD: ISD::SHL, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvslli.h/xvsll.h
359 {.ISD: ISD::SHL, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvslli.w/xvsll.w
360 {.ISD: ISD::SHL, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvslli.d/xvsll.d
361
362 {.ISD: ISD::SRL, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrli.b/xvsrl.b
363 {.ISD: ISD::SRL, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrli.h/xvsrl.h
364 {.ISD: ISD::SRL, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrli.w/xvsrl.w
365 {.ISD: ISD::SRL, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrli.d/xvsrl.d
366
367 {.ISD: ISD::SRA, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrai.b/xvsra.b
368 {.ISD: ISD::SRA, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrai.h/xvsra.h
369 {.ISD: ISD::SRA, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrai.w/xvsra.w
370 {.ISD: ISD::SRA, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvsrai.d/xvsra.d
371
372 {.ISD: ISD::AND, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvandi.b/xvand.v
373 {.ISD: ISD::AND, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvand.v
374 {.ISD: ISD::AND, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvand.v
375 {.ISD: ISD::AND, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvand.v
376
377 {.ISD: ISD::OR, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvori.b/xvor.v
378 {.ISD: ISD::OR, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvor.v
379 {.ISD: ISD::OR, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvor.v
380 {.ISD: ISD::OR, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvor.v
381
382 {.ISD: ISD::XOR, .Type: MVT::v32i8, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvxori.b/xvxor.v
383 {.ISD: ISD::XOR, .Type: MVT::v16i16, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvxor.v
384 {.ISD: ISD::XOR, .Type: MVT::v8i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvxor.v
385 {.ISD: ISD::XOR, .Type: MVT::v4i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xvxor.v
386
387 {.ISD: ISD::FADD, .Type: MVT::v8f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // xvfadd.s
388 {.ISD: ISD::FADD, .Type: MVT::v4f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // xvfadd.d
389
390 {.ISD: ISD::FSUB, .Type: MVT::v8f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // xvfsub.s
391 {.ISD: ISD::FSUB, .Type: MVT::v4f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // xvfsub.d
392
393 {.ISD: ISD::FMUL, .Type: MVT::v8f32, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // xvfmul.s
394 {.ISD: ISD::FMUL, .Type: MVT::v4f64, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // xvfmul.d
395
396 {.ISD: ISD::FDIV, .Type: MVT::v8f32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 22}}, // xvfdiv.s
397 {.ISD: ISD::FDIV, .Type: MVT::v4f64, .Cost: {.LatencyCost: 8, .RecipThroughputCost: 16}}, // xvfdiv.d
398 };
399
400 if (ST->hasExtLASX()) {
401 if (const auto *Entry =
402 CostTableLookup(Table: LASXUniformConstCostTable, ISD, Ty: LT.second))
403 if (auto KindCost = Entry->Cost[CostKind])
404 return LT.first * *KindCost;
405 }
406
407 static const CostKindTblEntry LA64CostTable[]{
408 {.ISD: ISD::ADD, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // addi.d/add.d
409 {.ISD: ISD::SUB, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // subi.d/sub.d
410 {.ISD: ISD::MUL, .Type: MVT::i64, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // mul.d
411
412 {.ISD: ISD::SDIV, .Type: MVT::i64, .Cost: {.LatencyCost: 18, .RecipThroughputCost: 26}}, // div.d
413 {.ISD: ISD::UDIV, .Type: MVT::i64, .Cost: {.LatencyCost: 18, .RecipThroughputCost: 26}}, // div.du
414 {.ISD: ISD::SREM, .Type: MVT::i64, .Cost: {.LatencyCost: 18, .RecipThroughputCost: 26}}, // mod.d
415 {.ISD: ISD::UREM, .Type: MVT::i64, .Cost: {.LatencyCost: 18, .RecipThroughputCost: 26}}, // mod.du
416
417 {.ISD: ISD::SHL, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // slli.d/sll.d
418 {.ISD: ISD::SRL, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // srli.d/srl.d
419 {.ISD: ISD::SRA, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // srai.d/sra.d
420
421 {.ISD: ISD::AND, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // andi.d/and.d
422 {.ISD: ISD::OR, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // ori.d/or.d
423 {.ISD: ISD::XOR, .Type: MVT::i64, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xori.d/xor.d
424
425 {.ISD: ISD::FADD, .Type: MVT::f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // fadd.d
426 {.ISD: ISD::FSUB, .Type: MVT::f64, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // fsub.d
427 {.ISD: ISD::FMUL, .Type: MVT::f64, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // fmul.d
428 {.ISD: ISD::FDIV, .Type: MVT::f64, .Cost: {.LatencyCost: 12, .RecipThroughputCost: 9}}, // fdiv.d
429 };
430
431 if (ST->is64Bit()) {
432 if (const auto *Entry = CostTableLookup(Table: LA64CostTable, ISD, Ty: LT.second))
433 if (auto KindCost = Entry->Cost[CostKind])
434 return LT.first * *KindCost;
435 }
436
437 static const CostKindTblEntry LA32CostTable[]{
438 {.ISD: ISD::ADD, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // addi.w/add.w
439 {.ISD: ISD::SUB, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // subi.w/sub.w
440 {.ISD: ISD::MUL, .Type: MVT::i32, .Cost: {.LatencyCost: 4, .RecipThroughputCost: 2}}, // mul.w
441
442 {.ISD: ISD::SDIV, .Type: MVT::i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 24}}, // div.w
443 {.ISD: ISD::UDIV, .Type: MVT::i32, .Cost: {.LatencyCost: 12, .RecipThroughputCost: 24}}, // div.wu
444 {.ISD: ISD::SREM, .Type: MVT::i32, .Cost: {.LatencyCost: 11, .RecipThroughputCost: 24}}, // mod.w
445 {.ISD: ISD::UREM, .Type: MVT::i32, .Cost: {.LatencyCost: 12, .RecipThroughputCost: 24}}, // mod.wu
446
447 {.ISD: ISD::SHL, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // slli.w/sll.w
448 {.ISD: ISD::SRL, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // srli.w/srl.w
449 {.ISD: ISD::SRA, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // srai.w/sra.w
450
451 {.ISD: ISD::AND, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // andi.w/and.w
452 {.ISD: ISD::OR, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // ori.w/or.w
453 {.ISD: ISD::XOR, .Type: MVT::i32, .Cost: {.LatencyCost: 1, .RecipThroughputCost: 1}}, // xori.w/xor.w
454
455 {.ISD: ISD::FADD, .Type: MVT::f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // fadd.s
456 {.ISD: ISD::FSUB, .Type: MVT::f32, .Cost: {.LatencyCost: 3, .RecipThroughputCost: 1}}, // fsub.s
457 {.ISD: ISD::FMUL, .Type: MVT::f32, .Cost: {.LatencyCost: 5, .RecipThroughputCost: 2}}, // fmul.s
458 {.ISD: ISD::FDIV, .Type: MVT::f32, .Cost: {.LatencyCost: 9, .RecipThroughputCost: 8}}, // fdiv.s
459 };
460
461 if (const auto *Entry = CostTableLookup(Table: LA32CostTable, ISD, Ty: LT.second))
462 if (auto KindCost = Entry->Cost[CostKind])
463 return LT.first * *KindCost;
464
465 // Fallback to the default implementation.
466 return BaseT::getArithmeticInstrCost(Opcode, Ty, CostKind, Opd1Info: Op1Info, Opd2Info: Op2Info,
467 Args, CtxI: CxtI);
468}
469