AMDGPU: Mark test as XFAIL in expensive_checks builds
[llvm-project.git] / llvm / lib / CodeGen / GlobalISel / LegalizerHelper.cpp
blobd0a62340a5f3227ff0b9e127856ab8a2f02a34fa
1 //===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
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 This file implements the LegalizerHelper class to legalize
10 /// individual instructions and the LegalizeMachineIR wrapper pass for the
11 /// primary legalization.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
16 #include "llvm/CodeGen/GlobalISel/CallLowering.h"
17 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
18 #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
19 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
20 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
21 #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
22 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24 #include "llvm/CodeGen/GlobalISel/Utils.h"
25 #include "llvm/CodeGen/LowLevelTypeUtils.h"
26 #include "llvm/CodeGen/MachineConstantPool.h"
27 #include "llvm/CodeGen/MachineFrameInfo.h"
28 #include "llvm/CodeGen/MachineRegisterInfo.h"
29 #include "llvm/CodeGen/RuntimeLibcallUtil.h"
30 #include "llvm/CodeGen/TargetFrameLowering.h"
31 #include "llvm/CodeGen/TargetInstrInfo.h"
32 #include "llvm/CodeGen/TargetLowering.h"
33 #include "llvm/CodeGen/TargetOpcodes.h"
34 #include "llvm/CodeGen/TargetSubtargetInfo.h"
35 #include "llvm/IR/Instructions.h"
36 #include "llvm/Support/Debug.h"
37 #include "llvm/Support/MathExtras.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Target/TargetMachine.h"
40 #include <numeric>
41 #include <optional>
43 #define DEBUG_TYPE "legalizer"
45 using namespace llvm;
46 using namespace LegalizeActions;
47 using namespace MIPatternMatch;
49 /// Try to break down \p OrigTy into \p NarrowTy sized pieces.
50 ///
51 /// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
52 /// with any leftover piece as type \p LeftoverTy
53 ///
54 /// Returns -1 in the first element of the pair if the breakdown is not
55 /// satisfiable.
56 static std::pair<int, int>
57 getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
58 assert(!LeftoverTy.isValid() && "this is an out argument");
60 unsigned Size = OrigTy.getSizeInBits();
61 unsigned NarrowSize = NarrowTy.getSizeInBits();
62 unsigned NumParts = Size / NarrowSize;
63 unsigned LeftoverSize = Size - NumParts * NarrowSize;
64 assert(Size > NarrowSize);
66 if (LeftoverSize == 0)
67 return {NumParts, 0};
69 if (NarrowTy.isVector()) {
70 unsigned EltSize = OrigTy.getScalarSizeInBits();
71 if (LeftoverSize % EltSize != 0)
72 return {-1, -1};
73 LeftoverTy =
74 LLT::scalarOrVector(ElementCount::getFixed(LeftoverSize / EltSize),
75 OrigTy.getElementType());
76 } else {
77 LeftoverTy = LLT::scalar(LeftoverSize);
80 int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
81 return std::make_pair(NumParts, NumLeftover);
84 static Type *getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty) {
86 if (!Ty.isScalar())
87 return nullptr;
89 switch (Ty.getSizeInBits()) {
90 case 16:
91 return Type::getHalfTy(Ctx);
92 case 32:
93 return Type::getFloatTy(Ctx);
94 case 64:
95 return Type::getDoubleTy(Ctx);
96 case 80:
97 return Type::getX86_FP80Ty(Ctx);
98 case 128:
99 return Type::getFP128Ty(Ctx);
100 default:
101 return nullptr;
105 LegalizerHelper::LegalizerHelper(MachineFunction &MF,
106 GISelChangeObserver &Observer,
107 MachineIRBuilder &Builder)
108 : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
109 LI(*MF.getSubtarget().getLegalizerInfo()),
110 TLI(*MF.getSubtarget().getTargetLowering()), KB(nullptr) {}
112 LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
113 GISelChangeObserver &Observer,
114 MachineIRBuilder &B, GISelKnownBits *KB)
115 : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
116 TLI(*MF.getSubtarget().getTargetLowering()), KB(KB) {}
118 LegalizerHelper::LegalizeResult
119 LegalizerHelper::legalizeInstrStep(MachineInstr &MI,
120 LostDebugLocObserver &LocObserver) {
121 LLVM_DEBUG(dbgs() << "Legalizing: " << MI);
123 MIRBuilder.setInstrAndDebugLoc(MI);
125 if (isa<GIntrinsic>(MI))
126 return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
127 auto Step = LI.getAction(MI, MRI);
128 switch (Step.Action) {
129 case Legal:
130 LLVM_DEBUG(dbgs() << ".. Already legal\n");
131 return AlreadyLegal;
132 case Libcall:
133 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
134 return libcall(MI, LocObserver);
135 case NarrowScalar:
136 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
137 return narrowScalar(MI, Step.TypeIdx, Step.NewType);
138 case WidenScalar:
139 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
140 return widenScalar(MI, Step.TypeIdx, Step.NewType);
141 case Bitcast:
142 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
143 return bitcast(MI, Step.TypeIdx, Step.NewType);
144 case Lower:
145 LLVM_DEBUG(dbgs() << ".. Lower\n");
146 return lower(MI, Step.TypeIdx, Step.NewType);
147 case FewerElements:
148 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
149 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
150 case MoreElements:
151 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
152 return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
153 case Custom:
154 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
155 return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
156 : UnableToLegalize;
157 default:
158 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
159 return UnableToLegalize;
163 void LegalizerHelper::insertParts(Register DstReg,
164 LLT ResultTy, LLT PartTy,
165 ArrayRef<Register> PartRegs,
166 LLT LeftoverTy,
167 ArrayRef<Register> LeftoverRegs) {
168 if (!LeftoverTy.isValid()) {
169 assert(LeftoverRegs.empty());
171 if (!ResultTy.isVector()) {
172 MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
173 return;
176 if (PartTy.isVector())
177 MIRBuilder.buildConcatVectors(DstReg, PartRegs);
178 else
179 MIRBuilder.buildBuildVector(DstReg, PartRegs);
180 return;
183 // Merge sub-vectors with different number of elements and insert into DstReg.
184 if (ResultTy.isVector()) {
185 assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
186 SmallVector<Register, 8> AllRegs(PartRegs.begin(), PartRegs.end());
187 AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());
188 return mergeMixedSubvectors(DstReg, AllRegs);
191 SmallVector<Register> GCDRegs;
192 LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
193 for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
194 extractGCDType(GCDRegs, GCDTy, PartReg);
195 LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
196 buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
199 void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
200 Register Reg) {
201 LLT Ty = MRI.getType(Reg);
202 SmallVector<Register, 8> RegElts;
203 extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
204 MIRBuilder, MRI);
205 Elts.append(RegElts);
208 /// Merge \p PartRegs with different types into \p DstReg.
209 void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
210 ArrayRef<Register> PartRegs) {
211 SmallVector<Register, 8> AllElts;
212 for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
213 appendVectorElts(AllElts, PartRegs[i]);
215 Register Leftover = PartRegs[PartRegs.size() - 1];
216 if (!MRI.getType(Leftover).isVector())
217 AllElts.push_back(Leftover);
218 else
219 appendVectorElts(AllElts, Leftover);
221 MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
224 /// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
225 static void getUnmergeResults(SmallVectorImpl<Register> &Regs,
226 const MachineInstr &MI) {
227 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
229 const int StartIdx = Regs.size();
230 const int NumResults = MI.getNumOperands() - 1;
231 Regs.resize(Regs.size() + NumResults);
232 for (int I = 0; I != NumResults; ++I)
233 Regs[StartIdx + I] = MI.getOperand(I).getReg();
236 void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
237 LLT GCDTy, Register SrcReg) {
238 LLT SrcTy = MRI.getType(SrcReg);
239 if (SrcTy == GCDTy) {
240 // If the source already evenly divides the result type, we don't need to do
241 // anything.
242 Parts.push_back(SrcReg);
243 } else {
244 // Need to split into common type sized pieces.
245 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
246 getUnmergeResults(Parts, *Unmerge);
250 LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
251 LLT NarrowTy, Register SrcReg) {
252 LLT SrcTy = MRI.getType(SrcReg);
253 LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
254 extractGCDType(Parts, GCDTy, SrcReg);
255 return GCDTy;
258 LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
259 SmallVectorImpl<Register> &VRegs,
260 unsigned PadStrategy) {
261 LLT LCMTy = getLCMType(DstTy, NarrowTy);
263 int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
264 int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
265 int NumOrigSrc = VRegs.size();
267 Register PadReg;
269 // Get a value we can use to pad the source value if the sources won't evenly
270 // cover the result type.
271 if (NumOrigSrc < NumParts * NumSubParts) {
272 if (PadStrategy == TargetOpcode::G_ZEXT)
273 PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
274 else if (PadStrategy == TargetOpcode::G_ANYEXT)
275 PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
276 else {
277 assert(PadStrategy == TargetOpcode::G_SEXT);
279 // Shift the sign bit of the low register through the high register.
280 auto ShiftAmt =
281 MIRBuilder.buildConstant(LLT::scalar(64), GCDTy.getSizeInBits() - 1);
282 PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
286 // Registers for the final merge to be produced.
287 SmallVector<Register, 4> Remerge(NumParts);
289 // Registers needed for intermediate merges, which will be merged into a
290 // source for Remerge.
291 SmallVector<Register, 4> SubMerge(NumSubParts);
293 // Once we've fully read off the end of the original source bits, we can reuse
294 // the same high bits for remaining padding elements.
295 Register AllPadReg;
297 // Build merges to the LCM type to cover the original result type.
298 for (int I = 0; I != NumParts; ++I) {
299 bool AllMergePartsArePadding = true;
301 // Build the requested merges to the requested type.
302 for (int J = 0; J != NumSubParts; ++J) {
303 int Idx = I * NumSubParts + J;
304 if (Idx >= NumOrigSrc) {
305 SubMerge[J] = PadReg;
306 continue;
309 SubMerge[J] = VRegs[Idx];
311 // There are meaningful bits here we can't reuse later.
312 AllMergePartsArePadding = false;
315 // If we've filled up a complete piece with padding bits, we can directly
316 // emit the natural sized constant if applicable, rather than a merge of
317 // smaller constants.
318 if (AllMergePartsArePadding && !AllPadReg) {
319 if (PadStrategy == TargetOpcode::G_ANYEXT)
320 AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
321 else if (PadStrategy == TargetOpcode::G_ZEXT)
322 AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
324 // If this is a sign extension, we can't materialize a trivial constant
325 // with the right type and have to produce a merge.
328 if (AllPadReg) {
329 // Avoid creating additional instructions if we're just adding additional
330 // copies of padding bits.
331 Remerge[I] = AllPadReg;
332 continue;
335 if (NumSubParts == 1)
336 Remerge[I] = SubMerge[0];
337 else
338 Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
340 // In the sign extend padding case, re-use the first all-signbit merge.
341 if (AllMergePartsArePadding && !AllPadReg)
342 AllPadReg = Remerge[I];
345 VRegs = std::move(Remerge);
346 return LCMTy;
349 void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
350 ArrayRef<Register> RemergeRegs) {
351 LLT DstTy = MRI.getType(DstReg);
353 // Create the merge to the widened source, and extract the relevant bits into
354 // the result.
356 if (DstTy == LCMTy) {
357 MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
358 return;
361 auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
362 if (DstTy.isScalar() && LCMTy.isScalar()) {
363 MIRBuilder.buildTrunc(DstReg, Remerge);
364 return;
367 if (LCMTy.isVector()) {
368 unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
369 SmallVector<Register, 8> UnmergeDefs(NumDefs);
370 UnmergeDefs[0] = DstReg;
371 for (unsigned I = 1; I != NumDefs; ++I)
372 UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
374 MIRBuilder.buildUnmerge(UnmergeDefs,
375 MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
376 return;
379 llvm_unreachable("unhandled case");
382 static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
383 #define RTLIBCASE_INT(LibcallPrefix) \
384 do { \
385 switch (Size) { \
386 case 32: \
387 return RTLIB::LibcallPrefix##32; \
388 case 64: \
389 return RTLIB::LibcallPrefix##64; \
390 case 128: \
391 return RTLIB::LibcallPrefix##128; \
392 default: \
393 llvm_unreachable("unexpected size"); \
395 } while (0)
397 #define RTLIBCASE(LibcallPrefix) \
398 do { \
399 switch (Size) { \
400 case 32: \
401 return RTLIB::LibcallPrefix##32; \
402 case 64: \
403 return RTLIB::LibcallPrefix##64; \
404 case 80: \
405 return RTLIB::LibcallPrefix##80; \
406 case 128: \
407 return RTLIB::LibcallPrefix##128; \
408 default: \
409 llvm_unreachable("unexpected size"); \
411 } while (0)
413 switch (Opcode) {
414 case TargetOpcode::G_MUL:
415 RTLIBCASE_INT(MUL_I);
416 case TargetOpcode::G_SDIV:
417 RTLIBCASE_INT(SDIV_I);
418 case TargetOpcode::G_UDIV:
419 RTLIBCASE_INT(UDIV_I);
420 case TargetOpcode::G_SREM:
421 RTLIBCASE_INT(SREM_I);
422 case TargetOpcode::G_UREM:
423 RTLIBCASE_INT(UREM_I);
424 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
425 RTLIBCASE_INT(CTLZ_I);
426 case TargetOpcode::G_FADD:
427 RTLIBCASE(ADD_F);
428 case TargetOpcode::G_FSUB:
429 RTLIBCASE(SUB_F);
430 case TargetOpcode::G_FMUL:
431 RTLIBCASE(MUL_F);
432 case TargetOpcode::G_FDIV:
433 RTLIBCASE(DIV_F);
434 case TargetOpcode::G_FEXP:
435 RTLIBCASE(EXP_F);
436 case TargetOpcode::G_FEXP2:
437 RTLIBCASE(EXP2_F);
438 case TargetOpcode::G_FEXP10:
439 RTLIBCASE(EXP10_F);
440 case TargetOpcode::G_FREM:
441 RTLIBCASE(REM_F);
442 case TargetOpcode::G_FPOW:
443 RTLIBCASE(POW_F);
444 case TargetOpcode::G_FPOWI:
445 RTLIBCASE(POWI_F);
446 case TargetOpcode::G_FMA:
447 RTLIBCASE(FMA_F);
448 case TargetOpcode::G_FSIN:
449 RTLIBCASE(SIN_F);
450 case TargetOpcode::G_FCOS:
451 RTLIBCASE(COS_F);
452 case TargetOpcode::G_FTAN:
453 RTLIBCASE(TAN_F);
454 case TargetOpcode::G_FASIN:
455 RTLIBCASE(ASIN_F);
456 case TargetOpcode::G_FACOS:
457 RTLIBCASE(ACOS_F);
458 case TargetOpcode::G_FATAN:
459 RTLIBCASE(ATAN_F);
460 case TargetOpcode::G_FATAN2:
461 RTLIBCASE(ATAN2_F);
462 case TargetOpcode::G_FSINH:
463 RTLIBCASE(SINH_F);
464 case TargetOpcode::G_FCOSH:
465 RTLIBCASE(COSH_F);
466 case TargetOpcode::G_FTANH:
467 RTLIBCASE(TANH_F);
468 case TargetOpcode::G_FLOG10:
469 RTLIBCASE(LOG10_F);
470 case TargetOpcode::G_FLOG:
471 RTLIBCASE(LOG_F);
472 case TargetOpcode::G_FLOG2:
473 RTLIBCASE(LOG2_F);
474 case TargetOpcode::G_FLDEXP:
475 RTLIBCASE(LDEXP_F);
476 case TargetOpcode::G_FCEIL:
477 RTLIBCASE(CEIL_F);
478 case TargetOpcode::G_FFLOOR:
479 RTLIBCASE(FLOOR_F);
480 case TargetOpcode::G_FMINNUM:
481 RTLIBCASE(FMIN_F);
482 case TargetOpcode::G_FMAXNUM:
483 RTLIBCASE(FMAX_F);
484 case TargetOpcode::G_FSQRT:
485 RTLIBCASE(SQRT_F);
486 case TargetOpcode::G_FRINT:
487 RTLIBCASE(RINT_F);
488 case TargetOpcode::G_FNEARBYINT:
489 RTLIBCASE(NEARBYINT_F);
490 case TargetOpcode::G_INTRINSIC_TRUNC:
491 RTLIBCASE(TRUNC_F);
492 case TargetOpcode::G_INTRINSIC_ROUND:
493 RTLIBCASE(ROUND_F);
494 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
495 RTLIBCASE(ROUNDEVEN_F);
496 case TargetOpcode::G_INTRINSIC_LRINT:
497 RTLIBCASE(LRINT_F);
498 case TargetOpcode::G_INTRINSIC_LLRINT:
499 RTLIBCASE(LLRINT_F);
501 llvm_unreachable("Unknown libcall function");
502 #undef RTLIBCASE_INT
503 #undef RTLIBCASE
506 /// True if an instruction is in tail position in its caller. Intended for
507 /// legalizing libcalls as tail calls when possible.
508 static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result,
509 MachineInstr &MI,
510 const TargetInstrInfo &TII,
511 MachineRegisterInfo &MRI) {
512 MachineBasicBlock &MBB = *MI.getParent();
513 const Function &F = MBB.getParent()->getFunction();
515 // Conservatively require the attributes of the call to match those of
516 // the return. Ignore NoAlias and NonNull because they don't affect the
517 // call sequence.
518 AttributeList CallerAttrs = F.getAttributes();
519 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
520 .removeAttribute(Attribute::NoAlias)
521 .removeAttribute(Attribute::NonNull)
522 .hasAttributes())
523 return false;
525 // It's not safe to eliminate the sign / zero extension of the return value.
526 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
527 CallerAttrs.hasRetAttr(Attribute::SExt))
528 return false;
530 // Only tail call if the following instruction is a standard return or if we
531 // have a `thisreturn` callee, and a sequence like:
533 // G_MEMCPY %0, %1, %2
534 // $x0 = COPY %0
535 // RET_ReallyLR implicit $x0
536 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
537 if (Next != MBB.instr_end() && Next->isCopy()) {
538 if (MI.getOpcode() == TargetOpcode::G_BZERO)
539 return false;
541 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
542 // mempy/etc routines return the same parameter. For other it will be the
543 // returned value.
544 Register VReg = MI.getOperand(0).getReg();
545 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
546 return false;
548 Register PReg = Next->getOperand(0).getReg();
549 if (!PReg.isPhysical())
550 return false;
552 auto Ret = next_nodbg(Next, MBB.instr_end());
553 if (Ret == MBB.instr_end() || !Ret->isReturn())
554 return false;
556 if (Ret->getNumImplicitOperands() != 1)
557 return false;
559 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
560 return false;
562 // Skip over the COPY that we just validated.
563 Next = Ret;
566 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
567 return false;
569 return true;
572 LegalizerHelper::LegalizeResult
573 llvm::createLibcall(MachineIRBuilder &MIRBuilder, const char *Name,
574 const CallLowering::ArgInfo &Result,
575 ArrayRef<CallLowering::ArgInfo> Args,
576 const CallingConv::ID CC, LostDebugLocObserver &LocObserver,
577 MachineInstr *MI) {
578 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
580 CallLowering::CallLoweringInfo Info;
581 Info.CallConv = CC;
582 Info.Callee = MachineOperand::CreateES(Name);
583 Info.OrigRet = Result;
584 if (MI)
585 Info.IsTailCall =
586 (Result.Ty->isVoidTy() ||
587 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
588 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
589 *MIRBuilder.getMRI());
591 std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
592 if (!CLI.lowerCall(MIRBuilder, Info))
593 return LegalizerHelper::UnableToLegalize;
595 if (MI && Info.LoweredTailCall) {
596 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
598 // Check debug locations before removing the return.
599 LocObserver.checkpoint(true);
601 // We must have a return following the call (or debug insts) to get past
602 // isLibCallInTailPosition.
603 do {
604 MachineInstr *Next = MI->getNextNode();
605 assert(Next &&
606 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
607 "Expected instr following MI to be return or debug inst?");
608 // We lowered a tail call, so the call is now the return from the block.
609 // Delete the old return.
610 Next->eraseFromParent();
611 } while (MI->getNextNode());
613 // We expect to lose the debug location from the return.
614 LocObserver.checkpoint(false);
616 return LegalizerHelper::Legalized;
619 LegalizerHelper::LegalizeResult
620 llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
621 const CallLowering::ArgInfo &Result,
622 ArrayRef<CallLowering::ArgInfo> Args,
623 LostDebugLocObserver &LocObserver, MachineInstr *MI) {
624 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
625 const char *Name = TLI.getLibcallName(Libcall);
626 if (!Name)
627 return LegalizerHelper::UnableToLegalize;
628 const CallingConv::ID CC = TLI.getLibcallCallingConv(Libcall);
629 return createLibcall(MIRBuilder, Name, Result, Args, CC, LocObserver, MI);
632 // Useful for libcalls where all operands have the same type.
633 static LegalizerHelper::LegalizeResult
634 simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,
635 Type *OpType, LostDebugLocObserver &LocObserver) {
636 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
638 // FIXME: What does the original arg index mean here?
639 SmallVector<CallLowering::ArgInfo, 3> Args;
640 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
641 Args.push_back({MO.getReg(), OpType, 0});
642 return createLibcall(MIRBuilder, Libcall,
643 {MI.getOperand(0).getReg(), OpType, 0}, Args,
644 LocObserver, &MI);
647 LegalizerHelper::LegalizeResult
648 llvm::createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
649 MachineInstr &MI, LostDebugLocObserver &LocObserver) {
650 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
652 SmallVector<CallLowering::ArgInfo, 3> Args;
653 // Add all the args, except for the last which is an imm denoting 'tail'.
654 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
655 Register Reg = MI.getOperand(i).getReg();
657 // Need derive an IR type for call lowering.
658 LLT OpLLT = MRI.getType(Reg);
659 Type *OpTy = nullptr;
660 if (OpLLT.isPointer())
661 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
662 else
663 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
664 Args.push_back({Reg, OpTy, 0});
667 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
668 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
669 RTLIB::Libcall RTLibcall;
670 unsigned Opc = MI.getOpcode();
671 switch (Opc) {
672 case TargetOpcode::G_BZERO:
673 RTLibcall = RTLIB::BZERO;
674 break;
675 case TargetOpcode::G_MEMCPY:
676 RTLibcall = RTLIB::MEMCPY;
677 Args[0].Flags[0].setReturned();
678 break;
679 case TargetOpcode::G_MEMMOVE:
680 RTLibcall = RTLIB::MEMMOVE;
681 Args[0].Flags[0].setReturned();
682 break;
683 case TargetOpcode::G_MEMSET:
684 RTLibcall = RTLIB::MEMSET;
685 Args[0].Flags[0].setReturned();
686 break;
687 default:
688 llvm_unreachable("unsupported opcode");
690 const char *Name = TLI.getLibcallName(RTLibcall);
692 // Unsupported libcall on the target.
693 if (!Name) {
694 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
695 << MIRBuilder.getTII().getName(Opc) << "\n");
696 return LegalizerHelper::UnableToLegalize;
699 CallLowering::CallLoweringInfo Info;
700 Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);
701 Info.Callee = MachineOperand::CreateES(Name);
702 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
703 Info.IsTailCall =
704 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
705 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI);
707 std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
708 if (!CLI.lowerCall(MIRBuilder, Info))
709 return LegalizerHelper::UnableToLegalize;
711 if (Info.LoweredTailCall) {
712 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
714 // Check debug locations before removing the return.
715 LocObserver.checkpoint(true);
717 // We must have a return following the call (or debug insts) to get past
718 // isLibCallInTailPosition.
719 do {
720 MachineInstr *Next = MI.getNextNode();
721 assert(Next &&
722 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
723 "Expected instr following MI to be return or debug inst?");
724 // We lowered a tail call, so the call is now the return from the block.
725 // Delete the old return.
726 Next->eraseFromParent();
727 } while (MI.getNextNode());
729 // We expect to lose the debug location from the return.
730 LocObserver.checkpoint(false);
733 return LegalizerHelper::Legalized;
736 static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
737 unsigned Opc = MI.getOpcode();
738 auto &AtomicMI = cast<GMemOperation>(MI);
739 auto &MMO = AtomicMI.getMMO();
740 auto Ordering = MMO.getMergedOrdering();
741 LLT MemType = MMO.getMemoryType();
742 uint64_t MemSize = MemType.getSizeInBytes();
743 if (MemType.isVector())
744 return RTLIB::UNKNOWN_LIBCALL;
746 #define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
747 #define LCALL5(A) \
748 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
749 switch (Opc) {
750 case TargetOpcode::G_ATOMIC_CMPXCHG:
751 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
752 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
753 return getOutlineAtomicHelper(LC, Ordering, MemSize);
755 case TargetOpcode::G_ATOMICRMW_XCHG: {
756 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
757 return getOutlineAtomicHelper(LC, Ordering, MemSize);
759 case TargetOpcode::G_ATOMICRMW_ADD:
760 case TargetOpcode::G_ATOMICRMW_SUB: {
761 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
762 return getOutlineAtomicHelper(LC, Ordering, MemSize);
764 case TargetOpcode::G_ATOMICRMW_AND: {
765 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
766 return getOutlineAtomicHelper(LC, Ordering, MemSize);
768 case TargetOpcode::G_ATOMICRMW_OR: {
769 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
770 return getOutlineAtomicHelper(LC, Ordering, MemSize);
772 case TargetOpcode::G_ATOMICRMW_XOR: {
773 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
774 return getOutlineAtomicHelper(LC, Ordering, MemSize);
776 default:
777 return RTLIB::UNKNOWN_LIBCALL;
779 #undef LCALLS
780 #undef LCALL5
783 static LegalizerHelper::LegalizeResult
784 createAtomicLibcall(MachineIRBuilder &MIRBuilder, MachineInstr &MI) {
785 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
787 Type *RetTy;
788 SmallVector<Register> RetRegs;
789 SmallVector<CallLowering::ArgInfo, 3> Args;
790 unsigned Opc = MI.getOpcode();
791 switch (Opc) {
792 case TargetOpcode::G_ATOMIC_CMPXCHG:
793 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
794 Register Success;
795 LLT SuccessLLT;
796 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
797 MI.getFirst4RegLLTs();
798 RetRegs.push_back(Ret);
799 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
800 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
801 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
802 NewLLT) = MI.getFirst5RegLLTs();
803 RetRegs.push_back(Success);
804 RetTy = StructType::get(
805 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
807 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
808 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
809 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
810 break;
812 case TargetOpcode::G_ATOMICRMW_XCHG:
813 case TargetOpcode::G_ATOMICRMW_ADD:
814 case TargetOpcode::G_ATOMICRMW_SUB:
815 case TargetOpcode::G_ATOMICRMW_AND:
816 case TargetOpcode::G_ATOMICRMW_OR:
817 case TargetOpcode::G_ATOMICRMW_XOR: {
818 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
819 RetRegs.push_back(Ret);
820 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
821 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
822 Val =
823 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
824 .getReg(0);
825 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
826 Val =
827 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
828 .getReg(0);
829 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
830 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
831 break;
833 default:
834 llvm_unreachable("unsupported opcode");
837 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
838 auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
839 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
840 const char *Name = TLI.getLibcallName(RTLibcall);
842 // Unsupported libcall on the target.
843 if (!Name) {
844 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
845 << MIRBuilder.getTII().getName(Opc) << "\n");
846 return LegalizerHelper::UnableToLegalize;
849 CallLowering::CallLoweringInfo Info;
850 Info.CallConv = TLI.getLibcallCallingConv(RTLibcall);
851 Info.Callee = MachineOperand::CreateES(Name);
852 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
854 std::copy(Args.begin(), Args.end(), std::back_inserter(Info.OrigArgs));
855 if (!CLI.lowerCall(MIRBuilder, Info))
856 return LegalizerHelper::UnableToLegalize;
858 return LegalizerHelper::Legalized;
861 static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
862 Type *FromType) {
863 auto ToMVT = MVT::getVT(ToType);
864 auto FromMVT = MVT::getVT(FromType);
866 switch (Opcode) {
867 case TargetOpcode::G_FPEXT:
868 return RTLIB::getFPEXT(FromMVT, ToMVT);
869 case TargetOpcode::G_FPTRUNC:
870 return RTLIB::getFPROUND(FromMVT, ToMVT);
871 case TargetOpcode::G_FPTOSI:
872 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
873 case TargetOpcode::G_FPTOUI:
874 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
875 case TargetOpcode::G_SITOFP:
876 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
877 case TargetOpcode::G_UITOFP:
878 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
880 llvm_unreachable("Unsupported libcall function");
883 static LegalizerHelper::LegalizeResult
884 conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,
885 Type *FromType, LostDebugLocObserver &LocObserver,
886 const TargetLowering &TLI, bool IsSigned = false) {
887 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
888 if (FromType->isIntegerTy()) {
889 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
890 Arg.Flags[0].setSExt();
891 else
892 Arg.Flags[0].setZExt();
895 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
896 return createLibcall(MIRBuilder, Libcall,
897 {MI.getOperand(0).getReg(), ToType, 0}, Arg, LocObserver,
898 &MI);
901 static RTLIB::Libcall
902 getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI) {
903 RTLIB::Libcall RTLibcall;
904 switch (MI.getOpcode()) {
905 case TargetOpcode::G_GET_FPENV:
906 RTLibcall = RTLIB::FEGETENV;
907 break;
908 case TargetOpcode::G_SET_FPENV:
909 case TargetOpcode::G_RESET_FPENV:
910 RTLibcall = RTLIB::FESETENV;
911 break;
912 case TargetOpcode::G_GET_FPMODE:
913 RTLibcall = RTLIB::FEGETMODE;
914 break;
915 case TargetOpcode::G_SET_FPMODE:
916 case TargetOpcode::G_RESET_FPMODE:
917 RTLibcall = RTLIB::FESETMODE;
918 break;
919 default:
920 llvm_unreachable("Unexpected opcode");
922 return RTLibcall;
925 // Some library functions that read FP state (fegetmode, fegetenv) write the
926 // state into a region in memory. IR intrinsics that do the same operations
927 // (get_fpmode, get_fpenv) return the state as integer value. To implement these
928 // intrinsics via the library functions, we need to use temporary variable,
929 // for example:
931 // %0:_(s32) = G_GET_FPMODE
933 // is transformed to:
935 // %1:_(p0) = G_FRAME_INDEX %stack.0
936 // BL &fegetmode
937 // %0:_(s32) = G_LOAD % 1
939 LegalizerHelper::LegalizeResult
940 LegalizerHelper::createGetStateLibcall(MachineIRBuilder &MIRBuilder,
941 MachineInstr &MI,
942 LostDebugLocObserver &LocObserver) {
943 const DataLayout &DL = MIRBuilder.getDataLayout();
944 auto &MF = MIRBuilder.getMF();
945 auto &MRI = *MIRBuilder.getMRI();
946 auto &Ctx = MF.getFunction().getContext();
948 // Create temporary, where library function will put the read state.
949 Register Dst = MI.getOperand(0).getReg();
950 LLT StateTy = MRI.getType(Dst);
951 TypeSize StateSize = StateTy.getSizeInBytes();
952 Align TempAlign = getStackTemporaryAlignment(StateTy);
953 MachinePointerInfo TempPtrInfo;
954 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
956 // Create a call to library function, with the temporary as an argument.
957 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
958 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
959 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
960 auto Res =
961 createLibcall(MIRBuilder, RTLibcall,
962 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
963 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
964 LocObserver, nullptr);
965 if (Res != LegalizerHelper::Legalized)
966 return Res;
968 // Create a load from the temporary.
969 MachineMemOperand *MMO = MF.getMachineMemOperand(
970 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
971 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
973 return LegalizerHelper::Legalized;
976 // Similar to `createGetStateLibcall` the function calls a library function
977 // using transient space in stack. In this case the library function reads
978 // content of memory region.
979 LegalizerHelper::LegalizeResult
980 LegalizerHelper::createSetStateLibcall(MachineIRBuilder &MIRBuilder,
981 MachineInstr &MI,
982 LostDebugLocObserver &LocObserver) {
983 const DataLayout &DL = MIRBuilder.getDataLayout();
984 auto &MF = MIRBuilder.getMF();
985 auto &MRI = *MIRBuilder.getMRI();
986 auto &Ctx = MF.getFunction().getContext();
988 // Create temporary, where library function will get the new state.
989 Register Src = MI.getOperand(0).getReg();
990 LLT StateTy = MRI.getType(Src);
991 TypeSize StateSize = StateTy.getSizeInBytes();
992 Align TempAlign = getStackTemporaryAlignment(StateTy);
993 MachinePointerInfo TempPtrInfo;
994 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
996 // Put the new state into the temporary.
997 MachineMemOperand *MMO = MF.getMachineMemOperand(
998 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
999 MIRBuilder.buildStore(Src, Temp, *MMO);
1001 // Create a call to library function, with the temporary as an argument.
1002 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1003 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1004 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1005 return createLibcall(MIRBuilder, RTLibcall,
1006 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1007 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1008 LocObserver, nullptr);
1011 /// Returns the corresponding libcall for the given Pred and
1012 /// the ICMP predicate that should be generated to compare with #0
1013 /// after the libcall.
1014 static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1015 getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size) {
1016 #define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1017 do { \
1018 switch (Size) { \
1019 case 32: \
1020 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1021 case 64: \
1022 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1023 case 128: \
1024 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1025 default: \
1026 llvm_unreachable("unexpected size"); \
1028 } while (0)
1030 switch (Pred) {
1031 case CmpInst::FCMP_OEQ:
1032 RTLIBCASE_CMP(OEQ_F, CmpInst::ICMP_EQ);
1033 case CmpInst::FCMP_UNE:
1034 RTLIBCASE_CMP(UNE_F, CmpInst::ICMP_NE);
1035 case CmpInst::FCMP_OGE:
1036 RTLIBCASE_CMP(OGE_F, CmpInst::ICMP_SGE);
1037 case CmpInst::FCMP_OLT:
1038 RTLIBCASE_CMP(OLT_F, CmpInst::ICMP_SLT);
1039 case CmpInst::FCMP_OLE:
1040 RTLIBCASE_CMP(OLE_F, CmpInst::ICMP_SLE);
1041 case CmpInst::FCMP_OGT:
1042 RTLIBCASE_CMP(OGT_F, CmpInst::ICMP_SGT);
1043 case CmpInst::FCMP_UNO:
1044 RTLIBCASE_CMP(UO_F, CmpInst::ICMP_NE);
1045 default:
1046 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1050 LegalizerHelper::LegalizeResult
1051 LegalizerHelper::createFCMPLibcall(MachineIRBuilder &MIRBuilder,
1052 MachineInstr &MI,
1053 LostDebugLocObserver &LocObserver) {
1054 auto &MF = MIRBuilder.getMF();
1055 auto &Ctx = MF.getFunction().getContext();
1056 const GFCmp *Cmp = cast<GFCmp>(&MI);
1058 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1059 unsigned Size = OpLLT.getSizeInBits();
1060 if ((Size != 32 && Size != 64 && Size != 128) ||
1061 OpLLT != MRI.getType(Cmp->getRHSReg()))
1062 return UnableToLegalize;
1064 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1066 // DstReg type is s32
1067 const Register DstReg = Cmp->getReg(0);
1068 LLT DstTy = MRI.getType(DstReg);
1069 const auto Cond = Cmp->getCond();
1071 // Reference:
1072 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1073 // Generates a libcall followed by ICMP.
1074 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1075 const CmpInst::Predicate ICmpPred,
1076 const DstOp &Res) -> Register {
1077 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1078 constexpr LLT TempLLT = LLT::scalar(32);
1079 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1080 // Generate libcall, holding result in Temp
1081 const auto Status = createLibcall(
1082 MIRBuilder, Libcall, {Temp, Type::getInt32Ty(Ctx), 0},
1083 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1084 LocObserver, &MI);
1085 if (!Status)
1086 return {};
1088 // Compare temp with #0 to get the final result.
1089 return MIRBuilder
1090 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1091 .getReg(0);
1094 // Simple case if we have a direct mapping from predicate to libcall
1095 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1096 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1097 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1098 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1099 return Legalized;
1101 return UnableToLegalize;
1104 // No direct mapping found, should be generated as combination of libcalls.
1106 switch (Cond) {
1107 case CmpInst::FCMP_UEQ: {
1108 // FCMP_UEQ: unordered or equal
1109 // Convert into (FCMP_OEQ || FCMP_UNO).
1111 const auto [OeqLibcall, OeqPred] =
1112 getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);
1113 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1115 const auto [UnoLibcall, UnoPred] =
1116 getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);
1117 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1118 if (Oeq && Uno)
1119 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1120 else
1121 return UnableToLegalize;
1123 break;
1125 case CmpInst::FCMP_ONE: {
1126 // FCMP_ONE: ordered and operands are unequal
1127 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1129 // We inverse the predicate instead of generating a NOT
1130 // to save one instruction.
1131 // On AArch64 isel can even select two cmp into a single ccmp.
1132 const auto [OeqLibcall, OeqPred] =
1133 getFCMPLibcallDesc(CmpInst::FCMP_OEQ, Size);
1134 const auto NotOeq =
1135 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1137 const auto [UnoLibcall, UnoPred] =
1138 getFCMPLibcallDesc(CmpInst::FCMP_UNO, Size);
1139 const auto NotUno =
1140 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1142 if (NotOeq && NotUno)
1143 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1144 else
1145 return UnableToLegalize;
1147 break;
1149 case CmpInst::FCMP_ULT:
1150 case CmpInst::FCMP_UGE:
1151 case CmpInst::FCMP_UGT:
1152 case CmpInst::FCMP_ULE:
1153 case CmpInst::FCMP_ORD: {
1154 // Convert into: !(inverse(Pred))
1155 // E.g. FCMP_ULT becomes !FCMP_OGE
1156 // This is equivalent to the following, but saves some instructions.
1157 // MIRBuilder.buildNot(
1158 // PredTy,
1159 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1160 // Op1, Op2));
1161 const auto [InversedLibcall, InversedPred] =
1162 getFCMPLibcallDesc(CmpInst::getInversePredicate(Cond), Size);
1163 if (!BuildLibcall(InversedLibcall,
1164 CmpInst::getInversePredicate(InversedPred), DstReg))
1165 return UnableToLegalize;
1166 break;
1168 default:
1169 return UnableToLegalize;
1172 return Legalized;
1175 // The function is used to legalize operations that set default environment
1176 // state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1177 // On most targets supported in glibc FE_DFL_MODE is defined as
1178 // `((const femode_t *) -1)`. Such assumption is used here. If for some target
1179 // it is not true, the target must provide custom lowering.
1180 LegalizerHelper::LegalizeResult
1181 LegalizerHelper::createResetStateLibcall(MachineIRBuilder &MIRBuilder,
1182 MachineInstr &MI,
1183 LostDebugLocObserver &LocObserver) {
1184 const DataLayout &DL = MIRBuilder.getDataLayout();
1185 auto &MF = MIRBuilder.getMF();
1186 auto &Ctx = MF.getFunction().getContext();
1188 // Create an argument for the library function.
1189 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1190 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1191 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1192 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1193 auto DefValue = MIRBuilder.buildConstant(LLT::scalar(PtrSize), -1LL);
1194 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1195 MIRBuilder.buildIntToPtr(Dest, DefValue);
1197 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1198 return createLibcall(MIRBuilder, RTLibcall,
1199 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1200 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}),
1201 LocObserver, &MI);
1204 LegalizerHelper::LegalizeResult
1205 LegalizerHelper::libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver) {
1206 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1208 switch (MI.getOpcode()) {
1209 default:
1210 return UnableToLegalize;
1211 case TargetOpcode::G_MUL:
1212 case TargetOpcode::G_SDIV:
1213 case TargetOpcode::G_UDIV:
1214 case TargetOpcode::G_SREM:
1215 case TargetOpcode::G_UREM:
1216 case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
1217 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1218 unsigned Size = LLTy.getSizeInBits();
1219 Type *HLTy = IntegerType::get(Ctx, Size);
1220 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1221 if (Status != Legalized)
1222 return Status;
1223 break;
1225 case TargetOpcode::G_FADD:
1226 case TargetOpcode::G_FSUB:
1227 case TargetOpcode::G_FMUL:
1228 case TargetOpcode::G_FDIV:
1229 case TargetOpcode::G_FMA:
1230 case TargetOpcode::G_FPOW:
1231 case TargetOpcode::G_FREM:
1232 case TargetOpcode::G_FCOS:
1233 case TargetOpcode::G_FSIN:
1234 case TargetOpcode::G_FTAN:
1235 case TargetOpcode::G_FACOS:
1236 case TargetOpcode::G_FASIN:
1237 case TargetOpcode::G_FATAN:
1238 case TargetOpcode::G_FATAN2:
1239 case TargetOpcode::G_FCOSH:
1240 case TargetOpcode::G_FSINH:
1241 case TargetOpcode::G_FTANH:
1242 case TargetOpcode::G_FLOG10:
1243 case TargetOpcode::G_FLOG:
1244 case TargetOpcode::G_FLOG2:
1245 case TargetOpcode::G_FEXP:
1246 case TargetOpcode::G_FEXP2:
1247 case TargetOpcode::G_FEXP10:
1248 case TargetOpcode::G_FCEIL:
1249 case TargetOpcode::G_FFLOOR:
1250 case TargetOpcode::G_FMINNUM:
1251 case TargetOpcode::G_FMAXNUM:
1252 case TargetOpcode::G_FSQRT:
1253 case TargetOpcode::G_FRINT:
1254 case TargetOpcode::G_FNEARBYINT:
1255 case TargetOpcode::G_INTRINSIC_TRUNC:
1256 case TargetOpcode::G_INTRINSIC_ROUND:
1257 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1258 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1259 unsigned Size = LLTy.getSizeInBits();
1260 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1261 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1262 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1263 return UnableToLegalize;
1265 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1266 if (Status != Legalized)
1267 return Status;
1268 break;
1270 case TargetOpcode::G_INTRINSIC_LRINT:
1271 case TargetOpcode::G_INTRINSIC_LLRINT: {
1272 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1273 unsigned Size = LLTy.getSizeInBits();
1274 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1275 Type *ITy = IntegerType::get(
1276 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1277 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1278 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1279 return UnableToLegalize;
1281 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1282 LegalizeResult Status =
1283 createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1284 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1285 if (Status != Legalized)
1286 return Status;
1287 MI.eraseFromParent();
1288 return Legalized;
1290 case TargetOpcode::G_FPOWI:
1291 case TargetOpcode::G_FLDEXP: {
1292 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1293 unsigned Size = LLTy.getSizeInBits();
1294 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1295 Type *ITy = IntegerType::get(
1296 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1297 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1298 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1299 return UnableToLegalize;
1301 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1302 SmallVector<CallLowering::ArgInfo, 2> Args = {
1303 {MI.getOperand(1).getReg(), HLTy, 0},
1304 {MI.getOperand(2).getReg(), ITy, 1}};
1305 Args[1].Flags[0].setSExt();
1306 LegalizeResult Status =
1307 createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), HLTy, 0},
1308 Args, LocObserver, &MI);
1309 if (Status != Legalized)
1310 return Status;
1311 break;
1313 case TargetOpcode::G_FPEXT:
1314 case TargetOpcode::G_FPTRUNC: {
1315 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1316 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1317 if (!FromTy || !ToTy)
1318 return UnableToLegalize;
1319 LegalizeResult Status =
1320 conversionLibcall(MI, MIRBuilder, ToTy, FromTy, LocObserver, TLI);
1321 if (Status != Legalized)
1322 return Status;
1323 break;
1325 case TargetOpcode::G_FCMP: {
1326 LegalizeResult Status = createFCMPLibcall(MIRBuilder, MI, LocObserver);
1327 if (Status != Legalized)
1328 return Status;
1329 MI.eraseFromParent();
1330 return Status;
1332 case TargetOpcode::G_FPTOSI:
1333 case TargetOpcode::G_FPTOUI: {
1334 // FIXME: Support other types
1335 Type *FromTy =
1336 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1337 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1338 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1339 return UnableToLegalize;
1340 LegalizeResult Status = conversionLibcall(
1341 MI, MIRBuilder, Type::getIntNTy(Ctx, ToSize), FromTy, LocObserver, TLI);
1342 if (Status != Legalized)
1343 return Status;
1344 break;
1346 case TargetOpcode::G_SITOFP:
1347 case TargetOpcode::G_UITOFP: {
1348 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1349 Type *ToTy =
1350 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1351 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1352 return UnableToLegalize;
1353 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1354 LegalizeResult Status =
1355 conversionLibcall(MI, MIRBuilder, ToTy, Type::getIntNTy(Ctx, FromSize),
1356 LocObserver, TLI, IsSigned);
1357 if (Status != Legalized)
1358 return Status;
1359 break;
1361 case TargetOpcode::G_ATOMICRMW_XCHG:
1362 case TargetOpcode::G_ATOMICRMW_ADD:
1363 case TargetOpcode::G_ATOMICRMW_SUB:
1364 case TargetOpcode::G_ATOMICRMW_AND:
1365 case TargetOpcode::G_ATOMICRMW_OR:
1366 case TargetOpcode::G_ATOMICRMW_XOR:
1367 case TargetOpcode::G_ATOMIC_CMPXCHG:
1368 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1369 auto Status = createAtomicLibcall(MIRBuilder, MI);
1370 if (Status != Legalized)
1371 return Status;
1372 break;
1374 case TargetOpcode::G_BZERO:
1375 case TargetOpcode::G_MEMCPY:
1376 case TargetOpcode::G_MEMMOVE:
1377 case TargetOpcode::G_MEMSET: {
1378 LegalizeResult Result =
1379 createMemLibcall(MIRBuilder, *MIRBuilder.getMRI(), MI, LocObserver);
1380 if (Result != Legalized)
1381 return Result;
1382 MI.eraseFromParent();
1383 return Result;
1385 case TargetOpcode::G_GET_FPENV:
1386 case TargetOpcode::G_GET_FPMODE: {
1387 LegalizeResult Result = createGetStateLibcall(MIRBuilder, MI, LocObserver);
1388 if (Result != Legalized)
1389 return Result;
1390 break;
1392 case TargetOpcode::G_SET_FPENV:
1393 case TargetOpcode::G_SET_FPMODE: {
1394 LegalizeResult Result = createSetStateLibcall(MIRBuilder, MI, LocObserver);
1395 if (Result != Legalized)
1396 return Result;
1397 break;
1399 case TargetOpcode::G_RESET_FPENV:
1400 case TargetOpcode::G_RESET_FPMODE: {
1401 LegalizeResult Result =
1402 createResetStateLibcall(MIRBuilder, MI, LocObserver);
1403 if (Result != Legalized)
1404 return Result;
1405 break;
1409 MI.eraseFromParent();
1410 return Legalized;
1413 LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
1414 unsigned TypeIdx,
1415 LLT NarrowTy) {
1416 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1417 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1419 switch (MI.getOpcode()) {
1420 default:
1421 return UnableToLegalize;
1422 case TargetOpcode::G_IMPLICIT_DEF: {
1423 Register DstReg = MI.getOperand(0).getReg();
1424 LLT DstTy = MRI.getType(DstReg);
1426 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1427 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1428 // FIXME: Although this would also be legal for the general case, it causes
1429 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1430 // combines not being hit). This seems to be a problem related to the
1431 // artifact combiner.
1432 if (SizeOp0 % NarrowSize != 0) {
1433 LLT ImplicitTy = NarrowTy;
1434 if (DstTy.isVector())
1435 ImplicitTy = LLT::vector(DstTy.getElementCount(), ImplicitTy);
1437 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1438 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1440 MI.eraseFromParent();
1441 return Legalized;
1444 int NumParts = SizeOp0 / NarrowSize;
1446 SmallVector<Register, 2> DstRegs;
1447 for (int i = 0; i < NumParts; ++i)
1448 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1450 if (DstTy.isVector())
1451 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1452 else
1453 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1454 MI.eraseFromParent();
1455 return Legalized;
1457 case TargetOpcode::G_CONSTANT: {
1458 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1459 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1460 unsigned TotalSize = Ty.getSizeInBits();
1461 unsigned NarrowSize = NarrowTy.getSizeInBits();
1462 int NumParts = TotalSize / NarrowSize;
1464 SmallVector<Register, 4> PartRegs;
1465 for (int I = 0; I != NumParts; ++I) {
1466 unsigned Offset = I * NarrowSize;
1467 auto K = MIRBuilder.buildConstant(NarrowTy,
1468 Val.lshr(Offset).trunc(NarrowSize));
1469 PartRegs.push_back(K.getReg(0));
1472 LLT LeftoverTy;
1473 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1474 SmallVector<Register, 1> LeftoverRegs;
1475 if (LeftoverBits != 0) {
1476 LeftoverTy = LLT::scalar(LeftoverBits);
1477 auto K = MIRBuilder.buildConstant(
1478 LeftoverTy,
1479 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1480 LeftoverRegs.push_back(K.getReg(0));
1483 insertParts(MI.getOperand(0).getReg(),
1484 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1486 MI.eraseFromParent();
1487 return Legalized;
1489 case TargetOpcode::G_SEXT:
1490 case TargetOpcode::G_ZEXT:
1491 case TargetOpcode::G_ANYEXT:
1492 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1493 case TargetOpcode::G_TRUNC: {
1494 if (TypeIdx != 1)
1495 return UnableToLegalize;
1497 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1498 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1499 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1500 return UnableToLegalize;
1503 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1504 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1505 MI.eraseFromParent();
1506 return Legalized;
1508 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1509 case TargetOpcode::G_FREEZE: {
1510 if (TypeIdx != 0)
1511 return UnableToLegalize;
1513 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1514 // Should widen scalar first
1515 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1516 return UnableToLegalize;
1518 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1519 SmallVector<Register, 8> Parts;
1520 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1521 Parts.push_back(
1522 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1523 .getReg(0));
1526 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1527 MI.eraseFromParent();
1528 return Legalized;
1530 case TargetOpcode::G_ADD:
1531 case TargetOpcode::G_SUB:
1532 case TargetOpcode::G_SADDO:
1533 case TargetOpcode::G_SSUBO:
1534 case TargetOpcode::G_SADDE:
1535 case TargetOpcode::G_SSUBE:
1536 case TargetOpcode::G_UADDO:
1537 case TargetOpcode::G_USUBO:
1538 case TargetOpcode::G_UADDE:
1539 case TargetOpcode::G_USUBE:
1540 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1541 case TargetOpcode::G_MUL:
1542 case TargetOpcode::G_UMULH:
1543 return narrowScalarMul(MI, NarrowTy);
1544 case TargetOpcode::G_EXTRACT:
1545 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1546 case TargetOpcode::G_INSERT:
1547 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1548 case TargetOpcode::G_LOAD: {
1549 auto &LoadMI = cast<GLoad>(MI);
1550 Register DstReg = LoadMI.getDstReg();
1551 LLT DstTy = MRI.getType(DstReg);
1552 if (DstTy.isVector())
1553 return UnableToLegalize;
1555 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1556 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1557 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1558 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1559 LoadMI.eraseFromParent();
1560 return Legalized;
1563 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1565 case TargetOpcode::G_ZEXTLOAD:
1566 case TargetOpcode::G_SEXTLOAD: {
1567 auto &LoadMI = cast<GExtLoad>(MI);
1568 Register DstReg = LoadMI.getDstReg();
1569 Register PtrReg = LoadMI.getPointerReg();
1571 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1572 auto &MMO = LoadMI.getMMO();
1573 unsigned MemSize = MMO.getSizeInBits().getValue();
1575 if (MemSize == NarrowSize) {
1576 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1577 } else if (MemSize < NarrowSize) {
1578 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1579 } else if (MemSize > NarrowSize) {
1580 // FIXME: Need to split the load.
1581 return UnableToLegalize;
1584 if (isa<GZExtLoad>(LoadMI))
1585 MIRBuilder.buildZExt(DstReg, TmpReg);
1586 else
1587 MIRBuilder.buildSExt(DstReg, TmpReg);
1589 LoadMI.eraseFromParent();
1590 return Legalized;
1592 case TargetOpcode::G_STORE: {
1593 auto &StoreMI = cast<GStore>(MI);
1595 Register SrcReg = StoreMI.getValueReg();
1596 LLT SrcTy = MRI.getType(SrcReg);
1597 if (SrcTy.isVector())
1598 return UnableToLegalize;
1600 int NumParts = SizeOp0 / NarrowSize;
1601 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1602 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1603 if (SrcTy.isVector() && LeftoverBits != 0)
1604 return UnableToLegalize;
1606 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1607 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1608 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1609 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1610 StoreMI.eraseFromParent();
1611 return Legalized;
1614 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1616 case TargetOpcode::G_SELECT:
1617 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1618 case TargetOpcode::G_AND:
1619 case TargetOpcode::G_OR:
1620 case TargetOpcode::G_XOR: {
1621 // Legalize bitwise operation:
1622 // A = BinOp<Ty> B, C
1623 // into:
1624 // B1, ..., BN = G_UNMERGE_VALUES B
1625 // C1, ..., CN = G_UNMERGE_VALUES C
1626 // A1 = BinOp<Ty/N> B1, C2
1627 // ...
1628 // AN = BinOp<Ty/N> BN, CN
1629 // A = G_MERGE_VALUES A1, ..., AN
1630 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1632 case TargetOpcode::G_SHL:
1633 case TargetOpcode::G_LSHR:
1634 case TargetOpcode::G_ASHR:
1635 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1636 case TargetOpcode::G_CTLZ:
1637 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
1638 case TargetOpcode::G_CTTZ:
1639 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
1640 case TargetOpcode::G_CTPOP:
1641 if (TypeIdx == 1)
1642 switch (MI.getOpcode()) {
1643 case TargetOpcode::G_CTLZ:
1644 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
1645 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1646 case TargetOpcode::G_CTTZ:
1647 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
1648 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1649 case TargetOpcode::G_CTPOP:
1650 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1651 default:
1652 return UnableToLegalize;
1655 Observer.changingInstr(MI);
1656 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1657 Observer.changedInstr(MI);
1658 return Legalized;
1659 case TargetOpcode::G_INTTOPTR:
1660 if (TypeIdx != 1)
1661 return UnableToLegalize;
1663 Observer.changingInstr(MI);
1664 narrowScalarSrc(MI, NarrowTy, 1);
1665 Observer.changedInstr(MI);
1666 return Legalized;
1667 case TargetOpcode::G_PTRTOINT:
1668 if (TypeIdx != 0)
1669 return UnableToLegalize;
1671 Observer.changingInstr(MI);
1672 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1673 Observer.changedInstr(MI);
1674 return Legalized;
1675 case TargetOpcode::G_PHI: {
1676 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1677 // NarrowSize.
1678 if (SizeOp0 % NarrowSize != 0)
1679 return UnableToLegalize;
1681 unsigned NumParts = SizeOp0 / NarrowSize;
1682 SmallVector<Register, 2> DstRegs(NumParts);
1683 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1684 Observer.changingInstr(MI);
1685 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1686 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1687 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1688 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1689 SrcRegs[i / 2], MIRBuilder, MRI);
1691 MachineBasicBlock &MBB = *MI.getParent();
1692 MIRBuilder.setInsertPt(MBB, MI);
1693 for (unsigned i = 0; i < NumParts; ++i) {
1694 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1695 MachineInstrBuilder MIB =
1696 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1697 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1698 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1700 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1701 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1702 Observer.changedInstr(MI);
1703 MI.eraseFromParent();
1704 return Legalized;
1706 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1707 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1708 if (TypeIdx != 2)
1709 return UnableToLegalize;
1711 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1712 Observer.changingInstr(MI);
1713 narrowScalarSrc(MI, NarrowTy, OpIdx);
1714 Observer.changedInstr(MI);
1715 return Legalized;
1717 case TargetOpcode::G_ICMP: {
1718 Register LHS = MI.getOperand(2).getReg();
1719 LLT SrcTy = MRI.getType(LHS);
1720 CmpInst::Predicate Pred =
1721 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1723 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1724 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1725 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1726 LHSLeftoverRegs, MIRBuilder, MRI))
1727 return UnableToLegalize;
1729 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1730 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1731 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1732 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1733 return UnableToLegalize;
1735 // We now have the LHS and RHS of the compare split into narrow-type
1736 // registers, plus potentially some leftover type.
1737 Register Dst = MI.getOperand(0).getReg();
1738 LLT ResTy = MRI.getType(Dst);
1739 if (ICmpInst::isEquality(Pred)) {
1740 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1741 // them together. For each equal part, the result should be all 0s. For
1742 // each non-equal part, we'll get at least one 1.
1743 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1744 SmallVector<Register, 4> Xors;
1745 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1746 auto LHS = std::get<0>(LHSAndRHS);
1747 auto RHS = std::get<1>(LHSAndRHS);
1748 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1749 Xors.push_back(Xor);
1752 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1753 // to the desired narrow type so that we can OR them together later.
1754 SmallVector<Register, 4> WidenedXors;
1755 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1756 auto LHS = std::get<0>(LHSAndRHS);
1757 auto RHS = std::get<1>(LHSAndRHS);
1758 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1759 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1760 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1761 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1762 Xors.insert(Xors.end(), WidenedXors.begin(), WidenedXors.end());
1765 // Now, for each part we broke up, we know if they are equal/not equal
1766 // based off the G_XOR. We can OR these all together and compare against
1767 // 0 to get the result.
1768 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1769 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1770 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1771 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1772 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1773 } else {
1774 Register CmpIn;
1775 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1776 Register CmpOut;
1777 CmpInst::Predicate PartPred;
1779 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1780 PartPred = Pred;
1781 CmpOut = Dst;
1782 } else {
1783 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1784 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1787 if (!CmpIn) {
1788 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1789 RHSPartRegs[I]);
1790 } else {
1791 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1792 RHSPartRegs[I]);
1793 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1794 LHSPartRegs[I], RHSPartRegs[I]);
1795 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1798 CmpIn = CmpOut;
1801 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1802 Register CmpOut;
1803 CmpInst::Predicate PartPred;
1805 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1806 PartPred = Pred;
1807 CmpOut = Dst;
1808 } else {
1809 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1810 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1813 if (!CmpIn) {
1814 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1815 RHSLeftoverRegs[I]);
1816 } else {
1817 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1818 RHSLeftoverRegs[I]);
1819 auto CmpEq =
1820 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1821 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1822 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1825 CmpIn = CmpOut;
1828 MI.eraseFromParent();
1829 return Legalized;
1831 case TargetOpcode::G_FCMP:
1832 if (TypeIdx != 0)
1833 return UnableToLegalize;
1835 Observer.changingInstr(MI);
1836 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1837 Observer.changedInstr(MI);
1838 return Legalized;
1840 case TargetOpcode::G_SEXT_INREG: {
1841 if (TypeIdx != 0)
1842 return UnableToLegalize;
1844 int64_t SizeInBits = MI.getOperand(2).getImm();
1846 // So long as the new type has more bits than the bits we're extending we
1847 // don't need to break it apart.
1848 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
1849 Observer.changingInstr(MI);
1850 // We don't lose any non-extension bits by truncating the src and
1851 // sign-extending the dst.
1852 MachineOperand &MO1 = MI.getOperand(1);
1853 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
1854 MO1.setReg(TruncMIB.getReg(0));
1856 MachineOperand &MO2 = MI.getOperand(0);
1857 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
1858 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
1859 MIRBuilder.buildSExt(MO2, DstExt);
1860 MO2.setReg(DstExt);
1861 Observer.changedInstr(MI);
1862 return Legalized;
1865 // Break it apart. Components below the extension point are unmodified. The
1866 // component containing the extension point becomes a narrower SEXT_INREG.
1867 // Components above it are ashr'd from the component containing the
1868 // extension point.
1869 if (SizeOp0 % NarrowSize != 0)
1870 return UnableToLegalize;
1871 int NumParts = SizeOp0 / NarrowSize;
1873 // List the registers where the destination will be scattered.
1874 SmallVector<Register, 2> DstRegs;
1875 // List the registers where the source will be split.
1876 SmallVector<Register, 2> SrcRegs;
1878 // Create all the temporary registers.
1879 for (int i = 0; i < NumParts; ++i) {
1880 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
1882 SrcRegs.push_back(SrcReg);
1885 // Explode the big arguments into smaller chunks.
1886 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
1888 Register AshrCstReg =
1889 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
1890 .getReg(0);
1891 Register FullExtensionReg;
1892 Register PartialExtensionReg;
1894 // Do the operation on each small part.
1895 for (int i = 0; i < NumParts; ++i) {
1896 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
1897 DstRegs.push_back(SrcRegs[i]);
1898 PartialExtensionReg = DstRegs.back();
1899 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
1900 assert(PartialExtensionReg &&
1901 "Expected to visit partial extension before full");
1902 if (FullExtensionReg) {
1903 DstRegs.push_back(FullExtensionReg);
1904 continue;
1906 DstRegs.push_back(
1907 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
1908 .getReg(0));
1909 FullExtensionReg = DstRegs.back();
1910 } else {
1911 DstRegs.push_back(
1912 MIRBuilder
1913 .buildInstr(
1914 TargetOpcode::G_SEXT_INREG, {NarrowTy},
1915 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
1916 .getReg(0));
1917 PartialExtensionReg = DstRegs.back();
1921 // Gather the destination registers into the final destination.
1922 Register DstReg = MI.getOperand(0).getReg();
1923 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1924 MI.eraseFromParent();
1925 return Legalized;
1927 case TargetOpcode::G_BSWAP:
1928 case TargetOpcode::G_BITREVERSE: {
1929 if (SizeOp0 % NarrowSize != 0)
1930 return UnableToLegalize;
1932 Observer.changingInstr(MI);
1933 SmallVector<Register, 2> SrcRegs, DstRegs;
1934 unsigned NumParts = SizeOp0 / NarrowSize;
1935 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
1936 MIRBuilder, MRI);
1938 for (unsigned i = 0; i < NumParts; ++i) {
1939 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
1940 {SrcRegs[NumParts - 1 - i]});
1941 DstRegs.push_back(DstPart.getReg(0));
1944 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1946 Observer.changedInstr(MI);
1947 MI.eraseFromParent();
1948 return Legalized;
1950 case TargetOpcode::G_PTR_ADD:
1951 case TargetOpcode::G_PTRMASK: {
1952 if (TypeIdx != 1)
1953 return UnableToLegalize;
1954 Observer.changingInstr(MI);
1955 narrowScalarSrc(MI, NarrowTy, 2);
1956 Observer.changedInstr(MI);
1957 return Legalized;
1959 case TargetOpcode::G_FPTOUI:
1960 case TargetOpcode::G_FPTOSI:
1961 case TargetOpcode::G_FPTOUI_SAT:
1962 case TargetOpcode::G_FPTOSI_SAT:
1963 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
1964 case TargetOpcode::G_FPEXT:
1965 if (TypeIdx != 0)
1966 return UnableToLegalize;
1967 Observer.changingInstr(MI);
1968 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
1969 Observer.changedInstr(MI);
1970 return Legalized;
1971 case TargetOpcode::G_FLDEXP:
1972 case TargetOpcode::G_STRICT_FLDEXP:
1973 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
1974 case TargetOpcode::G_VSCALE: {
1975 Register Dst = MI.getOperand(0).getReg();
1976 LLT Ty = MRI.getType(Dst);
1978 // Assume VSCALE(1) fits into a legal integer
1979 const APInt One(NarrowTy.getSizeInBits(), 1);
1980 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
1981 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
1982 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
1983 MIRBuilder.buildMul(Dst, ZExt, C);
1985 MI.eraseFromParent();
1986 return Legalized;
1991 Register LegalizerHelper::coerceToScalar(Register Val) {
1992 LLT Ty = MRI.getType(Val);
1993 if (Ty.isScalar())
1994 return Val;
1996 const DataLayout &DL = MIRBuilder.getDataLayout();
1997 LLT NewTy = LLT::scalar(Ty.getSizeInBits());
1998 if (Ty.isPointer()) {
1999 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2000 return Register();
2001 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2004 Register NewVal = Val;
2006 assert(Ty.isVector());
2007 if (Ty.isPointerVector())
2008 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2009 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2012 void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy,
2013 unsigned OpIdx, unsigned ExtOpcode) {
2014 MachineOperand &MO = MI.getOperand(OpIdx);
2015 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2016 MO.setReg(ExtB.getReg(0));
2019 void LegalizerHelper::narrowScalarSrc(MachineInstr &MI, LLT NarrowTy,
2020 unsigned OpIdx) {
2021 MachineOperand &MO = MI.getOperand(OpIdx);
2022 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2023 MO.setReg(ExtB.getReg(0));
2026 void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,
2027 unsigned OpIdx, unsigned TruncOpcode) {
2028 MachineOperand &MO = MI.getOperand(OpIdx);
2029 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2030 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2031 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2032 MO.setReg(DstExt);
2035 void LegalizerHelper::narrowScalarDst(MachineInstr &MI, LLT NarrowTy,
2036 unsigned OpIdx, unsigned ExtOpcode) {
2037 MachineOperand &MO = MI.getOperand(OpIdx);
2038 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2039 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2040 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2041 MO.setReg(DstTrunc);
2044 void LegalizerHelper::moreElementsVectorDst(MachineInstr &MI, LLT WideTy,
2045 unsigned OpIdx) {
2046 MachineOperand &MO = MI.getOperand(OpIdx);
2047 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2048 Register Dst = MO.getReg();
2049 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2050 MO.setReg(DstExt);
2051 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2054 void LegalizerHelper::moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy,
2055 unsigned OpIdx) {
2056 MachineOperand &MO = MI.getOperand(OpIdx);
2057 SmallVector<Register, 8> Regs;
2058 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2061 void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2062 MachineOperand &Op = MI.getOperand(OpIdx);
2063 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2066 void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2067 MachineOperand &MO = MI.getOperand(OpIdx);
2068 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2069 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2070 MIRBuilder.buildBitcast(MO, CastDst);
2071 MO.setReg(CastDst);
2074 LegalizerHelper::LegalizeResult
2075 LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2076 LLT WideTy) {
2077 if (TypeIdx != 1)
2078 return UnableToLegalize;
2080 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2081 if (DstTy.isVector())
2082 return UnableToLegalize;
2084 LLT SrcTy = MRI.getType(Src1Reg);
2085 const int DstSize = DstTy.getSizeInBits();
2086 const int SrcSize = SrcTy.getSizeInBits();
2087 const int WideSize = WideTy.getSizeInBits();
2088 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2090 unsigned NumOps = MI.getNumOperands();
2091 unsigned NumSrc = MI.getNumOperands() - 1;
2092 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2094 if (WideSize >= DstSize) {
2095 // Directly pack the bits in the target type.
2096 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2098 for (unsigned I = 2; I != NumOps; ++I) {
2099 const unsigned Offset = (I - 1) * PartSize;
2101 Register SrcReg = MI.getOperand(I).getReg();
2102 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2104 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2106 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2107 MRI.createGenericVirtualRegister(WideTy);
2109 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2110 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2111 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2112 ResultReg = NextResult;
2115 if (WideSize > DstSize)
2116 MIRBuilder.buildTrunc(DstReg, ResultReg);
2117 else if (DstTy.isPointer())
2118 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2120 MI.eraseFromParent();
2121 return Legalized;
2124 // Unmerge the original values to the GCD type, and recombine to the next
2125 // multiple greater than the original type.
2127 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2128 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2129 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2130 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2131 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2132 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2133 // %12:_(s12) = G_MERGE_VALUES %10, %11
2135 // Padding with undef if necessary:
2137 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2138 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2139 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2140 // %7:_(s2) = G_IMPLICIT_DEF
2141 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2142 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2143 // %10:_(s12) = G_MERGE_VALUES %8, %9
2145 const int GCD = std::gcd(SrcSize, WideSize);
2146 LLT GCDTy = LLT::scalar(GCD);
2148 SmallVector<Register, 8> Parts;
2149 SmallVector<Register, 8> NewMergeRegs;
2150 SmallVector<Register, 8> Unmerges;
2151 LLT WideDstTy = LLT::scalar(NumMerge * WideSize);
2153 // Decompose the original operands if they don't evenly divide.
2154 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2155 Register SrcReg = MO.getReg();
2156 if (GCD == SrcSize) {
2157 Unmerges.push_back(SrcReg);
2158 } else {
2159 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2160 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2161 Unmerges.push_back(Unmerge.getReg(J));
2165 // Pad with undef to the next size that is a multiple of the requested size.
2166 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2167 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2168 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2169 Unmerges.push_back(UndefReg);
2172 const int PartsPerGCD = WideSize / GCD;
2174 // Build merges of each piece.
2175 ArrayRef<Register> Slicer(Unmerges);
2176 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2177 auto Merge =
2178 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2179 NewMergeRegs.push_back(Merge.getReg(0));
2182 // A truncate may be necessary if the requested type doesn't evenly divide the
2183 // original result type.
2184 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2185 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2186 } else {
2187 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2188 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2191 MI.eraseFromParent();
2192 return Legalized;
2195 LegalizerHelper::LegalizeResult
2196 LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2197 LLT WideTy) {
2198 if (TypeIdx != 0)
2199 return UnableToLegalize;
2201 int NumDst = MI.getNumOperands() - 1;
2202 Register SrcReg = MI.getOperand(NumDst).getReg();
2203 LLT SrcTy = MRI.getType(SrcReg);
2204 if (SrcTy.isVector())
2205 return UnableToLegalize;
2207 Register Dst0Reg = MI.getOperand(0).getReg();
2208 LLT DstTy = MRI.getType(Dst0Reg);
2209 if (!DstTy.isScalar())
2210 return UnableToLegalize;
2212 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2213 if (SrcTy.isPointer()) {
2214 const DataLayout &DL = MIRBuilder.getDataLayout();
2215 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2216 LLVM_DEBUG(
2217 dbgs() << "Not casting non-integral address space integer\n");
2218 return UnableToLegalize;
2221 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2222 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2225 // Widen SrcTy to WideTy. This does not affect the result, but since the
2226 // user requested this size, it is probably better handled than SrcTy and
2227 // should reduce the total number of legalization artifacts.
2228 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2229 SrcTy = WideTy;
2230 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2233 // Theres no unmerge type to target. Directly extract the bits from the
2234 // source type
2235 unsigned DstSize = DstTy.getSizeInBits();
2237 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2238 for (int I = 1; I != NumDst; ++I) {
2239 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2240 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2241 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2244 MI.eraseFromParent();
2245 return Legalized;
2248 // Extend the source to a wider type.
2249 LLT LCMTy = getLCMType(SrcTy, WideTy);
2251 Register WideSrc = SrcReg;
2252 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2253 // TODO: If this is an integral address space, cast to integer and anyext.
2254 if (SrcTy.isPointer()) {
2255 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2256 return UnableToLegalize;
2259 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2262 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2264 // Create a sequence of unmerges and merges to the original results. Since we
2265 // may have widened the source, we will need to pad the results with dead defs
2266 // to cover the source register.
2267 // e.g. widen s48 to s64:
2268 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2270 // =>
2271 // %4:_(s192) = G_ANYEXT %0:_(s96)
2272 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2273 // ; unpack to GCD type, with extra dead defs
2274 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2275 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2276 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2277 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2278 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2279 const LLT GCDTy = getGCDType(WideTy, DstTy);
2280 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2281 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2283 // Directly unmerge to the destination without going through a GCD type
2284 // if possible
2285 if (PartsPerRemerge == 1) {
2286 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2288 for (int I = 0; I != NumUnmerge; ++I) {
2289 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2291 for (int J = 0; J != PartsPerUnmerge; ++J) {
2292 int Idx = I * PartsPerUnmerge + J;
2293 if (Idx < NumDst)
2294 MIB.addDef(MI.getOperand(Idx).getReg());
2295 else {
2296 // Create dead def for excess components.
2297 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2301 MIB.addUse(Unmerge.getReg(I));
2303 } else {
2304 SmallVector<Register, 16> Parts;
2305 for (int J = 0; J != NumUnmerge; ++J)
2306 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2308 SmallVector<Register, 8> RemergeParts;
2309 for (int I = 0; I != NumDst; ++I) {
2310 for (int J = 0; J < PartsPerRemerge; ++J) {
2311 const int Idx = I * PartsPerRemerge + J;
2312 RemergeParts.emplace_back(Parts[Idx]);
2315 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2316 RemergeParts.clear();
2320 MI.eraseFromParent();
2321 return Legalized;
2324 LegalizerHelper::LegalizeResult
2325 LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2326 LLT WideTy) {
2327 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2328 unsigned Offset = MI.getOperand(2).getImm();
2330 if (TypeIdx == 0) {
2331 if (SrcTy.isVector() || DstTy.isVector())
2332 return UnableToLegalize;
2334 SrcOp Src(SrcReg);
2335 if (SrcTy.isPointer()) {
2336 // Extracts from pointers can be handled only if they are really just
2337 // simple integers.
2338 const DataLayout &DL = MIRBuilder.getDataLayout();
2339 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2340 return UnableToLegalize;
2342 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2343 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2344 SrcTy = SrcAsIntTy;
2347 if (DstTy.isPointer())
2348 return UnableToLegalize;
2350 if (Offset == 0) {
2351 // Avoid a shift in the degenerate case.
2352 MIRBuilder.buildTrunc(DstReg,
2353 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2354 MI.eraseFromParent();
2355 return Legalized;
2358 // Do a shift in the source type.
2359 LLT ShiftTy = SrcTy;
2360 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2361 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2362 ShiftTy = WideTy;
2365 auto LShr = MIRBuilder.buildLShr(
2366 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2367 MIRBuilder.buildTrunc(DstReg, LShr);
2368 MI.eraseFromParent();
2369 return Legalized;
2372 if (SrcTy.isScalar()) {
2373 Observer.changingInstr(MI);
2374 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2375 Observer.changedInstr(MI);
2376 return Legalized;
2379 if (!SrcTy.isVector())
2380 return UnableToLegalize;
2382 if (DstTy != SrcTy.getElementType())
2383 return UnableToLegalize;
2385 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2386 return UnableToLegalize;
2388 Observer.changingInstr(MI);
2389 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2391 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2392 Offset);
2393 widenScalarDst(MI, WideTy.getScalarType(), 0);
2394 Observer.changedInstr(MI);
2395 return Legalized;
2398 LegalizerHelper::LegalizeResult
2399 LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2400 LLT WideTy) {
2401 if (TypeIdx != 0 || WideTy.isVector())
2402 return UnableToLegalize;
2403 Observer.changingInstr(MI);
2404 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2405 widenScalarDst(MI, WideTy);
2406 Observer.changedInstr(MI);
2407 return Legalized;
2410 LegalizerHelper::LegalizeResult
2411 LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2412 LLT WideTy) {
2413 unsigned Opcode;
2414 unsigned ExtOpcode;
2415 std::optional<Register> CarryIn;
2416 switch (MI.getOpcode()) {
2417 default:
2418 llvm_unreachable("Unexpected opcode!");
2419 case TargetOpcode::G_SADDO:
2420 Opcode = TargetOpcode::G_ADD;
2421 ExtOpcode = TargetOpcode::G_SEXT;
2422 break;
2423 case TargetOpcode::G_SSUBO:
2424 Opcode = TargetOpcode::G_SUB;
2425 ExtOpcode = TargetOpcode::G_SEXT;
2426 break;
2427 case TargetOpcode::G_UADDO:
2428 Opcode = TargetOpcode::G_ADD;
2429 ExtOpcode = TargetOpcode::G_ZEXT;
2430 break;
2431 case TargetOpcode::G_USUBO:
2432 Opcode = TargetOpcode::G_SUB;
2433 ExtOpcode = TargetOpcode::G_ZEXT;
2434 break;
2435 case TargetOpcode::G_SADDE:
2436 Opcode = TargetOpcode::G_UADDE;
2437 ExtOpcode = TargetOpcode::G_SEXT;
2438 CarryIn = MI.getOperand(4).getReg();
2439 break;
2440 case TargetOpcode::G_SSUBE:
2441 Opcode = TargetOpcode::G_USUBE;
2442 ExtOpcode = TargetOpcode::G_SEXT;
2443 CarryIn = MI.getOperand(4).getReg();
2444 break;
2445 case TargetOpcode::G_UADDE:
2446 Opcode = TargetOpcode::G_UADDE;
2447 ExtOpcode = TargetOpcode::G_ZEXT;
2448 CarryIn = MI.getOperand(4).getReg();
2449 break;
2450 case TargetOpcode::G_USUBE:
2451 Opcode = TargetOpcode::G_USUBE;
2452 ExtOpcode = TargetOpcode::G_ZEXT;
2453 CarryIn = MI.getOperand(4).getReg();
2454 break;
2457 if (TypeIdx == 1) {
2458 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2460 Observer.changingInstr(MI);
2461 if (CarryIn)
2462 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2463 widenScalarDst(MI, WideTy, 1);
2465 Observer.changedInstr(MI);
2466 return Legalized;
2469 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2470 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2471 // Do the arithmetic in the larger type.
2472 Register NewOp;
2473 if (CarryIn) {
2474 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2475 NewOp = MIRBuilder
2476 .buildInstr(Opcode, {WideTy, CarryOutTy},
2477 {LHSExt, RHSExt, *CarryIn})
2478 .getReg(0);
2479 } else {
2480 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2482 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2483 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2484 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2485 // There is no overflow if the ExtOp is the same as NewOp.
2486 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2487 // Now trunc the NewOp to the original result.
2488 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2489 MI.eraseFromParent();
2490 return Legalized;
2493 LegalizerHelper::LegalizeResult
2494 LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2495 LLT WideTy) {
2496 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2497 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2498 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2499 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2500 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2501 // We can convert this to:
2502 // 1. Any extend iN to iM
2503 // 2. SHL by M-N
2504 // 3. [US][ADD|SUB|SHL]SAT
2505 // 4. L/ASHR by M-N
2507 // It may be more efficient to lower this to a min and a max operation in
2508 // the higher precision arithmetic if the promoted operation isn't legal,
2509 // but this decision is up to the target's lowering request.
2510 Register DstReg = MI.getOperand(0).getReg();
2512 unsigned NewBits = WideTy.getScalarSizeInBits();
2513 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2515 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2516 // must not left shift the RHS to preserve the shift amount.
2517 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2518 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2519 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2520 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2521 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2522 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2524 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2525 {ShiftL, ShiftR}, MI.getFlags());
2527 // Use a shift that will preserve the number of sign bits when the trunc is
2528 // folded away.
2529 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2530 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2532 MIRBuilder.buildTrunc(DstReg, Result);
2533 MI.eraseFromParent();
2534 return Legalized;
2537 LegalizerHelper::LegalizeResult
2538 LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2539 LLT WideTy) {
2540 if (TypeIdx == 1) {
2541 Observer.changingInstr(MI);
2542 widenScalarDst(MI, WideTy, 1);
2543 Observer.changedInstr(MI);
2544 return Legalized;
2547 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2548 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2549 LLT SrcTy = MRI.getType(LHS);
2550 LLT OverflowTy = MRI.getType(OriginalOverflow);
2551 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2553 // To determine if the result overflowed in the larger type, we extend the
2554 // input to the larger type, do the multiply (checking if it overflows),
2555 // then also check the high bits of the result to see if overflow happened
2556 // there.
2557 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2558 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2559 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2561 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2562 // so we don't need to check the overflow result of larger type Mulo.
2563 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2565 unsigned MulOpc =
2566 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2568 MachineInstrBuilder Mulo;
2569 if (WideMulCanOverflow)
2570 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2571 {LeftOperand, RightOperand});
2572 else
2573 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2575 auto Mul = Mulo->getOperand(0);
2576 MIRBuilder.buildTrunc(Result, Mul);
2578 MachineInstrBuilder ExtResult;
2579 // Overflow occurred if it occurred in the larger type, or if the high part
2580 // of the result does not zero/sign-extend the low part. Check this second
2581 // possibility first.
2582 if (IsSigned) {
2583 // For signed, overflow occurred when the high part does not sign-extend
2584 // the low part.
2585 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2586 } else {
2587 // Unsigned overflow occurred when the high part does not zero-extend the
2588 // low part.
2589 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2592 if (WideMulCanOverflow) {
2593 auto Overflow =
2594 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2595 // Finally check if the multiplication in the larger type itself overflowed.
2596 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2597 } else {
2598 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2600 MI.eraseFromParent();
2601 return Legalized;
2604 LegalizerHelper::LegalizeResult
2605 LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
2606 unsigned Opcode = MI.getOpcode();
2607 switch (Opcode) {
2608 default:
2609 return UnableToLegalize;
2610 case TargetOpcode::G_ATOMICRMW_XCHG:
2611 case TargetOpcode::G_ATOMICRMW_ADD:
2612 case TargetOpcode::G_ATOMICRMW_SUB:
2613 case TargetOpcode::G_ATOMICRMW_AND:
2614 case TargetOpcode::G_ATOMICRMW_OR:
2615 case TargetOpcode::G_ATOMICRMW_XOR:
2616 case TargetOpcode::G_ATOMICRMW_MIN:
2617 case TargetOpcode::G_ATOMICRMW_MAX:
2618 case TargetOpcode::G_ATOMICRMW_UMIN:
2619 case TargetOpcode::G_ATOMICRMW_UMAX:
2620 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2621 Observer.changingInstr(MI);
2622 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2623 widenScalarDst(MI, WideTy, 0);
2624 Observer.changedInstr(MI);
2625 return Legalized;
2626 case TargetOpcode::G_ATOMIC_CMPXCHG:
2627 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2628 Observer.changingInstr(MI);
2629 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2630 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2631 widenScalarDst(MI, WideTy, 0);
2632 Observer.changedInstr(MI);
2633 return Legalized;
2634 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2635 if (TypeIdx == 0) {
2636 Observer.changingInstr(MI);
2637 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2638 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2639 widenScalarDst(MI, WideTy, 0);
2640 Observer.changedInstr(MI);
2641 return Legalized;
2643 assert(TypeIdx == 1 &&
2644 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2645 Observer.changingInstr(MI);
2646 widenScalarDst(MI, WideTy, 1);
2647 Observer.changedInstr(MI);
2648 return Legalized;
2649 case TargetOpcode::G_EXTRACT:
2650 return widenScalarExtract(MI, TypeIdx, WideTy);
2651 case TargetOpcode::G_INSERT:
2652 return widenScalarInsert(MI, TypeIdx, WideTy);
2653 case TargetOpcode::G_MERGE_VALUES:
2654 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2655 case TargetOpcode::G_UNMERGE_VALUES:
2656 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2657 case TargetOpcode::G_SADDO:
2658 case TargetOpcode::G_SSUBO:
2659 case TargetOpcode::G_UADDO:
2660 case TargetOpcode::G_USUBO:
2661 case TargetOpcode::G_SADDE:
2662 case TargetOpcode::G_SSUBE:
2663 case TargetOpcode::G_UADDE:
2664 case TargetOpcode::G_USUBE:
2665 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2666 case TargetOpcode::G_UMULO:
2667 case TargetOpcode::G_SMULO:
2668 return widenScalarMulo(MI, TypeIdx, WideTy);
2669 case TargetOpcode::G_SADDSAT:
2670 case TargetOpcode::G_SSUBSAT:
2671 case TargetOpcode::G_SSHLSAT:
2672 case TargetOpcode::G_UADDSAT:
2673 case TargetOpcode::G_USUBSAT:
2674 case TargetOpcode::G_USHLSAT:
2675 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2676 case TargetOpcode::G_CTTZ:
2677 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
2678 case TargetOpcode::G_CTLZ:
2679 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
2680 case TargetOpcode::G_CTPOP: {
2681 if (TypeIdx == 0) {
2682 Observer.changingInstr(MI);
2683 widenScalarDst(MI, WideTy, 0);
2684 Observer.changedInstr(MI);
2685 return Legalized;
2688 Register SrcReg = MI.getOperand(1).getReg();
2690 // First extend the input.
2691 unsigned ExtOpc = Opcode == TargetOpcode::G_CTTZ ||
2692 Opcode == TargetOpcode::G_CTTZ_ZERO_UNDEF
2693 ? TargetOpcode::G_ANYEXT
2694 : TargetOpcode::G_ZEXT;
2695 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2696 LLT CurTy = MRI.getType(SrcReg);
2697 unsigned NewOpc = Opcode;
2698 if (NewOpc == TargetOpcode::G_CTTZ) {
2699 // The count is the same in the larger type except if the original
2700 // value was zero. This can be handled by setting the bit just off
2701 // the top of the original type.
2702 auto TopBit =
2703 APInt::getOneBitSet(WideTy.getSizeInBits(), CurTy.getSizeInBits());
2704 MIBSrc = MIRBuilder.buildOr(
2705 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2706 // Now we know the operand is non-zero, use the more relaxed opcode.
2707 NewOpc = TargetOpcode::G_CTTZ_ZERO_UNDEF;
2710 unsigned SizeDiff = WideTy.getSizeInBits() - CurTy.getSizeInBits();
2712 if (Opcode == TargetOpcode::G_CTLZ_ZERO_UNDEF) {
2713 // An optimization where the result is the CTLZ after the left shift by
2714 // (Difference in widety and current ty), that is,
2715 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2716 // Result = ctlz MIBSrc
2717 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2718 MIRBuilder.buildConstant(WideTy, SizeDiff));
2721 // Perform the operation at the larger size.
2722 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2723 // This is already the correct result for CTPOP and CTTZs
2724 if (Opcode == TargetOpcode::G_CTLZ) {
2725 // The correct result is NewOp - (Difference in widety and current ty).
2726 MIBNewOp = MIRBuilder.buildSub(
2727 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff));
2730 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2731 MI.eraseFromParent();
2732 return Legalized;
2734 case TargetOpcode::G_BSWAP: {
2735 Observer.changingInstr(MI);
2736 Register DstReg = MI.getOperand(0).getReg();
2738 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2739 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2740 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2741 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2743 MI.getOperand(0).setReg(DstExt);
2745 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2747 LLT Ty = MRI.getType(DstReg);
2748 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2749 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2750 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2752 MIRBuilder.buildTrunc(DstReg, ShrReg);
2753 Observer.changedInstr(MI);
2754 return Legalized;
2756 case TargetOpcode::G_BITREVERSE: {
2757 Observer.changingInstr(MI);
2759 Register DstReg = MI.getOperand(0).getReg();
2760 LLT Ty = MRI.getType(DstReg);
2761 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2763 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2764 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2765 MI.getOperand(0).setReg(DstExt);
2766 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2768 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2769 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2770 MIRBuilder.buildTrunc(DstReg, Shift);
2771 Observer.changedInstr(MI);
2772 return Legalized;
2774 case TargetOpcode::G_FREEZE:
2775 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2776 Observer.changingInstr(MI);
2777 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2778 widenScalarDst(MI, WideTy);
2779 Observer.changedInstr(MI);
2780 return Legalized;
2782 case TargetOpcode::G_ABS:
2783 Observer.changingInstr(MI);
2784 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2785 widenScalarDst(MI, WideTy);
2786 Observer.changedInstr(MI);
2787 return Legalized;
2789 case TargetOpcode::G_ADD:
2790 case TargetOpcode::G_AND:
2791 case TargetOpcode::G_MUL:
2792 case TargetOpcode::G_OR:
2793 case TargetOpcode::G_XOR:
2794 case TargetOpcode::G_SUB:
2795 case TargetOpcode::G_SHUFFLE_VECTOR:
2796 // Perform operation at larger width (any extension is fines here, high bits
2797 // don't affect the result) and then truncate the result back to the
2798 // original type.
2799 Observer.changingInstr(MI);
2800 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2801 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2802 widenScalarDst(MI, WideTy);
2803 Observer.changedInstr(MI);
2804 return Legalized;
2806 case TargetOpcode::G_SBFX:
2807 case TargetOpcode::G_UBFX:
2808 Observer.changingInstr(MI);
2810 if (TypeIdx == 0) {
2811 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2812 widenScalarDst(MI, WideTy);
2813 } else {
2814 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2815 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
2818 Observer.changedInstr(MI);
2819 return Legalized;
2821 case TargetOpcode::G_SHL:
2822 Observer.changingInstr(MI);
2824 if (TypeIdx == 0) {
2825 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2826 widenScalarDst(MI, WideTy);
2827 } else {
2828 assert(TypeIdx == 1);
2829 // The "number of bits to shift" operand must preserve its value as an
2830 // unsigned integer:
2831 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2834 Observer.changedInstr(MI);
2835 return Legalized;
2837 case TargetOpcode::G_ROTR:
2838 case TargetOpcode::G_ROTL:
2839 if (TypeIdx != 1)
2840 return UnableToLegalize;
2842 Observer.changingInstr(MI);
2843 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2844 Observer.changedInstr(MI);
2845 return Legalized;
2847 case TargetOpcode::G_SDIV:
2848 case TargetOpcode::G_SREM:
2849 case TargetOpcode::G_SMIN:
2850 case TargetOpcode::G_SMAX:
2851 Observer.changingInstr(MI);
2852 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2853 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
2854 widenScalarDst(MI, WideTy);
2855 Observer.changedInstr(MI);
2856 return Legalized;
2858 case TargetOpcode::G_SDIVREM:
2859 Observer.changingInstr(MI);
2860 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
2861 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
2862 widenScalarDst(MI, WideTy);
2863 widenScalarDst(MI, WideTy, 1);
2864 Observer.changedInstr(MI);
2865 return Legalized;
2867 case TargetOpcode::G_ASHR:
2868 case TargetOpcode::G_LSHR:
2869 Observer.changingInstr(MI);
2871 if (TypeIdx == 0) {
2872 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
2873 : TargetOpcode::G_ZEXT;
2875 widenScalarSrc(MI, WideTy, 1, CvtOp);
2876 widenScalarDst(MI, WideTy);
2877 } else {
2878 assert(TypeIdx == 1);
2879 // The "number of bits to shift" operand must preserve its value as an
2880 // unsigned integer:
2881 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2884 Observer.changedInstr(MI);
2885 return Legalized;
2886 case TargetOpcode::G_UDIV:
2887 case TargetOpcode::G_UREM:
2888 Observer.changingInstr(MI);
2889 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
2890 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2891 widenScalarDst(MI, WideTy);
2892 Observer.changedInstr(MI);
2893 return Legalized;
2894 case TargetOpcode::G_UDIVREM:
2895 Observer.changingInstr(MI);
2896 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2897 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
2898 widenScalarDst(MI, WideTy);
2899 widenScalarDst(MI, WideTy, 1);
2900 Observer.changedInstr(MI);
2901 return Legalized;
2902 case TargetOpcode::G_UMIN:
2903 case TargetOpcode::G_UMAX: {
2904 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
2906 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
2907 unsigned ExtOpc =
2908 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
2909 getApproximateEVTForLLT(WideTy, Ctx))
2910 ? TargetOpcode::G_SEXT
2911 : TargetOpcode::G_ZEXT;
2913 Observer.changingInstr(MI);
2914 widenScalarSrc(MI, WideTy, 1, ExtOpc);
2915 widenScalarSrc(MI, WideTy, 2, ExtOpc);
2916 widenScalarDst(MI, WideTy);
2917 Observer.changedInstr(MI);
2918 return Legalized;
2921 case TargetOpcode::G_SELECT:
2922 Observer.changingInstr(MI);
2923 if (TypeIdx == 0) {
2924 // Perform operation at larger width (any extension is fine here, high
2925 // bits don't affect the result) and then truncate the result back to the
2926 // original type.
2927 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2928 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2929 widenScalarDst(MI, WideTy);
2930 } else {
2931 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
2932 // Explicit extension is required here since high bits affect the result.
2933 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
2935 Observer.changedInstr(MI);
2936 return Legalized;
2938 case TargetOpcode::G_FPTOSI:
2939 case TargetOpcode::G_FPTOUI:
2940 case TargetOpcode::G_INTRINSIC_LRINT:
2941 case TargetOpcode::G_INTRINSIC_LLRINT:
2942 case TargetOpcode::G_IS_FPCLASS:
2943 Observer.changingInstr(MI);
2945 if (TypeIdx == 0)
2946 widenScalarDst(MI, WideTy);
2947 else
2948 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
2950 Observer.changedInstr(MI);
2951 return Legalized;
2952 case TargetOpcode::G_SITOFP:
2953 Observer.changingInstr(MI);
2955 if (TypeIdx == 0)
2956 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2957 else
2958 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2960 Observer.changedInstr(MI);
2961 return Legalized;
2962 case TargetOpcode::G_UITOFP:
2963 Observer.changingInstr(MI);
2965 if (TypeIdx == 0)
2966 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
2967 else
2968 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
2970 Observer.changedInstr(MI);
2971 return Legalized;
2972 case TargetOpcode::G_FPTOSI_SAT:
2973 case TargetOpcode::G_FPTOUI_SAT:
2974 Observer.changingInstr(MI);
2976 if (TypeIdx == 0) {
2977 Register OldDst = MI.getOperand(0).getReg();
2978 LLT Ty = MRI.getType(OldDst);
2979 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
2980 Register NewDst;
2981 MI.getOperand(0).setReg(ExtReg);
2982 uint64_t ShortBits = Ty.getScalarSizeInBits();
2983 uint64_t WideBits = WideTy.getScalarSizeInBits();
2984 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2985 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
2986 // z = i16 fptosi_sat(a)
2987 // ->
2988 // x = i32 fptosi_sat(a)
2989 // y = smin(x, 32767)
2990 // z = smax(y, -32768)
2991 auto MaxVal = MIRBuilder.buildConstant(
2992 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
2993 auto MinVal = MIRBuilder.buildConstant(
2994 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
2995 Register MidReg =
2996 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
2997 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
2998 } else {
2999 // z = i16 fptoui_sat(a)
3000 // ->
3001 // x = i32 fptoui_sat(a)
3002 // y = smin(x, 65535)
3003 auto MaxVal = MIRBuilder.buildConstant(
3004 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3005 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3007 MIRBuilder.buildTrunc(OldDst, NewDst);
3008 } else
3009 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
3011 Observer.changedInstr(MI);
3012 return Legalized;
3013 case TargetOpcode::G_LOAD:
3014 case TargetOpcode::G_SEXTLOAD:
3015 case TargetOpcode::G_ZEXTLOAD:
3016 Observer.changingInstr(MI);
3017 widenScalarDst(MI, WideTy);
3018 Observer.changedInstr(MI);
3019 return Legalized;
3021 case TargetOpcode::G_STORE: {
3022 if (TypeIdx != 0)
3023 return UnableToLegalize;
3025 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3026 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3027 if (!Ty.isScalar()) {
3028 // We need to widen the vector element type.
3029 Observer.changingInstr(MI);
3030 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3031 // We also need to adjust the MMO to turn this into a truncating store.
3032 MachineMemOperand &MMO = **MI.memoperands_begin();
3033 MachineFunction &MF = MIRBuilder.getMF();
3034 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3035 MI.setMemRefs(MF, {NewMMO});
3036 Observer.changedInstr(MI);
3037 return Legalized;
3040 Observer.changingInstr(MI);
3042 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3043 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3044 widenScalarSrc(MI, WideTy, 0, ExtType);
3046 Observer.changedInstr(MI);
3047 return Legalized;
3049 case TargetOpcode::G_CONSTANT: {
3050 MachineOperand &SrcMO = MI.getOperand(1);
3051 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3052 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3053 MRI.getType(MI.getOperand(0).getReg()));
3054 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3055 ExtOpc == TargetOpcode::G_ANYEXT) &&
3056 "Illegal Extend");
3057 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3058 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3059 ? SrcVal.sext(WideTy.getSizeInBits())
3060 : SrcVal.zext(WideTy.getSizeInBits());
3061 Observer.changingInstr(MI);
3062 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3064 widenScalarDst(MI, WideTy);
3065 Observer.changedInstr(MI);
3066 return Legalized;
3068 case TargetOpcode::G_FCONSTANT: {
3069 // To avoid changing the bits of the constant due to extension to a larger
3070 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3071 MachineOperand &SrcMO = MI.getOperand(1);
3072 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3073 MIRBuilder.setInstrAndDebugLoc(MI);
3074 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3075 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3076 MI.eraseFromParent();
3077 return Legalized;
3079 case TargetOpcode::G_IMPLICIT_DEF: {
3080 Observer.changingInstr(MI);
3081 widenScalarDst(MI, WideTy);
3082 Observer.changedInstr(MI);
3083 return Legalized;
3085 case TargetOpcode::G_BRCOND:
3086 Observer.changingInstr(MI);
3087 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3088 Observer.changedInstr(MI);
3089 return Legalized;
3091 case TargetOpcode::G_FCMP:
3092 Observer.changingInstr(MI);
3093 if (TypeIdx == 0)
3094 widenScalarDst(MI, WideTy);
3095 else {
3096 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
3097 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);
3099 Observer.changedInstr(MI);
3100 return Legalized;
3102 case TargetOpcode::G_ICMP:
3103 Observer.changingInstr(MI);
3104 if (TypeIdx == 0)
3105 widenScalarDst(MI, WideTy);
3106 else {
3107 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3108 CmpInst::Predicate Pred =
3109 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3111 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3112 unsigned ExtOpcode =
3113 (CmpInst::isSigned(Pred) ||
3114 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3115 getApproximateEVTForLLT(WideTy, Ctx)))
3116 ? TargetOpcode::G_SEXT
3117 : TargetOpcode::G_ZEXT;
3118 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3119 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3121 Observer.changedInstr(MI);
3122 return Legalized;
3124 case TargetOpcode::G_PTR_ADD:
3125 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3126 Observer.changingInstr(MI);
3127 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3128 Observer.changedInstr(MI);
3129 return Legalized;
3131 case TargetOpcode::G_PHI: {
3132 assert(TypeIdx == 0 && "Expecting only Idx 0");
3134 Observer.changingInstr(MI);
3135 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3136 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3137 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3138 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3141 MachineBasicBlock &MBB = *MI.getParent();
3142 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3143 widenScalarDst(MI, WideTy);
3144 Observer.changedInstr(MI);
3145 return Legalized;
3147 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3148 if (TypeIdx == 0) {
3149 Register VecReg = MI.getOperand(1).getReg();
3150 LLT VecTy = MRI.getType(VecReg);
3151 Observer.changingInstr(MI);
3153 widenScalarSrc(
3154 MI, LLT::vector(VecTy.getElementCount(), WideTy.getSizeInBits()), 1,
3155 TargetOpcode::G_ANYEXT);
3157 widenScalarDst(MI, WideTy, 0);
3158 Observer.changedInstr(MI);
3159 return Legalized;
3162 if (TypeIdx != 2)
3163 return UnableToLegalize;
3164 Observer.changingInstr(MI);
3165 // TODO: Probably should be zext
3166 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3167 Observer.changedInstr(MI);
3168 return Legalized;
3170 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3171 if (TypeIdx == 0) {
3172 Observer.changingInstr(MI);
3173 const LLT WideEltTy = WideTy.getElementType();
3175 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3176 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3177 widenScalarDst(MI, WideTy, 0);
3178 Observer.changedInstr(MI);
3179 return Legalized;
3182 if (TypeIdx == 1) {
3183 Observer.changingInstr(MI);
3185 Register VecReg = MI.getOperand(1).getReg();
3186 LLT VecTy = MRI.getType(VecReg);
3187 LLT WideVecTy = LLT::vector(VecTy.getElementCount(), WideTy);
3189 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3190 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3191 widenScalarDst(MI, WideVecTy, 0);
3192 Observer.changedInstr(MI);
3193 return Legalized;
3196 if (TypeIdx == 2) {
3197 Observer.changingInstr(MI);
3198 // TODO: Probably should be zext
3199 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3200 Observer.changedInstr(MI);
3201 return Legalized;
3204 return UnableToLegalize;
3206 case TargetOpcode::G_FADD:
3207 case TargetOpcode::G_FMUL:
3208 case TargetOpcode::G_FSUB:
3209 case TargetOpcode::G_FMA:
3210 case TargetOpcode::G_FMAD:
3211 case TargetOpcode::G_FNEG:
3212 case TargetOpcode::G_FABS:
3213 case TargetOpcode::G_FCANONICALIZE:
3214 case TargetOpcode::G_FMINNUM:
3215 case TargetOpcode::G_FMAXNUM:
3216 case TargetOpcode::G_FMINNUM_IEEE:
3217 case TargetOpcode::G_FMAXNUM_IEEE:
3218 case TargetOpcode::G_FMINIMUM:
3219 case TargetOpcode::G_FMAXIMUM:
3220 case TargetOpcode::G_FDIV:
3221 case TargetOpcode::G_FREM:
3222 case TargetOpcode::G_FCEIL:
3223 case TargetOpcode::G_FFLOOR:
3224 case TargetOpcode::G_FCOS:
3225 case TargetOpcode::G_FSIN:
3226 case TargetOpcode::G_FTAN:
3227 case TargetOpcode::G_FACOS:
3228 case TargetOpcode::G_FASIN:
3229 case TargetOpcode::G_FATAN:
3230 case TargetOpcode::G_FATAN2:
3231 case TargetOpcode::G_FCOSH:
3232 case TargetOpcode::G_FSINH:
3233 case TargetOpcode::G_FTANH:
3234 case TargetOpcode::G_FLOG10:
3235 case TargetOpcode::G_FLOG:
3236 case TargetOpcode::G_FLOG2:
3237 case TargetOpcode::G_FRINT:
3238 case TargetOpcode::G_FNEARBYINT:
3239 case TargetOpcode::G_FSQRT:
3240 case TargetOpcode::G_FEXP:
3241 case TargetOpcode::G_FEXP2:
3242 case TargetOpcode::G_FEXP10:
3243 case TargetOpcode::G_FPOW:
3244 case TargetOpcode::G_INTRINSIC_TRUNC:
3245 case TargetOpcode::G_INTRINSIC_ROUND:
3246 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3247 assert(TypeIdx == 0);
3248 Observer.changingInstr(MI);
3250 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3251 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_FPEXT);
3253 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
3254 Observer.changedInstr(MI);
3255 return Legalized;
3256 case TargetOpcode::G_FPOWI:
3257 case TargetOpcode::G_FLDEXP:
3258 case TargetOpcode::G_STRICT_FLDEXP: {
3259 if (TypeIdx == 0) {
3260 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3261 return UnableToLegalize;
3263 Observer.changingInstr(MI);
3264 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_FPEXT);
3265 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
3266 Observer.changedInstr(MI);
3267 return Legalized;
3270 if (TypeIdx == 1) {
3271 // For some reason SelectionDAG tries to promote to a libcall without
3272 // actually changing the integer type for promotion.
3273 Observer.changingInstr(MI);
3274 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3275 Observer.changedInstr(MI);
3276 return Legalized;
3279 return UnableToLegalize;
3281 case TargetOpcode::G_FFREXP: {
3282 Observer.changingInstr(MI);
3284 if (TypeIdx == 0) {
3285 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
3286 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
3287 } else {
3288 widenScalarDst(MI, WideTy, 1);
3291 Observer.changedInstr(MI);
3292 return Legalized;
3294 case TargetOpcode::G_INTTOPTR:
3295 if (TypeIdx != 1)
3296 return UnableToLegalize;
3298 Observer.changingInstr(MI);
3299 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3300 Observer.changedInstr(MI);
3301 return Legalized;
3302 case TargetOpcode::G_PTRTOINT:
3303 if (TypeIdx != 0)
3304 return UnableToLegalize;
3306 Observer.changingInstr(MI);
3307 widenScalarDst(MI, WideTy, 0);
3308 Observer.changedInstr(MI);
3309 return Legalized;
3310 case TargetOpcode::G_BUILD_VECTOR: {
3311 Observer.changingInstr(MI);
3313 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3314 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3315 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3317 // Avoid changing the result vector type if the source element type was
3318 // requested.
3319 if (TypeIdx == 1) {
3320 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3321 } else {
3322 widenScalarDst(MI, WideTy, 0);
3325 Observer.changedInstr(MI);
3326 return Legalized;
3328 case TargetOpcode::G_SEXT_INREG:
3329 if (TypeIdx != 0)
3330 return UnableToLegalize;
3332 Observer.changingInstr(MI);
3333 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3334 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3335 Observer.changedInstr(MI);
3336 return Legalized;
3337 case TargetOpcode::G_PTRMASK: {
3338 if (TypeIdx != 1)
3339 return UnableToLegalize;
3340 Observer.changingInstr(MI);
3341 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3342 Observer.changedInstr(MI);
3343 return Legalized;
3345 case TargetOpcode::G_VECREDUCE_FADD:
3346 case TargetOpcode::G_VECREDUCE_FMUL:
3347 case TargetOpcode::G_VECREDUCE_FMIN:
3348 case TargetOpcode::G_VECREDUCE_FMAX:
3349 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3350 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3351 if (TypeIdx != 0)
3352 return UnableToLegalize;
3353 Observer.changingInstr(MI);
3354 Register VecReg = MI.getOperand(1).getReg();
3355 LLT VecTy = MRI.getType(VecReg);
3356 LLT WideVecTy = VecTy.isVector()
3357 ? LLT::vector(VecTy.getElementCount(), WideTy)
3358 : WideTy;
3359 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_FPEXT);
3360 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
3361 Observer.changedInstr(MI);
3362 return Legalized;
3364 case TargetOpcode::G_VSCALE: {
3365 MachineOperand &SrcMO = MI.getOperand(1);
3366 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3367 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3368 // The CImm is always a signed value
3369 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3370 Observer.changingInstr(MI);
3371 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3372 widenScalarDst(MI, WideTy);
3373 Observer.changedInstr(MI);
3374 return Legalized;
3376 case TargetOpcode::G_SPLAT_VECTOR: {
3377 if (TypeIdx != 1)
3378 return UnableToLegalize;
3380 Observer.changingInstr(MI);
3381 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3382 Observer.changedInstr(MI);
3383 return Legalized;
3385 case TargetOpcode::G_INSERT_SUBVECTOR: {
3386 if (TypeIdx != 0)
3387 return UnableToLegalize;
3389 GInsertSubvector &IS = cast<GInsertSubvector>(MI);
3390 Register BigVec = IS.getBigVec();
3391 Register SubVec = IS.getSubVec();
3393 LLT SubVecTy = MRI.getType(SubVec);
3394 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3396 // Widen the G_INSERT_SUBVECTOR
3397 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3398 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3399 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3400 IS.getIndexImm());
3402 // Truncate back down
3403 auto SplatZero = MIRBuilder.buildSplatVector(
3404 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3405 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3406 SplatZero);
3408 MI.eraseFromParent();
3410 return Legalized;
3415 static void getUnmergePieces(SmallVectorImpl<Register> &Pieces,
3416 MachineIRBuilder &B, Register Src, LLT Ty) {
3417 auto Unmerge = B.buildUnmerge(Ty, Src);
3418 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3419 Pieces.push_back(Unmerge.getReg(I));
3422 static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3423 MachineIRBuilder &MIRBuilder) {
3424 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3425 MachineFunction &MF = MIRBuilder.getMF();
3426 const DataLayout &DL = MIRBuilder.getDataLayout();
3427 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3428 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3429 LLT DstLLT = MRI.getType(DstReg);
3431 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3433 auto Addr = MIRBuilder.buildConstantPool(
3434 AddrPtrTy,
3435 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3437 MachineMemOperand *MMO =
3438 MF.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF),
3439 MachineMemOperand::MOLoad, DstLLT, Alignment);
3441 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3444 LegalizerHelper::LegalizeResult
3445 LegalizerHelper::lowerConstant(MachineInstr &MI) {
3446 const MachineOperand &ConstOperand = MI.getOperand(1);
3447 const Constant *ConstantVal = ConstOperand.getCImm();
3449 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3450 MI.eraseFromParent();
3452 return Legalized;
3455 LegalizerHelper::LegalizeResult
3456 LegalizerHelper::lowerFConstant(MachineInstr &MI) {
3457 const MachineOperand &ConstOperand = MI.getOperand(1);
3458 const Constant *ConstantVal = ConstOperand.getFPImm();
3460 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3461 MI.eraseFromParent();
3463 return Legalized;
3466 LegalizerHelper::LegalizeResult
3467 LegalizerHelper::lowerBitcast(MachineInstr &MI) {
3468 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3469 if (SrcTy.isVector()) {
3470 LLT SrcEltTy = SrcTy.getElementType();
3471 SmallVector<Register, 8> SrcRegs;
3473 if (DstTy.isVector()) {
3474 int NumDstElt = DstTy.getNumElements();
3475 int NumSrcElt = SrcTy.getNumElements();
3477 LLT DstEltTy = DstTy.getElementType();
3478 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3479 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3481 // If there's an element size mismatch, insert intermediate casts to match
3482 // the result element type.
3483 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3484 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3486 // =>
3488 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3489 // %3:_(<2 x s8>) = G_BITCAST %2
3490 // %4:_(<2 x s8>) = G_BITCAST %3
3491 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3492 DstCastTy = LLT::fixed_vector(NumDstElt / NumSrcElt, DstEltTy);
3493 SrcPartTy = SrcEltTy;
3494 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3496 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3498 // =>
3500 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3501 // %3:_(s16) = G_BITCAST %2
3502 // %4:_(s16) = G_BITCAST %3
3503 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3504 SrcPartTy = LLT::fixed_vector(NumSrcElt / NumDstElt, SrcEltTy);
3505 DstCastTy = DstEltTy;
3508 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3509 for (Register &SrcReg : SrcRegs)
3510 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3511 } else
3512 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3514 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3515 MI.eraseFromParent();
3516 return Legalized;
3519 if (DstTy.isVector()) {
3520 SmallVector<Register, 8> SrcRegs;
3521 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3522 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3523 MI.eraseFromParent();
3524 return Legalized;
3527 return UnableToLegalize;
3530 /// Figure out the bit offset into a register when coercing a vector index for
3531 /// the wide element type. This is only for the case when promoting vector to
3532 /// one with larger elements.
3535 /// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3536 /// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3537 static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B,
3538 Register Idx,
3539 unsigned NewEltSize,
3540 unsigned OldEltSize) {
3541 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3542 LLT IdxTy = B.getMRI()->getType(Idx);
3544 // Now figure out the amount we need to shift to get the target bits.
3545 auto OffsetMask = B.buildConstant(
3546 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3547 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3548 return B.buildShl(IdxTy, OffsetIdx,
3549 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3552 /// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3553 /// is casting to a vector with a smaller element size, perform multiple element
3554 /// extracts and merge the results. If this is coercing to a vector with larger
3555 /// elements, index the bitcasted vector and extract the target element with bit
3556 /// operations. This is intended to force the indexing in the native register
3557 /// size for architectures that can dynamically index the register file.
3558 LegalizerHelper::LegalizeResult
3559 LegalizerHelper::bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx,
3560 LLT CastTy) {
3561 if (TypeIdx != 1)
3562 return UnableToLegalize;
3564 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3566 LLT SrcEltTy = SrcVecTy.getElementType();
3567 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3568 unsigned OldNumElts = SrcVecTy.getNumElements();
3570 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3571 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3573 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3574 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3575 if (NewNumElts > OldNumElts) {
3576 // Decreasing the vector element size
3578 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3579 // =>
3580 // v4i32:castx = bitcast x:v2i64
3582 // i64 = bitcast
3583 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3584 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3586 if (NewNumElts % OldNumElts != 0)
3587 return UnableToLegalize;
3589 // Type of the intermediate result vector.
3590 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3591 LLT MidTy =
3592 LLT::scalarOrVector(ElementCount::getFixed(NewEltsPerOldElt), NewEltTy);
3594 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3596 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3597 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3599 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3600 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3601 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3602 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3603 NewOps[I] = Elt.getReg(0);
3606 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3607 MIRBuilder.buildBitcast(Dst, NewVec);
3608 MI.eraseFromParent();
3609 return Legalized;
3612 if (NewNumElts < OldNumElts) {
3613 if (NewEltSize % OldEltSize != 0)
3614 return UnableToLegalize;
3616 // This only depends on powers of 2 because we use bit tricks to figure out
3617 // the bit offset we need to shift to get the target element. A general
3618 // expansion could emit division/multiply.
3619 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3620 return UnableToLegalize;
3622 // Increasing the vector element size.
3623 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3625 // =>
3627 // %cast = G_BITCAST %vec
3628 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3629 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3630 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3631 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3632 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3633 // %elt = G_TRUNC %elt_bits
3635 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3636 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3638 // Divide to get the index in the wider element type.
3639 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3641 Register WideElt = CastVec;
3642 if (CastTy.isVector()) {
3643 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3644 ScaledIdx).getReg(0);
3647 // Compute the bit offset into the register of the target element.
3648 Register OffsetBits = getBitcastWiderVectorElementOffset(
3649 MIRBuilder, Idx, NewEltSize, OldEltSize);
3651 // Shift the wide element to get the target element.
3652 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3653 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3654 MI.eraseFromParent();
3655 return Legalized;
3658 return UnableToLegalize;
3661 /// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3662 /// TargetReg, while preserving other bits in \p TargetReg.
3664 /// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3665 static Register buildBitFieldInsert(MachineIRBuilder &B,
3666 Register TargetReg, Register InsertReg,
3667 Register OffsetBits) {
3668 LLT TargetTy = B.getMRI()->getType(TargetReg);
3669 LLT InsertTy = B.getMRI()->getType(InsertReg);
3670 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3671 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3673 // Produce a bitmask of the value to insert
3674 auto EltMask = B.buildConstant(
3675 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3676 InsertTy.getSizeInBits()));
3677 // Shift it into position
3678 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3679 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3681 // Clear out the bits in the wide element
3682 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3684 // The value to insert has all zeros already, so stick it into the masked
3685 // wide element.
3686 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3689 /// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3690 /// is increasing the element size, perform the indexing in the target element
3691 /// type, and use bit operations to insert at the element position. This is
3692 /// intended for architectures that can dynamically index the register file and
3693 /// want to force indexing in the native register size.
3694 LegalizerHelper::LegalizeResult
3695 LegalizerHelper::bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx,
3696 LLT CastTy) {
3697 if (TypeIdx != 0)
3698 return UnableToLegalize;
3700 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3701 MI.getFirst4RegLLTs();
3702 LLT VecTy = DstTy;
3704 LLT VecEltTy = VecTy.getElementType();
3705 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3706 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3707 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3709 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3710 unsigned OldNumElts = VecTy.getNumElements();
3712 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3713 if (NewNumElts < OldNumElts) {
3714 if (NewEltSize % OldEltSize != 0)
3715 return UnableToLegalize;
3717 // This only depends on powers of 2 because we use bit tricks to figure out
3718 // the bit offset we need to shift to get the target element. A general
3719 // expansion could emit division/multiply.
3720 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3721 return UnableToLegalize;
3723 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3724 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3726 // Divide to get the index in the wider element type.
3727 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3729 Register ExtractedElt = CastVec;
3730 if (CastTy.isVector()) {
3731 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3732 ScaledIdx).getReg(0);
3735 // Compute the bit offset into the register of the target element.
3736 Register OffsetBits = getBitcastWiderVectorElementOffset(
3737 MIRBuilder, Idx, NewEltSize, OldEltSize);
3739 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
3740 Val, OffsetBits);
3741 if (CastTy.isVector()) {
3742 InsertedElt = MIRBuilder.buildInsertVectorElement(
3743 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
3746 MIRBuilder.buildBitcast(Dst, InsertedElt);
3747 MI.eraseFromParent();
3748 return Legalized;
3751 return UnableToLegalize;
3754 // This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
3755 // those that have smaller than legal operands.
3757 // <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
3759 // ===>
3761 // s32 = G_BITCAST <4 x s8>
3762 // s32 = G_BITCAST <4 x s8>
3763 // s32 = G_BITCAST <4 x s8>
3764 // s32 = G_BITCAST <4 x s8>
3765 // <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
3766 // <16 x s8> = G_BITCAST <4 x s32>
3767 LegalizerHelper::LegalizeResult
3768 LegalizerHelper::bitcastConcatVector(MachineInstr &MI, unsigned TypeIdx,
3769 LLT CastTy) {
3770 // Convert it to CONCAT instruction
3771 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
3772 if (!ConcatMI) {
3773 return UnableToLegalize;
3776 // Check if bitcast is Legal
3777 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
3778 LLT SrcScalTy = LLT::scalar(SrcTy.getSizeInBits());
3780 // Check if the build vector is Legal
3781 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
3782 return UnableToLegalize;
3785 // Bitcast the sources
3786 SmallVector<Register> BitcastRegs;
3787 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
3788 BitcastRegs.push_back(
3789 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
3790 .getReg(0));
3793 // Build the scalar values into a vector
3794 Register BuildReg =
3795 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
3796 MIRBuilder.buildBitcast(DstReg, BuildReg);
3798 MI.eraseFromParent();
3799 return Legalized;
3802 // This bitcasts a shuffle vector to a different type currently of the same
3803 // element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
3804 // will be used instead.
3806 // <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
3807 // ===>
3808 // <4 x s64> = G_PTRTOINT <4 x p0>
3809 // <4 x s64> = G_PTRTOINT <4 x p0>
3810 // <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
3811 // <16 x p0> = G_INTTOPTR <16 x s64>
3812 LegalizerHelper::LegalizeResult
3813 LegalizerHelper::bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx,
3814 LLT CastTy) {
3815 auto ShuffleMI = cast<GShuffleVector>(&MI);
3816 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
3817 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
3819 // We currently only handle vectors of the same size.
3820 if (TypeIdx != 0 ||
3821 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
3822 CastTy.getElementCount() != DstTy.getElementCount())
3823 return UnableToLegalize;
3825 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
3827 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
3828 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
3829 auto Shuf =
3830 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
3831 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
3833 MI.eraseFromParent();
3834 return Legalized;
3837 /// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
3839 /// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
3841 /// ===>
3843 /// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
3844 /// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
3845 /// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
3846 LegalizerHelper::LegalizeResult
3847 LegalizerHelper::bitcastExtractSubvector(MachineInstr &MI, unsigned TypeIdx,
3848 LLT CastTy) {
3849 auto ES = cast<GExtractSubvector>(&MI);
3851 if (!CastTy.isVector())
3852 return UnableToLegalize;
3854 if (TypeIdx != 0)
3855 return UnableToLegalize;
3857 Register Dst = ES->getReg(0);
3858 Register Src = ES->getSrcVec();
3859 uint64_t Idx = ES->getIndexImm();
3861 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3863 LLT DstTy = MRI.getType(Dst);
3864 LLT SrcTy = MRI.getType(Src);
3865 ElementCount DstTyEC = DstTy.getElementCount();
3866 ElementCount SrcTyEC = SrcTy.getElementCount();
3867 auto DstTyMinElts = DstTyEC.getKnownMinValue();
3868 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
3870 if (DstTy == CastTy)
3871 return Legalized;
3873 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
3874 return UnableToLegalize;
3876 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
3877 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
3878 if (CastEltSize < DstEltSize)
3879 return UnableToLegalize;
3881 auto AdjustAmt = CastEltSize / DstEltSize;
3882 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
3883 SrcTyMinElts % AdjustAmt != 0)
3884 return UnableToLegalize;
3886 Idx /= AdjustAmt;
3887 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
3888 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
3889 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
3890 MIRBuilder.buildBitcast(Dst, PromotedES);
3892 ES->eraseFromParent();
3893 return Legalized;
3896 /// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
3898 /// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
3899 /// <vscale x 8 x i1>,
3900 /// N
3902 /// ===>
3904 /// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
3905 /// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
3906 /// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
3907 /// <vscale x 1 x i8>, N / 8
3908 /// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
3909 LegalizerHelper::LegalizeResult
3910 LegalizerHelper::bitcastInsertSubvector(MachineInstr &MI, unsigned TypeIdx,
3911 LLT CastTy) {
3912 auto ES = cast<GInsertSubvector>(&MI);
3914 if (!CastTy.isVector())
3915 return UnableToLegalize;
3917 if (TypeIdx != 0)
3918 return UnableToLegalize;
3920 Register Dst = ES->getReg(0);
3921 Register BigVec = ES->getBigVec();
3922 Register SubVec = ES->getSubVec();
3923 uint64_t Idx = ES->getIndexImm();
3925 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3927 LLT DstTy = MRI.getType(Dst);
3928 LLT BigVecTy = MRI.getType(BigVec);
3929 LLT SubVecTy = MRI.getType(SubVec);
3931 if (DstTy == CastTy)
3932 return Legalized;
3934 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
3935 return UnableToLegalize;
3937 ElementCount DstTyEC = DstTy.getElementCount();
3938 ElementCount BigVecTyEC = BigVecTy.getElementCount();
3939 ElementCount SubVecTyEC = SubVecTy.getElementCount();
3940 auto DstTyMinElts = DstTyEC.getKnownMinValue();
3941 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
3942 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
3944 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
3945 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
3946 if (CastEltSize < DstEltSize)
3947 return UnableToLegalize;
3949 auto AdjustAmt = CastEltSize / DstEltSize;
3950 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
3951 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
3952 return UnableToLegalize;
3954 Idx /= AdjustAmt;
3955 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
3956 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
3957 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
3958 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
3959 auto PromotedIS =
3960 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
3961 MIRBuilder.buildBitcast(Dst, PromotedIS);
3963 ES->eraseFromParent();
3964 return Legalized;
3967 LegalizerHelper::LegalizeResult LegalizerHelper::lowerLoad(GAnyLoad &LoadMI) {
3968 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
3969 Register DstReg = LoadMI.getDstReg();
3970 Register PtrReg = LoadMI.getPointerReg();
3971 LLT DstTy = MRI.getType(DstReg);
3972 MachineMemOperand &MMO = LoadMI.getMMO();
3973 LLT MemTy = MMO.getMemoryType();
3974 MachineFunction &MF = MIRBuilder.getMF();
3976 unsigned MemSizeInBits = MemTy.getSizeInBits();
3977 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
3979 if (MemSizeInBits != MemStoreSizeInBits) {
3980 if (MemTy.isVector())
3981 return UnableToLegalize;
3983 // Promote to a byte-sized load if not loading an integral number of
3984 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
3985 LLT WideMemTy = LLT::scalar(MemStoreSizeInBits);
3986 MachineMemOperand *NewMMO =
3987 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
3989 Register LoadReg = DstReg;
3990 LLT LoadTy = DstTy;
3992 // If this wasn't already an extending load, we need to widen the result
3993 // register to avoid creating a load with a narrower result than the source.
3994 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
3995 LoadTy = WideMemTy;
3996 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
3999 if (isa<GSExtLoad>(LoadMI)) {
4000 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4001 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4002 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4003 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4004 // The extra bits are guaranteed to be zero, since we stored them that
4005 // way. A zext load from Wide thus automatically gives zext from MemVT.
4006 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4007 } else {
4008 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4011 if (DstTy != LoadTy)
4012 MIRBuilder.buildTrunc(DstReg, LoadReg);
4014 LoadMI.eraseFromParent();
4015 return Legalized;
4018 // Big endian lowering not implemented.
4019 if (MIRBuilder.getDataLayout().isBigEndian())
4020 return UnableToLegalize;
4022 // This load needs splitting into power of 2 sized loads.
4024 // Our strategy here is to generate anyextending loads for the smaller
4025 // types up to next power-2 result type, and then combine the two larger
4026 // result values together, before truncating back down to the non-pow-2
4027 // type.
4028 // E.g. v1 = i24 load =>
4029 // v2 = i32 zextload (2 byte)
4030 // v3 = i32 load (1 byte)
4031 // v4 = i32 shl v3, 16
4032 // v5 = i32 or v4, v2
4033 // v1 = i24 trunc v5
4034 // By doing this we generate the correct truncate which should get
4035 // combined away as an artifact with a matching extend.
4037 uint64_t LargeSplitSize, SmallSplitSize;
4039 if (!isPowerOf2_32(MemSizeInBits)) {
4040 // This load needs splitting into power of 2 sized loads.
4041 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4042 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4043 } else {
4044 // This is already a power of 2, but we still need to split this in half.
4046 // Assume we're being asked to decompose an unaligned load.
4047 // TODO: If this requires multiple splits, handle them all at once.
4048 auto &Ctx = MF.getFunction().getContext();
4049 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4050 return UnableToLegalize;
4052 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4055 if (MemTy.isVector()) {
4056 // TODO: Handle vector extloads
4057 if (MemTy != DstTy)
4058 return UnableToLegalize;
4060 // TODO: We can do better than scalarizing the vector and at least split it
4061 // in half.
4062 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4065 MachineMemOperand *LargeMMO =
4066 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4067 MachineMemOperand *SmallMMO =
4068 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4070 LLT PtrTy = MRI.getType(PtrReg);
4071 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4072 LLT AnyExtTy = LLT::scalar(AnyExtSize);
4073 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4074 PtrReg, *LargeMMO);
4076 auto OffsetCst = MIRBuilder.buildConstant(LLT::scalar(PtrTy.getSizeInBits()),
4077 LargeSplitSize / 8);
4078 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4079 auto SmallPtr = MIRBuilder.buildPtrAdd(PtrAddReg, PtrReg, OffsetCst);
4080 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4081 SmallPtr, *SmallMMO);
4083 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4084 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4086 if (AnyExtTy == DstTy)
4087 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4088 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4089 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4090 MIRBuilder.buildTrunc(DstReg, {Or});
4091 } else {
4092 assert(DstTy.isPointer() && "expected pointer");
4093 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4095 // FIXME: We currently consider this to be illegal for non-integral address
4096 // spaces, but we need still need a way to reinterpret the bits.
4097 MIRBuilder.buildIntToPtr(DstReg, Or);
4100 LoadMI.eraseFromParent();
4101 return Legalized;
4104 LegalizerHelper::LegalizeResult LegalizerHelper::lowerStore(GStore &StoreMI) {
4105 // Lower a non-power of 2 store into multiple pow-2 stores.
4106 // E.g. split an i24 store into an i16 store + i8 store.
4107 // We do this by first extending the stored value to the next largest power
4108 // of 2 type, and then using truncating stores to store the components.
4109 // By doing this, likewise with G_LOAD, generate an extend that can be
4110 // artifact-combined away instead of leaving behind extracts.
4111 Register SrcReg = StoreMI.getValueReg();
4112 Register PtrReg = StoreMI.getPointerReg();
4113 LLT SrcTy = MRI.getType(SrcReg);
4114 MachineFunction &MF = MIRBuilder.getMF();
4115 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4116 LLT MemTy = MMO.getMemoryType();
4118 unsigned StoreWidth = MemTy.getSizeInBits();
4119 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4121 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4122 // Promote to a byte-sized store with upper bits zero if not
4123 // storing an integral number of bytes. For example, promote
4124 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4125 LLT WideTy = LLT::scalar(StoreSizeInBits);
4127 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4128 // Avoid creating a store with a narrower source than result.
4129 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4130 SrcTy = WideTy;
4133 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4135 MachineMemOperand *NewMMO =
4136 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4137 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4138 StoreMI.eraseFromParent();
4139 return Legalized;
4142 if (MemTy.isVector()) {
4143 if (MemTy != SrcTy)
4144 return scalarizeVectorBooleanStore(StoreMI);
4146 // TODO: We can do better than scalarizing the vector and at least split it
4147 // in half.
4148 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4151 unsigned MemSizeInBits = MemTy.getSizeInBits();
4152 uint64_t LargeSplitSize, SmallSplitSize;
4154 if (!isPowerOf2_32(MemSizeInBits)) {
4155 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4156 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4157 } else {
4158 auto &Ctx = MF.getFunction().getContext();
4159 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4160 return UnableToLegalize; // Don't know what we're being asked to do.
4162 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4165 // Extend to the next pow-2. If this store was itself the result of lowering,
4166 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4167 // that's wider than the stored size.
4168 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4169 const LLT NewSrcTy = LLT::scalar(AnyExtSize);
4171 if (SrcTy.isPointer()) {
4172 const LLT IntPtrTy = LLT::scalar(SrcTy.getSizeInBits());
4173 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4176 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4178 // Obtain the smaller value by shifting away the larger value.
4179 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4180 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4182 // Generate the PtrAdd and truncating stores.
4183 LLT PtrTy = MRI.getType(PtrReg);
4184 auto OffsetCst = MIRBuilder.buildConstant(
4185 LLT::scalar(PtrTy.getSizeInBits()), LargeSplitSize / 8);
4186 auto SmallPtr =
4187 MIRBuilder.buildPtrAdd(PtrTy, PtrReg, OffsetCst);
4189 MachineMemOperand *LargeMMO =
4190 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4191 MachineMemOperand *SmallMMO =
4192 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4193 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4194 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4195 StoreMI.eraseFromParent();
4196 return Legalized;
4199 LegalizerHelper::LegalizeResult
4200 LegalizerHelper::scalarizeVectorBooleanStore(GStore &StoreMI) {
4201 Register SrcReg = StoreMI.getValueReg();
4202 Register PtrReg = StoreMI.getPointerReg();
4203 LLT SrcTy = MRI.getType(SrcReg);
4204 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4205 LLT MemTy = MMO.getMemoryType();
4206 LLT MemScalarTy = MemTy.getElementType();
4207 MachineFunction &MF = MIRBuilder.getMF();
4209 assert(SrcTy.isVector() && "Expect a vector store type");
4211 if (!MemScalarTy.isByteSized()) {
4212 // We need to build an integer scalar of the vector bit pattern.
4213 // It's not legal for us to add padding when storing a vector.
4214 unsigned NumBits = MemTy.getSizeInBits();
4215 LLT IntTy = LLT::scalar(NumBits);
4216 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4217 LLT IdxTy = getLLTForMVT(TLI.getVectorIdxTy(MF.getDataLayout()));
4219 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4220 auto Elt = MIRBuilder.buildExtractVectorElement(
4221 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4222 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4223 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4224 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4225 ? (MemTy.getNumElements() - 1) - I
4226 : I;
4227 auto ShiftAmt = MIRBuilder.buildConstant(
4228 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4229 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4230 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4232 auto PtrInfo = MMO.getPointerInfo();
4233 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4234 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4235 StoreMI.eraseFromParent();
4236 return Legalized;
4239 // TODO: implement simple scalarization.
4240 return UnableToLegalize;
4243 LegalizerHelper::LegalizeResult
4244 LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4245 switch (MI.getOpcode()) {
4246 case TargetOpcode::G_LOAD: {
4247 if (TypeIdx != 0)
4248 return UnableToLegalize;
4249 MachineMemOperand &MMO = **MI.memoperands_begin();
4251 // Not sure how to interpret a bitcast of an extending load.
4252 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4253 return UnableToLegalize;
4255 Observer.changingInstr(MI);
4256 bitcastDst(MI, CastTy, 0);
4257 MMO.setType(CastTy);
4258 // The range metadata is no longer valid when reinterpreted as a different
4259 // type.
4260 MMO.clearRanges();
4261 Observer.changedInstr(MI);
4262 return Legalized;
4264 case TargetOpcode::G_STORE: {
4265 if (TypeIdx != 0)
4266 return UnableToLegalize;
4268 MachineMemOperand &MMO = **MI.memoperands_begin();
4270 // Not sure how to interpret a bitcast of a truncating store.
4271 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4272 return UnableToLegalize;
4274 Observer.changingInstr(MI);
4275 bitcastSrc(MI, CastTy, 0);
4276 MMO.setType(CastTy);
4277 Observer.changedInstr(MI);
4278 return Legalized;
4280 case TargetOpcode::G_SELECT: {
4281 if (TypeIdx != 0)
4282 return UnableToLegalize;
4284 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4285 LLVM_DEBUG(
4286 dbgs() << "bitcast action not implemented for vector select\n");
4287 return UnableToLegalize;
4290 Observer.changingInstr(MI);
4291 bitcastSrc(MI, CastTy, 2);
4292 bitcastSrc(MI, CastTy, 3);
4293 bitcastDst(MI, CastTy, 0);
4294 Observer.changedInstr(MI);
4295 return Legalized;
4297 case TargetOpcode::G_AND:
4298 case TargetOpcode::G_OR:
4299 case TargetOpcode::G_XOR: {
4300 Observer.changingInstr(MI);
4301 bitcastSrc(MI, CastTy, 1);
4302 bitcastSrc(MI, CastTy, 2);
4303 bitcastDst(MI, CastTy, 0);
4304 Observer.changedInstr(MI);
4305 return Legalized;
4307 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4308 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4309 case TargetOpcode::G_INSERT_VECTOR_ELT:
4310 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4311 case TargetOpcode::G_CONCAT_VECTORS:
4312 return bitcastConcatVector(MI, TypeIdx, CastTy);
4313 case TargetOpcode::G_SHUFFLE_VECTOR:
4314 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4315 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4316 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4317 case TargetOpcode::G_INSERT_SUBVECTOR:
4318 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4319 default:
4320 return UnableToLegalize;
4324 // Legalize an instruction by changing the opcode in place.
4325 void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4326 Observer.changingInstr(MI);
4327 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4328 Observer.changedInstr(MI);
4331 LegalizerHelper::LegalizeResult
4332 LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4333 using namespace TargetOpcode;
4335 switch(MI.getOpcode()) {
4336 default:
4337 return UnableToLegalize;
4338 case TargetOpcode::G_FCONSTANT:
4339 return lowerFConstant(MI);
4340 case TargetOpcode::G_BITCAST:
4341 return lowerBitcast(MI);
4342 case TargetOpcode::G_SREM:
4343 case TargetOpcode::G_UREM: {
4344 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4345 auto Quot =
4346 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4347 {MI.getOperand(1), MI.getOperand(2)});
4349 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4350 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4351 MI.eraseFromParent();
4352 return Legalized;
4354 case TargetOpcode::G_SADDO:
4355 case TargetOpcode::G_SSUBO:
4356 return lowerSADDO_SSUBO(MI);
4357 case TargetOpcode::G_UMULH:
4358 case TargetOpcode::G_SMULH:
4359 return lowerSMULH_UMULH(MI);
4360 case TargetOpcode::G_SMULO:
4361 case TargetOpcode::G_UMULO: {
4362 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4363 // result.
4364 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4365 LLT Ty = MRI.getType(Res);
4367 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4368 ? TargetOpcode::G_SMULH
4369 : TargetOpcode::G_UMULH;
4371 Observer.changingInstr(MI);
4372 const auto &TII = MIRBuilder.getTII();
4373 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4374 MI.removeOperand(1);
4375 Observer.changedInstr(MI);
4377 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4378 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4380 // Move insert point forward so we can use the Res register if needed.
4381 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4383 // For *signed* multiply, overflow is detected by checking:
4384 // (hi != (lo >> bitwidth-1))
4385 if (Opcode == TargetOpcode::G_SMULH) {
4386 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4387 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4388 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4389 } else {
4390 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4392 return Legalized;
4394 case TargetOpcode::G_FNEG: {
4395 auto [Res, SubByReg] = MI.getFirst2Regs();
4396 LLT Ty = MRI.getType(Res);
4398 auto SignMask = MIRBuilder.buildConstant(
4399 Ty, APInt::getSignMask(Ty.getScalarSizeInBits()));
4400 MIRBuilder.buildXor(Res, SubByReg, SignMask);
4401 MI.eraseFromParent();
4402 return Legalized;
4404 case TargetOpcode::G_FSUB:
4405 case TargetOpcode::G_STRICT_FSUB: {
4406 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4407 LLT Ty = MRI.getType(Res);
4409 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4410 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4412 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4413 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4414 else
4415 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4417 MI.eraseFromParent();
4418 return Legalized;
4420 case TargetOpcode::G_FMAD:
4421 return lowerFMad(MI);
4422 case TargetOpcode::G_FFLOOR:
4423 return lowerFFloor(MI);
4424 case TargetOpcode::G_LROUND:
4425 case TargetOpcode::G_LLROUND: {
4426 Register DstReg = MI.getOperand(0).getReg();
4427 Register SrcReg = MI.getOperand(1).getReg();
4428 LLT SrcTy = MRI.getType(SrcReg);
4429 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4430 {SrcReg});
4431 MIRBuilder.buildFPTOSI(DstReg, Round);
4432 MI.eraseFromParent();
4433 return Legalized;
4435 case TargetOpcode::G_INTRINSIC_ROUND:
4436 return lowerIntrinsicRound(MI);
4437 case TargetOpcode::G_FRINT: {
4438 // Since round even is the assumed rounding mode for unconstrained FP
4439 // operations, rint and roundeven are the same operation.
4440 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4441 return Legalized;
4443 case TargetOpcode::G_INTRINSIC_LRINT:
4444 case TargetOpcode::G_INTRINSIC_LLRINT: {
4445 Register DstReg = MI.getOperand(0).getReg();
4446 Register SrcReg = MI.getOperand(1).getReg();
4447 LLT SrcTy = MRI.getType(SrcReg);
4448 auto Round =
4449 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4450 MIRBuilder.buildFPTOSI(DstReg, Round);
4451 MI.eraseFromParent();
4452 return Legalized;
4454 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4455 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4456 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4457 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4458 **MI.memoperands_begin());
4459 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4460 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4461 MI.eraseFromParent();
4462 return Legalized;
4464 case TargetOpcode::G_LOAD:
4465 case TargetOpcode::G_SEXTLOAD:
4466 case TargetOpcode::G_ZEXTLOAD:
4467 return lowerLoad(cast<GAnyLoad>(MI));
4468 case TargetOpcode::G_STORE:
4469 return lowerStore(cast<GStore>(MI));
4470 case TargetOpcode::G_CTLZ_ZERO_UNDEF:
4471 case TargetOpcode::G_CTTZ_ZERO_UNDEF:
4472 case TargetOpcode::G_CTLZ:
4473 case TargetOpcode::G_CTTZ:
4474 case TargetOpcode::G_CTPOP:
4475 return lowerBitCount(MI);
4476 case G_UADDO: {
4477 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4479 Register NewRes = MRI.cloneVirtualRegister(Res);
4481 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4482 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4484 MIRBuilder.buildCopy(Res, NewRes);
4486 MI.eraseFromParent();
4487 return Legalized;
4489 case G_UADDE: {
4490 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4491 const LLT CondTy = MRI.getType(CarryOut);
4492 const LLT Ty = MRI.getType(Res);
4494 Register NewRes = MRI.cloneVirtualRegister(Res);
4496 // Initial add of the two operands.
4497 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4499 // Initial check for carry.
4500 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4502 // Add the sum and the carry.
4503 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4504 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4506 // Second check for carry. We can only carry if the initial sum is all 1s
4507 // and the carry is set, resulting in a new sum of 0.
4508 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4509 auto ResEqZero =
4510 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4511 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4512 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4514 MIRBuilder.buildCopy(Res, NewRes);
4516 MI.eraseFromParent();
4517 return Legalized;
4519 case G_USUBO: {
4520 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4522 MIRBuilder.buildSub(Res, LHS, RHS);
4523 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4525 MI.eraseFromParent();
4526 return Legalized;
4528 case G_USUBE: {
4529 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4530 const LLT CondTy = MRI.getType(BorrowOut);
4531 const LLT Ty = MRI.getType(Res);
4533 // Initial subtract of the two operands.
4534 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4536 // Initial check for borrow.
4537 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4539 // Subtract the borrow from the first subtract.
4540 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4541 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4543 // Second check for borrow. We can only borrow if the initial difference is
4544 // 0 and the borrow is set, resulting in a new difference of all 1s.
4545 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4546 auto TmpResEqZero =
4547 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4548 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4549 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4551 MI.eraseFromParent();
4552 return Legalized;
4554 case G_UITOFP:
4555 return lowerUITOFP(MI);
4556 case G_SITOFP:
4557 return lowerSITOFP(MI);
4558 case G_FPTOUI:
4559 return lowerFPTOUI(MI);
4560 case G_FPTOSI:
4561 return lowerFPTOSI(MI);
4562 case G_FPTOUI_SAT:
4563 case G_FPTOSI_SAT:
4564 return lowerFPTOINT_SAT(MI);
4565 case G_FPTRUNC:
4566 return lowerFPTRUNC(MI);
4567 case G_FPOWI:
4568 return lowerFPOWI(MI);
4569 case G_SMIN:
4570 case G_SMAX:
4571 case G_UMIN:
4572 case G_UMAX:
4573 return lowerMinMax(MI);
4574 case G_SCMP:
4575 case G_UCMP:
4576 return lowerThreewayCompare(MI);
4577 case G_FCOPYSIGN:
4578 return lowerFCopySign(MI);
4579 case G_FMINNUM:
4580 case G_FMAXNUM:
4581 return lowerFMinNumMaxNum(MI);
4582 case G_MERGE_VALUES:
4583 return lowerMergeValues(MI);
4584 case G_UNMERGE_VALUES:
4585 return lowerUnmergeValues(MI);
4586 case TargetOpcode::G_SEXT_INREG: {
4587 assert(MI.getOperand(2).isImm() && "Expected immediate");
4588 int64_t SizeInBits = MI.getOperand(2).getImm();
4590 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4591 LLT DstTy = MRI.getType(DstReg);
4592 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4594 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4595 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4596 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4597 MI.eraseFromParent();
4598 return Legalized;
4600 case G_EXTRACT_VECTOR_ELT:
4601 case G_INSERT_VECTOR_ELT:
4602 return lowerExtractInsertVectorElt(MI);
4603 case G_SHUFFLE_VECTOR:
4604 return lowerShuffleVector(MI);
4605 case G_VECTOR_COMPRESS:
4606 return lowerVECTOR_COMPRESS(MI);
4607 case G_DYN_STACKALLOC:
4608 return lowerDynStackAlloc(MI);
4609 case G_STACKSAVE:
4610 return lowerStackSave(MI);
4611 case G_STACKRESTORE:
4612 return lowerStackRestore(MI);
4613 case G_EXTRACT:
4614 return lowerExtract(MI);
4615 case G_INSERT:
4616 return lowerInsert(MI);
4617 case G_BSWAP:
4618 return lowerBswap(MI);
4619 case G_BITREVERSE:
4620 return lowerBitreverse(MI);
4621 case G_READ_REGISTER:
4622 case G_WRITE_REGISTER:
4623 return lowerReadWriteRegister(MI);
4624 case G_UADDSAT:
4625 case G_USUBSAT: {
4626 // Try to make a reasonable guess about which lowering strategy to use. The
4627 // target can override this with custom lowering and calling the
4628 // implementation functions.
4629 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4630 if (LI.isLegalOrCustom({G_UMIN, Ty}))
4631 return lowerAddSubSatToMinMax(MI);
4632 return lowerAddSubSatToAddoSubo(MI);
4634 case G_SADDSAT:
4635 case G_SSUBSAT: {
4636 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4638 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
4639 // since it's a shorter expansion. However, we would need to figure out the
4640 // preferred boolean type for the carry out for the query.
4641 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
4642 return lowerAddSubSatToMinMax(MI);
4643 return lowerAddSubSatToAddoSubo(MI);
4645 case G_SSHLSAT:
4646 case G_USHLSAT:
4647 return lowerShlSat(MI);
4648 case G_ABS:
4649 return lowerAbsToAddXor(MI);
4650 case G_FABS:
4651 return lowerFAbs(MI);
4652 case G_SELECT:
4653 return lowerSelect(MI);
4654 case G_IS_FPCLASS:
4655 return lowerISFPCLASS(MI);
4656 case G_SDIVREM:
4657 case G_UDIVREM:
4658 return lowerDIVREM(MI);
4659 case G_FSHL:
4660 case G_FSHR:
4661 return lowerFunnelShift(MI);
4662 case G_ROTL:
4663 case G_ROTR:
4664 return lowerRotate(MI);
4665 case G_MEMSET:
4666 case G_MEMCPY:
4667 case G_MEMMOVE:
4668 return lowerMemCpyFamily(MI);
4669 case G_MEMCPY_INLINE:
4670 return lowerMemcpyInline(MI);
4671 case G_ZEXT:
4672 case G_SEXT:
4673 case G_ANYEXT:
4674 return lowerEXT(MI);
4675 case G_TRUNC:
4676 return lowerTRUNC(MI);
4677 GISEL_VECREDUCE_CASES_NONSEQ
4678 return lowerVectorReduction(MI);
4679 case G_VAARG:
4680 return lowerVAArg(MI);
4684 Align LegalizerHelper::getStackTemporaryAlignment(LLT Ty,
4685 Align MinAlign) const {
4686 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
4687 // datalayout for the preferred alignment. Also there should be a target hook
4688 // for this to allow targets to reduce the alignment and ignore the
4689 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
4690 // the type.
4691 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
4694 MachineInstrBuilder
4695 LegalizerHelper::createStackTemporary(TypeSize Bytes, Align Alignment,
4696 MachinePointerInfo &PtrInfo) {
4697 MachineFunction &MF = MIRBuilder.getMF();
4698 const DataLayout &DL = MIRBuilder.getDataLayout();
4699 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
4701 unsigned AddrSpace = DL.getAllocaAddrSpace();
4702 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
4704 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
4705 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
4708 MachineInstrBuilder LegalizerHelper::createStackStoreLoad(const DstOp &Res,
4709 const SrcOp &Val) {
4710 LLT SrcTy = Val.getLLTTy(MRI);
4711 Align StackTypeAlign =
4712 std::max(getStackTemporaryAlignment(SrcTy),
4713 getStackTemporaryAlignment(Res.getLLTTy(MRI)));
4714 MachinePointerInfo PtrInfo;
4715 auto StackTemp =
4716 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
4718 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
4719 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
4722 static Register clampVectorIndex(MachineIRBuilder &B, Register IdxReg,
4723 LLT VecTy) {
4724 LLT IdxTy = B.getMRI()->getType(IdxReg);
4725 unsigned NElts = VecTy.getNumElements();
4727 int64_t IdxVal;
4728 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
4729 if (IdxVal < VecTy.getNumElements())
4730 return IdxReg;
4731 // If a constant index would be out of bounds, clamp it as well.
4734 if (isPowerOf2_32(NElts)) {
4735 APInt Imm = APInt::getLowBitsSet(IdxTy.getSizeInBits(), Log2_32(NElts));
4736 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
4739 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
4740 .getReg(0);
4743 Register LegalizerHelper::getVectorElementPointer(Register VecPtr, LLT VecTy,
4744 Register Index) {
4745 LLT EltTy = VecTy.getElementType();
4747 // Calculate the element offset and add it to the pointer.
4748 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
4749 assert(EltSize * 8 == EltTy.getSizeInBits() &&
4750 "Converting bits to bytes lost precision");
4752 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
4754 // Convert index to the correct size for the address space.
4755 const DataLayout &DL = MIRBuilder.getDataLayout();
4756 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
4757 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
4758 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
4759 if (IdxTy != MRI.getType(Index))
4760 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
4762 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
4763 MIRBuilder.buildConstant(IdxTy, EltSize));
4765 LLT PtrTy = MRI.getType(VecPtr);
4766 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
4769 #ifndef NDEBUG
4770 /// Check that all vector operands have same number of elements. Other operands
4771 /// should be listed in NonVecOp.
4772 static bool hasSameNumEltsOnAllVectorOperands(
4773 GenericMachineInstr &MI, MachineRegisterInfo &MRI,
4774 std::initializer_list<unsigned> NonVecOpIndices) {
4775 if (MI.getNumMemOperands() != 0)
4776 return false;
4778 LLT VecTy = MRI.getType(MI.getReg(0));
4779 if (!VecTy.isVector())
4780 return false;
4781 unsigned NumElts = VecTy.getNumElements();
4783 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
4784 MachineOperand &Op = MI.getOperand(OpIdx);
4785 if (!Op.isReg()) {
4786 if (!is_contained(NonVecOpIndices, OpIdx))
4787 return false;
4788 continue;
4791 LLT Ty = MRI.getType(Op.getReg());
4792 if (!Ty.isVector()) {
4793 if (!is_contained(NonVecOpIndices, OpIdx))
4794 return false;
4795 continue;
4798 if (Ty.getNumElements() != NumElts)
4799 return false;
4802 return true;
4804 #endif
4806 /// Fill \p DstOps with DstOps that have same number of elements combined as
4807 /// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
4808 /// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
4809 /// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
4810 static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
4811 unsigned NumElts) {
4812 LLT LeftoverTy;
4813 assert(Ty.isVector() && "Expected vector type");
4814 LLT EltTy = Ty.getElementType();
4815 LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElts, EltTy);
4816 int NumParts, NumLeftover;
4817 std::tie(NumParts, NumLeftover) =
4818 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
4820 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
4821 for (int i = 0; i < NumParts; ++i) {
4822 DstOps.push_back(NarrowTy);
4825 if (LeftoverTy.isValid()) {
4826 assert(NumLeftover == 1 && "expected exactly one leftover");
4827 DstOps.push_back(LeftoverTy);
4831 /// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
4832 /// made from \p Op depending on operand type.
4833 static void broadcastSrcOp(SmallVectorImpl<SrcOp> &Ops, unsigned N,
4834 MachineOperand &Op) {
4835 for (unsigned i = 0; i < N; ++i) {
4836 if (Op.isReg())
4837 Ops.push_back(Op.getReg());
4838 else if (Op.isImm())
4839 Ops.push_back(Op.getImm());
4840 else if (Op.isPredicate())
4841 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
4842 else
4843 llvm_unreachable("Unsupported type");
4847 // Handle splitting vector operations which need to have the same number of
4848 // elements in each type index, but each type index may have a different element
4849 // type.
4851 // e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
4852 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4853 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4855 // Also handles some irregular breakdown cases, e.g.
4856 // e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
4857 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4858 // s64 = G_SHL s64, s32
4859 LegalizerHelper::LegalizeResult
4860 LegalizerHelper::fewerElementsVectorMultiEltType(
4861 GenericMachineInstr &MI, unsigned NumElts,
4862 std::initializer_list<unsigned> NonVecOpIndices) {
4863 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
4864 "Non-compatible opcode or not specified non-vector operands");
4865 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
4867 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
4868 unsigned NumDefs = MI.getNumDefs();
4870 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
4871 // Build instructions with DstOps to use instruction found by CSE directly.
4872 // CSE copies found instruction into given vreg when building with vreg dest.
4873 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
4874 // Output registers will be taken from created instructions.
4875 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
4876 for (unsigned i = 0; i < NumDefs; ++i) {
4877 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
4880 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
4881 // Operands listed in NonVecOpIndices will be used as is without splitting;
4882 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
4883 // scalar condition (op 1), immediate in sext_inreg (op 2).
4884 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
4885 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
4886 ++UseIdx, ++UseNo) {
4887 if (is_contained(NonVecOpIndices, UseIdx)) {
4888 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
4889 MI.getOperand(UseIdx));
4890 } else {
4891 SmallVector<Register, 8> SplitPieces;
4892 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
4893 MRI);
4894 for (auto Reg : SplitPieces)
4895 InputOpsPieces[UseNo].push_back(Reg);
4899 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
4901 // Take i-th piece of each input operand split and build sub-vector/scalar
4902 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
4903 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
4904 SmallVector<DstOp, 2> Defs;
4905 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
4906 Defs.push_back(OutputOpsPieces[DstNo][i]);
4908 SmallVector<SrcOp, 3> Uses;
4909 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
4910 Uses.push_back(InputOpsPieces[InputNo][i]);
4912 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
4913 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
4914 OutputRegs[DstNo].push_back(I.getReg(DstNo));
4917 // Merge small outputs into MI's output for each def operand.
4918 if (NumLeftovers) {
4919 for (unsigned i = 0; i < NumDefs; ++i)
4920 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
4921 } else {
4922 for (unsigned i = 0; i < NumDefs; ++i)
4923 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
4926 MI.eraseFromParent();
4927 return Legalized;
4930 LegalizerHelper::LegalizeResult
4931 LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr &MI,
4932 unsigned NumElts) {
4933 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
4935 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
4936 unsigned NumDefs = MI.getNumDefs();
4938 SmallVector<DstOp, 8> OutputOpsPieces;
4939 SmallVector<Register, 8> OutputRegs;
4940 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
4942 // Instructions that perform register split will be inserted in basic block
4943 // where register is defined (basic block is in the next operand).
4944 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
4945 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
4946 UseIdx += 2, ++UseNo) {
4947 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
4948 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
4949 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
4950 MIRBuilder, MRI);
4953 // Build PHIs with fewer elements.
4954 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
4955 MIRBuilder.setInsertPt(*MI.getParent(), MI);
4956 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
4957 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
4958 Phi.addDef(
4959 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
4960 OutputRegs.push_back(Phi.getReg(0));
4962 for (unsigned j = 0; j < NumInputs / 2; ++j) {
4963 Phi.addUse(InputOpsPieces[j][i]);
4964 Phi.add(MI.getOperand(1 + j * 2 + 1));
4968 // Set the insert point after the existing PHIs
4969 MachineBasicBlock &MBB = *MI.getParent();
4970 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
4972 // Merge small outputs into MI's def.
4973 if (NumLeftovers) {
4974 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
4975 } else {
4976 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
4979 MI.eraseFromParent();
4980 return Legalized;
4983 LegalizerHelper::LegalizeResult
4984 LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr &MI,
4985 unsigned TypeIdx,
4986 LLT NarrowTy) {
4987 const int NumDst = MI.getNumOperands() - 1;
4988 const Register SrcReg = MI.getOperand(NumDst).getReg();
4989 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
4990 LLT SrcTy = MRI.getType(SrcReg);
4992 if (TypeIdx != 1 || NarrowTy == DstTy)
4993 return UnableToLegalize;
4995 // Requires compatible types. Otherwise SrcReg should have been defined by
4996 // merge-like instruction that would get artifact combined. Most likely
4997 // instruction that defines SrcReg has to perform more/fewer elements
4998 // legalization compatible with NarrowTy.
4999 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5000 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5002 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5003 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5004 return UnableToLegalize;
5006 // This is most likely DstTy (smaller then register size) packed in SrcTy
5007 // (larger then register size) and since unmerge was not combined it will be
5008 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5009 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5011 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5013 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5014 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5015 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5016 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5017 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5018 const int PartsPerUnmerge = NumDst / NumUnmerge;
5020 for (int I = 0; I != NumUnmerge; ++I) {
5021 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5023 for (int J = 0; J != PartsPerUnmerge; ++J)
5024 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5025 MIB.addUse(Unmerge.getReg(I));
5028 MI.eraseFromParent();
5029 return Legalized;
5032 LegalizerHelper::LegalizeResult
5033 LegalizerHelper::fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx,
5034 LLT NarrowTy) {
5035 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5036 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5037 // that should have been artifact combined. Most likely instruction that uses
5038 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5039 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5040 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5041 if (NarrowTy == SrcTy)
5042 return UnableToLegalize;
5044 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5045 // is for old mir tests. Since the changes to more/fewer elements it should no
5046 // longer be possible to generate MIR like this when starting from llvm-ir
5047 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5048 if (TypeIdx == 1) {
5049 assert(SrcTy.isVector() && "Expected vector types");
5050 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5051 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5052 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5053 return UnableToLegalize;
5054 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5056 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5057 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5058 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5059 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5060 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5061 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5063 SmallVector<Register, 8> Elts;
5064 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5065 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5066 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5067 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5068 Elts.push_back(Unmerge.getReg(j));
5071 SmallVector<Register, 8> NarrowTyElts;
5072 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5073 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5074 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5075 ++i, Offset += NumNarrowTyElts) {
5076 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5077 NarrowTyElts.push_back(
5078 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5081 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5082 MI.eraseFromParent();
5083 return Legalized;
5086 assert(TypeIdx == 0 && "Bad type index");
5087 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5088 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5089 return UnableToLegalize;
5091 // This is most likely SrcTy (smaller then register size) packed in DstTy
5092 // (larger then register size) and since merge was not combined it will be
5093 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5094 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5096 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5098 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5099 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5100 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5101 SmallVector<Register, 8> NarrowTyElts;
5102 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5103 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5104 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5105 for (unsigned i = 0; i < NumParts; ++i) {
5106 SmallVector<Register, 8> Sources;
5107 for (unsigned j = 0; j < NumElts; ++j)
5108 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5109 NarrowTyElts.push_back(
5110 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5113 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5114 MI.eraseFromParent();
5115 return Legalized;
5118 LegalizerHelper::LegalizeResult
5119 LegalizerHelper::fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI,
5120 unsigned TypeIdx,
5121 LLT NarrowVecTy) {
5122 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5123 Register InsertVal;
5124 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5126 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5127 if (IsInsert)
5128 InsertVal = MI.getOperand(2).getReg();
5130 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5132 // TODO: Handle total scalarization case.
5133 if (!NarrowVecTy.isVector())
5134 return UnableToLegalize;
5136 LLT VecTy = MRI.getType(SrcVec);
5138 // If the index is a constant, we can really break this down as you would
5139 // expect, and index into the target size pieces.
5140 int64_t IdxVal;
5141 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5142 if (MaybeCst) {
5143 IdxVal = MaybeCst->Value.getSExtValue();
5144 // Avoid out of bounds indexing the pieces.
5145 if (IdxVal >= VecTy.getNumElements()) {
5146 MIRBuilder.buildUndef(DstReg);
5147 MI.eraseFromParent();
5148 return Legalized;
5151 SmallVector<Register, 8> VecParts;
5152 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5154 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5155 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5156 TargetOpcode::G_ANYEXT);
5158 unsigned NewNumElts = NarrowVecTy.getNumElements();
5160 LLT IdxTy = MRI.getType(Idx);
5161 int64_t PartIdx = IdxVal / NewNumElts;
5162 auto NewIdx =
5163 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5165 if (IsInsert) {
5166 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5168 // Use the adjusted index to insert into one of the subvectors.
5169 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5170 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5171 VecParts[PartIdx] = InsertPart.getReg(0);
5173 // Recombine the inserted subvector with the others to reform the result
5174 // vector.
5175 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5176 } else {
5177 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5180 MI.eraseFromParent();
5181 return Legalized;
5184 // With a variable index, we can't perform the operation in a smaller type, so
5185 // we're forced to expand this.
5187 // TODO: We could emit a chain of compare/select to figure out which piece to
5188 // index.
5189 return lowerExtractInsertVectorElt(MI);
5192 LegalizerHelper::LegalizeResult
5193 LegalizerHelper::reduceLoadStoreWidth(GLoadStore &LdStMI, unsigned TypeIdx,
5194 LLT NarrowTy) {
5195 // FIXME: Don't know how to handle secondary types yet.
5196 if (TypeIdx != 0)
5197 return UnableToLegalize;
5199 // This implementation doesn't work for atomics. Give up instead of doing
5200 // something invalid.
5201 if (LdStMI.isAtomic())
5202 return UnableToLegalize;
5204 bool IsLoad = isa<GLoad>(LdStMI);
5205 Register ValReg = LdStMI.getReg(0);
5206 Register AddrReg = LdStMI.getPointerReg();
5207 LLT ValTy = MRI.getType(ValReg);
5209 // FIXME: Do we need a distinct NarrowMemory legalize action?
5210 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5211 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5212 return UnableToLegalize;
5215 int NumParts = -1;
5216 int NumLeftover = -1;
5217 LLT LeftoverTy;
5218 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5219 if (IsLoad) {
5220 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5221 } else {
5222 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5223 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5224 NumParts = NarrowRegs.size();
5225 NumLeftover = NarrowLeftoverRegs.size();
5229 if (NumParts == -1)
5230 return UnableToLegalize;
5232 LLT PtrTy = MRI.getType(AddrReg);
5233 const LLT OffsetTy = LLT::scalar(PtrTy.getSizeInBits());
5235 unsigned TotalSize = ValTy.getSizeInBits();
5237 // Split the load/store into PartTy sized pieces starting at Offset. If this
5238 // is a load, return the new registers in ValRegs. For a store, each elements
5239 // of ValRegs should be PartTy. Returns the next offset that needs to be
5240 // handled.
5241 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5242 auto MMO = LdStMI.getMMO();
5243 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5244 unsigned NumParts, unsigned Offset) -> unsigned {
5245 MachineFunction &MF = MIRBuilder.getMF();
5246 unsigned PartSize = PartTy.getSizeInBits();
5247 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5248 ++Idx) {
5249 unsigned ByteOffset = Offset / 8;
5250 Register NewAddrReg;
5252 MIRBuilder.materializePtrAdd(NewAddrReg, AddrReg, OffsetTy, ByteOffset);
5254 MachineMemOperand *NewMMO =
5255 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5257 if (IsLoad) {
5258 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5259 ValRegs.push_back(Dst);
5260 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5261 } else {
5262 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5264 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5267 return Offset;
5270 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5271 unsigned HandledOffset =
5272 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5274 // Handle the rest of the register if this isn't an even type breakdown.
5275 if (LeftoverTy.isValid())
5276 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5278 if (IsLoad) {
5279 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5280 LeftoverTy, NarrowLeftoverRegs);
5283 LdStMI.eraseFromParent();
5284 return Legalized;
5287 LegalizerHelper::LegalizeResult
5288 LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
5289 LLT NarrowTy) {
5290 using namespace TargetOpcode;
5291 GenericMachineInstr &GMI = cast<GenericMachineInstr>(MI);
5292 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5294 switch (MI.getOpcode()) {
5295 case G_IMPLICIT_DEF:
5296 case G_TRUNC:
5297 case G_AND:
5298 case G_OR:
5299 case G_XOR:
5300 case G_ADD:
5301 case G_SUB:
5302 case G_MUL:
5303 case G_PTR_ADD:
5304 case G_SMULH:
5305 case G_UMULH:
5306 case G_FADD:
5307 case G_FMUL:
5308 case G_FSUB:
5309 case G_FNEG:
5310 case G_FABS:
5311 case G_FCANONICALIZE:
5312 case G_FDIV:
5313 case G_FREM:
5314 case G_FMA:
5315 case G_FMAD:
5316 case G_FPOW:
5317 case G_FEXP:
5318 case G_FEXP2:
5319 case G_FEXP10:
5320 case G_FLOG:
5321 case G_FLOG2:
5322 case G_FLOG10:
5323 case G_FLDEXP:
5324 case G_FNEARBYINT:
5325 case G_FCEIL:
5326 case G_FFLOOR:
5327 case G_FRINT:
5328 case G_INTRINSIC_LRINT:
5329 case G_INTRINSIC_LLRINT:
5330 case G_INTRINSIC_ROUND:
5331 case G_INTRINSIC_ROUNDEVEN:
5332 case G_LROUND:
5333 case G_LLROUND:
5334 case G_INTRINSIC_TRUNC:
5335 case G_FCOS:
5336 case G_FSIN:
5337 case G_FTAN:
5338 case G_FACOS:
5339 case G_FASIN:
5340 case G_FATAN:
5341 case G_FATAN2:
5342 case G_FCOSH:
5343 case G_FSINH:
5344 case G_FTANH:
5345 case G_FSQRT:
5346 case G_BSWAP:
5347 case G_BITREVERSE:
5348 case G_SDIV:
5349 case G_UDIV:
5350 case G_SREM:
5351 case G_UREM:
5352 case G_SDIVREM:
5353 case G_UDIVREM:
5354 case G_SMIN:
5355 case G_SMAX:
5356 case G_UMIN:
5357 case G_UMAX:
5358 case G_ABS:
5359 case G_FMINNUM:
5360 case G_FMAXNUM:
5361 case G_FMINNUM_IEEE:
5362 case G_FMAXNUM_IEEE:
5363 case G_FMINIMUM:
5364 case G_FMAXIMUM:
5365 case G_FSHL:
5366 case G_FSHR:
5367 case G_ROTL:
5368 case G_ROTR:
5369 case G_FREEZE:
5370 case G_SADDSAT:
5371 case G_SSUBSAT:
5372 case G_UADDSAT:
5373 case G_USUBSAT:
5374 case G_UMULO:
5375 case G_SMULO:
5376 case G_SHL:
5377 case G_LSHR:
5378 case G_ASHR:
5379 case G_SSHLSAT:
5380 case G_USHLSAT:
5381 case G_CTLZ:
5382 case G_CTLZ_ZERO_UNDEF:
5383 case G_CTTZ:
5384 case G_CTTZ_ZERO_UNDEF:
5385 case G_CTPOP:
5386 case G_FCOPYSIGN:
5387 case G_ZEXT:
5388 case G_SEXT:
5389 case G_ANYEXT:
5390 case G_FPEXT:
5391 case G_FPTRUNC:
5392 case G_SITOFP:
5393 case G_UITOFP:
5394 case G_FPTOSI:
5395 case G_FPTOUI:
5396 case G_FPTOSI_SAT:
5397 case G_FPTOUI_SAT:
5398 case G_INTTOPTR:
5399 case G_PTRTOINT:
5400 case G_ADDRSPACE_CAST:
5401 case G_UADDO:
5402 case G_USUBO:
5403 case G_UADDE:
5404 case G_USUBE:
5405 case G_SADDO:
5406 case G_SSUBO:
5407 case G_SADDE:
5408 case G_SSUBE:
5409 case G_STRICT_FADD:
5410 case G_STRICT_FSUB:
5411 case G_STRICT_FMUL:
5412 case G_STRICT_FMA:
5413 case G_STRICT_FLDEXP:
5414 case G_FFREXP:
5415 return fewerElementsVectorMultiEltType(GMI, NumElts);
5416 case G_ICMP:
5417 case G_FCMP:
5418 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5419 case G_IS_FPCLASS:
5420 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5421 case G_SELECT:
5422 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5423 return fewerElementsVectorMultiEltType(GMI, NumElts);
5424 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5425 case G_PHI:
5426 return fewerElementsVectorPhi(GMI, NumElts);
5427 case G_UNMERGE_VALUES:
5428 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5429 case G_BUILD_VECTOR:
5430 assert(TypeIdx == 0 && "not a vector type index");
5431 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5432 case G_CONCAT_VECTORS:
5433 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5434 return UnableToLegalize;
5435 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5436 case G_EXTRACT_VECTOR_ELT:
5437 case G_INSERT_VECTOR_ELT:
5438 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5439 case G_LOAD:
5440 case G_STORE:
5441 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5442 case G_SEXT_INREG:
5443 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5444 GISEL_VECREDUCE_CASES_NONSEQ
5445 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5446 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5447 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5448 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5449 case G_SHUFFLE_VECTOR:
5450 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5451 case G_FPOWI:
5452 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5453 case G_BITCAST:
5454 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5455 case G_INTRINSIC_FPTRUNC_ROUND:
5456 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5457 default:
5458 return UnableToLegalize;
5462 LegalizerHelper::LegalizeResult
5463 LegalizerHelper::fewerElementsBitcast(MachineInstr &MI, unsigned int TypeIdx,
5464 LLT NarrowTy) {
5465 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5466 "Not a bitcast operation");
5468 if (TypeIdx != 0)
5469 return UnableToLegalize;
5471 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5473 unsigned NewElemCount =
5474 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5475 LLT SrcNarrowTy = LLT::fixed_vector(NewElemCount, SrcTy.getElementType());
5477 // Split the Src and Dst Reg into smaller registers
5478 SmallVector<Register> SrcVRegs, BitcastVRegs;
5479 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5480 return UnableToLegalize;
5482 // Build new smaller bitcast instructions
5483 // Not supporting Leftover types for now but will have to
5484 for (unsigned i = 0; i < SrcVRegs.size(); i++)
5485 BitcastVRegs.push_back(
5486 MIRBuilder.buildBitcast(NarrowTy, SrcVRegs[i]).getReg(0));
5488 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5489 MI.eraseFromParent();
5490 return Legalized;
5493 LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorShuffle(
5494 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5495 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5496 if (TypeIdx != 0)
5497 return UnableToLegalize;
5499 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
5500 MI.getFirst3RegLLTs();
5501 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5502 // The shuffle should be canonicalized by now.
5503 if (DstTy != Src1Ty)
5504 return UnableToLegalize;
5505 if (DstTy != Src2Ty)
5506 return UnableToLegalize;
5508 if (!isPowerOf2_32(DstTy.getNumElements()))
5509 return UnableToLegalize;
5511 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
5512 // Further legalization attempts will be needed to do split further.
5513 NarrowTy =
5514 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
5515 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5517 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
5518 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
5519 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
5520 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
5521 SplitSrc2Regs[1]};
5523 Register Hi, Lo;
5525 // If Lo or Hi uses elements from at most two of the four input vectors, then
5526 // express it as a vector shuffle of those two inputs. Otherwise extract the
5527 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
5528 SmallVector<int, 16> Ops;
5529 for (unsigned High = 0; High < 2; ++High) {
5530 Register &Output = High ? Hi : Lo;
5532 // Build a shuffle mask for the output, discovering on the fly which
5533 // input vectors to use as shuffle operands (recorded in InputUsed).
5534 // If building a suitable shuffle vector proves too hard, then bail
5535 // out with useBuildVector set.
5536 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
5537 unsigned FirstMaskIdx = High * NewElts;
5538 bool UseBuildVector = false;
5539 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5540 // The mask element. This indexes into the input.
5541 int Idx = Mask[FirstMaskIdx + MaskOffset];
5543 // The input vector this mask element indexes into.
5544 unsigned Input = (unsigned)Idx / NewElts;
5546 if (Input >= std::size(Inputs)) {
5547 // The mask element does not index into any input vector.
5548 Ops.push_back(-1);
5549 continue;
5552 // Turn the index into an offset from the start of the input vector.
5553 Idx -= Input * NewElts;
5555 // Find or create a shuffle vector operand to hold this input.
5556 unsigned OpNo;
5557 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
5558 if (InputUsed[OpNo] == Input) {
5559 // This input vector is already an operand.
5560 break;
5561 } else if (InputUsed[OpNo] == -1U) {
5562 // Create a new operand for this input vector.
5563 InputUsed[OpNo] = Input;
5564 break;
5568 if (OpNo >= std::size(InputUsed)) {
5569 // More than two input vectors used! Give up on trying to create a
5570 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
5571 UseBuildVector = true;
5572 break;
5575 // Add the mask index for the new shuffle vector.
5576 Ops.push_back(Idx + OpNo * NewElts);
5579 if (UseBuildVector) {
5580 LLT EltTy = NarrowTy.getElementType();
5581 SmallVector<Register, 16> SVOps;
5583 // Extract the input elements by hand.
5584 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5585 // The mask element. This indexes into the input.
5586 int Idx = Mask[FirstMaskIdx + MaskOffset];
5588 // The input vector this mask element indexes into.
5589 unsigned Input = (unsigned)Idx / NewElts;
5591 if (Input >= std::size(Inputs)) {
5592 // The mask element is "undef" or indexes off the end of the input.
5593 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
5594 continue;
5597 // Turn the index into an offset from the start of the input vector.
5598 Idx -= Input * NewElts;
5600 // Extract the vector element by hand.
5601 SVOps.push_back(MIRBuilder
5602 .buildExtractVectorElement(
5603 EltTy, Inputs[Input],
5604 MIRBuilder.buildConstant(LLT::scalar(32), Idx))
5605 .getReg(0));
5608 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
5609 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
5610 } else if (InputUsed[0] == -1U) {
5611 // No input vectors were used! The result is undefined.
5612 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
5613 } else {
5614 Register Op0 = Inputs[InputUsed[0]];
5615 // If only one input was used, use an undefined vector for the other.
5616 Register Op1 = InputUsed[1] == -1U
5617 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
5618 : Inputs[InputUsed[1]];
5619 // At least one input vector was used. Create a new shuffle vector.
5620 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
5623 Ops.clear();
5626 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
5627 MI.eraseFromParent();
5628 return Legalized;
5631 LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorReductions(
5632 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5633 auto &RdxMI = cast<GVecReduce>(MI);
5635 if (TypeIdx != 1)
5636 return UnableToLegalize;
5638 // The semantics of the normal non-sequential reductions allow us to freely
5639 // re-associate the operation.
5640 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
5642 if (NarrowTy.isVector() &&
5643 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
5644 return UnableToLegalize;
5646 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
5647 SmallVector<Register> SplitSrcs;
5648 // If NarrowTy is a scalar then we're being asked to scalarize.
5649 const unsigned NumParts =
5650 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
5651 : SrcTy.getNumElements();
5653 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
5654 if (NarrowTy.isScalar()) {
5655 if (DstTy != NarrowTy)
5656 return UnableToLegalize; // FIXME: handle implicit extensions.
5658 if (isPowerOf2_32(NumParts)) {
5659 // Generate a tree of scalar operations to reduce the critical path.
5660 SmallVector<Register> PartialResults;
5661 unsigned NumPartsLeft = NumParts;
5662 while (NumPartsLeft > 1) {
5663 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
5664 PartialResults.emplace_back(
5665 MIRBuilder
5666 .buildInstr(ScalarOpc, {NarrowTy},
5667 {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
5668 .getReg(0));
5670 SplitSrcs = PartialResults;
5671 PartialResults.clear();
5672 NumPartsLeft = SplitSrcs.size();
5674 assert(SplitSrcs.size() == 1);
5675 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
5676 MI.eraseFromParent();
5677 return Legalized;
5679 // If we can't generate a tree, then just do sequential operations.
5680 Register Acc = SplitSrcs[0];
5681 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
5682 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
5683 .getReg(0);
5684 MIRBuilder.buildCopy(DstReg, Acc);
5685 MI.eraseFromParent();
5686 return Legalized;
5688 SmallVector<Register> PartialReductions;
5689 for (unsigned Part = 0; Part < NumParts; ++Part) {
5690 PartialReductions.push_back(
5691 MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
5692 .getReg(0));
5695 // If the types involved are powers of 2, we can generate intermediate vector
5696 // ops, before generating a final reduction operation.
5697 if (isPowerOf2_32(SrcTy.getNumElements()) &&
5698 isPowerOf2_32(NarrowTy.getNumElements())) {
5699 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
5702 Register Acc = PartialReductions[0];
5703 for (unsigned Part = 1; Part < NumParts; ++Part) {
5704 if (Part == NumParts - 1) {
5705 MIRBuilder.buildInstr(ScalarOpc, {DstReg},
5706 {Acc, PartialReductions[Part]});
5707 } else {
5708 Acc = MIRBuilder
5709 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
5710 .getReg(0);
5713 MI.eraseFromParent();
5714 return Legalized;
5717 LegalizerHelper::LegalizeResult
5718 LegalizerHelper::fewerElementsVectorSeqReductions(MachineInstr &MI,
5719 unsigned int TypeIdx,
5720 LLT NarrowTy) {
5721 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
5722 MI.getFirst3RegLLTs();
5723 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
5724 DstTy != NarrowTy)
5725 return UnableToLegalize;
5727 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
5728 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
5729 "Unexpected vecreduce opcode");
5730 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
5731 ? TargetOpcode::G_FADD
5732 : TargetOpcode::G_FMUL;
5734 SmallVector<Register> SplitSrcs;
5735 unsigned NumParts = SrcTy.getNumElements();
5736 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
5737 Register Acc = ScalarReg;
5738 for (unsigned i = 0; i < NumParts; i++)
5739 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
5740 .getReg(0);
5742 MIRBuilder.buildCopy(DstReg, Acc);
5743 MI.eraseFromParent();
5744 return Legalized;
5747 LegalizerHelper::LegalizeResult
5748 LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
5749 LLT SrcTy, LLT NarrowTy,
5750 unsigned ScalarOpc) {
5751 SmallVector<Register> SplitSrcs;
5752 // Split the sources into NarrowTy size pieces.
5753 extractParts(SrcReg, NarrowTy,
5754 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
5755 MIRBuilder, MRI);
5756 // We're going to do a tree reduction using vector operations until we have
5757 // one NarrowTy size value left.
5758 while (SplitSrcs.size() > 1) {
5759 SmallVector<Register> PartialRdxs;
5760 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
5761 Register LHS = SplitSrcs[Idx];
5762 Register RHS = SplitSrcs[Idx + 1];
5763 // Create the intermediate vector op.
5764 Register Res =
5765 MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
5766 PartialRdxs.push_back(Res);
5768 SplitSrcs = std::move(PartialRdxs);
5770 // Finally generate the requested NarrowTy based reduction.
5771 Observer.changingInstr(MI);
5772 MI.getOperand(1).setReg(SplitSrcs[0]);
5773 Observer.changedInstr(MI);
5774 return Legalized;
5777 LegalizerHelper::LegalizeResult
5778 LegalizerHelper::narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt,
5779 const LLT HalfTy, const LLT AmtTy) {
5781 Register InL = MRI.createGenericVirtualRegister(HalfTy);
5782 Register InH = MRI.createGenericVirtualRegister(HalfTy);
5783 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
5785 if (Amt.isZero()) {
5786 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
5787 MI.eraseFromParent();
5788 return Legalized;
5791 LLT NVT = HalfTy;
5792 unsigned NVTBits = HalfTy.getSizeInBits();
5793 unsigned VTBits = 2 * NVTBits;
5795 SrcOp Lo(Register(0)), Hi(Register(0));
5796 if (MI.getOpcode() == TargetOpcode::G_SHL) {
5797 if (Amt.ugt(VTBits)) {
5798 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
5799 } else if (Amt.ugt(NVTBits)) {
5800 Lo = MIRBuilder.buildConstant(NVT, 0);
5801 Hi = MIRBuilder.buildShl(NVT, InL,
5802 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
5803 } else if (Amt == NVTBits) {
5804 Lo = MIRBuilder.buildConstant(NVT, 0);
5805 Hi = InL;
5806 } else {
5807 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
5808 auto OrLHS =
5809 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
5810 auto OrRHS = MIRBuilder.buildLShr(
5811 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
5812 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
5814 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
5815 if (Amt.ugt(VTBits)) {
5816 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
5817 } else if (Amt.ugt(NVTBits)) {
5818 Lo = MIRBuilder.buildLShr(NVT, InH,
5819 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
5820 Hi = MIRBuilder.buildConstant(NVT, 0);
5821 } else if (Amt == NVTBits) {
5822 Lo = InH;
5823 Hi = MIRBuilder.buildConstant(NVT, 0);
5824 } else {
5825 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
5827 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
5828 auto OrRHS = MIRBuilder.buildShl(
5829 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
5831 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
5832 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
5834 } else {
5835 if (Amt.ugt(VTBits)) {
5836 Hi = Lo = MIRBuilder.buildAShr(
5837 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
5838 } else if (Amt.ugt(NVTBits)) {
5839 Lo = MIRBuilder.buildAShr(NVT, InH,
5840 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
5841 Hi = MIRBuilder.buildAShr(NVT, InH,
5842 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
5843 } else if (Amt == NVTBits) {
5844 Lo = InH;
5845 Hi = MIRBuilder.buildAShr(NVT, InH,
5846 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
5847 } else {
5848 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
5850 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
5851 auto OrRHS = MIRBuilder.buildShl(
5852 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
5854 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
5855 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
5859 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
5860 MI.eraseFromParent();
5862 return Legalized;
5865 // TODO: Optimize if constant shift amount.
5866 LegalizerHelper::LegalizeResult
5867 LegalizerHelper::narrowScalarShift(MachineInstr &MI, unsigned TypeIdx,
5868 LLT RequestedTy) {
5869 if (TypeIdx == 1) {
5870 Observer.changingInstr(MI);
5871 narrowScalarSrc(MI, RequestedTy, 2);
5872 Observer.changedInstr(MI);
5873 return Legalized;
5876 Register DstReg = MI.getOperand(0).getReg();
5877 LLT DstTy = MRI.getType(DstReg);
5878 if (DstTy.isVector())
5879 return UnableToLegalize;
5881 Register Amt = MI.getOperand(2).getReg();
5882 LLT ShiftAmtTy = MRI.getType(Amt);
5883 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
5884 if (DstEltSize % 2 != 0)
5885 return UnableToLegalize;
5887 // Ignore the input type. We can only go to exactly half the size of the
5888 // input. If that isn't small enough, the resulting pieces will be further
5889 // legalized.
5890 const unsigned NewBitSize = DstEltSize / 2;
5891 const LLT HalfTy = LLT::scalar(NewBitSize);
5892 const LLT CondTy = LLT::scalar(1);
5894 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
5895 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
5896 ShiftAmtTy);
5899 // TODO: Expand with known bits.
5901 // Handle the fully general expansion by an unknown amount.
5902 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
5904 Register InL = MRI.createGenericVirtualRegister(HalfTy);
5905 Register InH = MRI.createGenericVirtualRegister(HalfTy);
5906 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
5908 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
5909 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
5911 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
5912 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
5913 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
5915 Register ResultRegs[2];
5916 switch (MI.getOpcode()) {
5917 case TargetOpcode::G_SHL: {
5918 // Short: ShAmt < NewBitSize
5919 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
5921 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
5922 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
5923 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
5925 // Long: ShAmt >= NewBitSize
5926 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
5927 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
5929 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
5930 auto Hi = MIRBuilder.buildSelect(
5931 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
5933 ResultRegs[0] = Lo.getReg(0);
5934 ResultRegs[1] = Hi.getReg(0);
5935 break;
5937 case TargetOpcode::G_LSHR:
5938 case TargetOpcode::G_ASHR: {
5939 // Short: ShAmt < NewBitSize
5940 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
5942 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
5943 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
5944 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
5946 // Long: ShAmt >= NewBitSize
5947 MachineInstrBuilder HiL;
5948 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
5949 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
5950 } else {
5951 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
5952 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
5954 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
5955 {InH, AmtExcess}); // Lo from Hi part.
5957 auto Lo = MIRBuilder.buildSelect(
5958 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
5960 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
5962 ResultRegs[0] = Lo.getReg(0);
5963 ResultRegs[1] = Hi.getReg(0);
5964 break;
5966 default:
5967 llvm_unreachable("not a shift");
5970 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
5971 MI.eraseFromParent();
5972 return Legalized;
5975 LegalizerHelper::LegalizeResult
5976 LegalizerHelper::moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx,
5977 LLT MoreTy) {
5978 assert(TypeIdx == 0 && "Expecting only Idx 0");
5980 Observer.changingInstr(MI);
5981 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
5982 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
5983 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
5984 moreElementsVectorSrc(MI, MoreTy, I);
5987 MachineBasicBlock &MBB = *MI.getParent();
5988 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
5989 moreElementsVectorDst(MI, MoreTy, 0);
5990 Observer.changedInstr(MI);
5991 return Legalized;
5994 MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
5995 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
5996 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
5998 switch (Opcode) {
5999 default:
6000 llvm_unreachable(
6001 "getNeutralElementForVecReduce called with invalid opcode!");
6002 case TargetOpcode::G_VECREDUCE_ADD:
6003 case TargetOpcode::G_VECREDUCE_OR:
6004 case TargetOpcode::G_VECREDUCE_XOR:
6005 case TargetOpcode::G_VECREDUCE_UMAX:
6006 return MIRBuilder.buildConstant(Ty, 0);
6007 case TargetOpcode::G_VECREDUCE_MUL:
6008 return MIRBuilder.buildConstant(Ty, 1);
6009 case TargetOpcode::G_VECREDUCE_AND:
6010 case TargetOpcode::G_VECREDUCE_UMIN:
6011 return MIRBuilder.buildConstant(
6012 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6013 case TargetOpcode::G_VECREDUCE_SMAX:
6014 return MIRBuilder.buildConstant(
6015 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6016 case TargetOpcode::G_VECREDUCE_SMIN:
6017 return MIRBuilder.buildConstant(
6018 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6019 case TargetOpcode::G_VECREDUCE_FADD:
6020 return MIRBuilder.buildFConstant(Ty, -0.0);
6021 case TargetOpcode::G_VECREDUCE_FMUL:
6022 return MIRBuilder.buildFConstant(Ty, 1.0);
6023 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6024 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6025 assert(false && "getNeutralElementForVecReduce unimplemented for "
6026 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6028 llvm_unreachable("switch expected to return!");
6031 LegalizerHelper::LegalizeResult
6032 LegalizerHelper::moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
6033 LLT MoreTy) {
6034 unsigned Opc = MI.getOpcode();
6035 switch (Opc) {
6036 case TargetOpcode::G_IMPLICIT_DEF:
6037 case TargetOpcode::G_LOAD: {
6038 if (TypeIdx != 0)
6039 return UnableToLegalize;
6040 Observer.changingInstr(MI);
6041 moreElementsVectorDst(MI, MoreTy, 0);
6042 Observer.changedInstr(MI);
6043 return Legalized;
6045 case TargetOpcode::G_STORE:
6046 if (TypeIdx != 0)
6047 return UnableToLegalize;
6048 Observer.changingInstr(MI);
6049 moreElementsVectorSrc(MI, MoreTy, 0);
6050 Observer.changedInstr(MI);
6051 return Legalized;
6052 case TargetOpcode::G_AND:
6053 case TargetOpcode::G_OR:
6054 case TargetOpcode::G_XOR:
6055 case TargetOpcode::G_ADD:
6056 case TargetOpcode::G_SUB:
6057 case TargetOpcode::G_MUL:
6058 case TargetOpcode::G_FADD:
6059 case TargetOpcode::G_FSUB:
6060 case TargetOpcode::G_FMUL:
6061 case TargetOpcode::G_FDIV:
6062 case TargetOpcode::G_FCOPYSIGN:
6063 case TargetOpcode::G_UADDSAT:
6064 case TargetOpcode::G_USUBSAT:
6065 case TargetOpcode::G_SADDSAT:
6066 case TargetOpcode::G_SSUBSAT:
6067 case TargetOpcode::G_SMIN:
6068 case TargetOpcode::G_SMAX:
6069 case TargetOpcode::G_UMIN:
6070 case TargetOpcode::G_UMAX:
6071 case TargetOpcode::G_FMINNUM:
6072 case TargetOpcode::G_FMAXNUM:
6073 case TargetOpcode::G_FMINNUM_IEEE:
6074 case TargetOpcode::G_FMAXNUM_IEEE:
6075 case TargetOpcode::G_FMINIMUM:
6076 case TargetOpcode::G_FMAXIMUM:
6077 case TargetOpcode::G_STRICT_FADD:
6078 case TargetOpcode::G_STRICT_FSUB:
6079 case TargetOpcode::G_STRICT_FMUL:
6080 case TargetOpcode::G_SHL:
6081 case TargetOpcode::G_ASHR:
6082 case TargetOpcode::G_LSHR: {
6083 Observer.changingInstr(MI);
6084 moreElementsVectorSrc(MI, MoreTy, 1);
6085 moreElementsVectorSrc(MI, MoreTy, 2);
6086 moreElementsVectorDst(MI, MoreTy, 0);
6087 Observer.changedInstr(MI);
6088 return Legalized;
6090 case TargetOpcode::G_FMA:
6091 case TargetOpcode::G_STRICT_FMA:
6092 case TargetOpcode::G_FSHR:
6093 case TargetOpcode::G_FSHL: {
6094 Observer.changingInstr(MI);
6095 moreElementsVectorSrc(MI, MoreTy, 1);
6096 moreElementsVectorSrc(MI, MoreTy, 2);
6097 moreElementsVectorSrc(MI, MoreTy, 3);
6098 moreElementsVectorDst(MI, MoreTy, 0);
6099 Observer.changedInstr(MI);
6100 return Legalized;
6102 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
6103 case TargetOpcode::G_EXTRACT:
6104 if (TypeIdx != 1)
6105 return UnableToLegalize;
6106 Observer.changingInstr(MI);
6107 moreElementsVectorSrc(MI, MoreTy, 1);
6108 Observer.changedInstr(MI);
6109 return Legalized;
6110 case TargetOpcode::G_INSERT:
6111 case TargetOpcode::G_INSERT_VECTOR_ELT:
6112 case TargetOpcode::G_FREEZE:
6113 case TargetOpcode::G_FNEG:
6114 case TargetOpcode::G_FABS:
6115 case TargetOpcode::G_FSQRT:
6116 case TargetOpcode::G_FCEIL:
6117 case TargetOpcode::G_FFLOOR:
6118 case TargetOpcode::G_FNEARBYINT:
6119 case TargetOpcode::G_FRINT:
6120 case TargetOpcode::G_INTRINSIC_ROUND:
6121 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
6122 case TargetOpcode::G_INTRINSIC_TRUNC:
6123 case TargetOpcode::G_BSWAP:
6124 case TargetOpcode::G_FCANONICALIZE:
6125 case TargetOpcode::G_SEXT_INREG:
6126 case TargetOpcode::G_ABS:
6127 if (TypeIdx != 0)
6128 return UnableToLegalize;
6129 Observer.changingInstr(MI);
6130 moreElementsVectorSrc(MI, MoreTy, 1);
6131 moreElementsVectorDst(MI, MoreTy, 0);
6132 Observer.changedInstr(MI);
6133 return Legalized;
6134 case TargetOpcode::G_SELECT: {
6135 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
6136 if (TypeIdx == 1) {
6137 if (!CondTy.isScalar() ||
6138 DstTy.getElementCount() != MoreTy.getElementCount())
6139 return UnableToLegalize;
6141 // This is turning a scalar select of vectors into a vector
6142 // select. Broadcast the select condition.
6143 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
6144 Observer.changingInstr(MI);
6145 MI.getOperand(1).setReg(ShufSplat.getReg(0));
6146 Observer.changedInstr(MI);
6147 return Legalized;
6150 if (CondTy.isVector())
6151 return UnableToLegalize;
6153 Observer.changingInstr(MI);
6154 moreElementsVectorSrc(MI, MoreTy, 2);
6155 moreElementsVectorSrc(MI, MoreTy, 3);
6156 moreElementsVectorDst(MI, MoreTy, 0);
6157 Observer.changedInstr(MI);
6158 return Legalized;
6160 case TargetOpcode::G_UNMERGE_VALUES:
6161 return UnableToLegalize;
6162 case TargetOpcode::G_PHI:
6163 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
6164 case TargetOpcode::G_SHUFFLE_VECTOR:
6165 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
6166 case TargetOpcode::G_BUILD_VECTOR: {
6167 SmallVector<SrcOp, 8> Elts;
6168 for (auto Op : MI.uses()) {
6169 Elts.push_back(Op.getReg());
6172 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
6173 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
6176 MIRBuilder.buildDeleteTrailingVectorElements(
6177 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
6178 MI.eraseFromParent();
6179 return Legalized;
6181 case TargetOpcode::G_SEXT:
6182 case TargetOpcode::G_ZEXT:
6183 case TargetOpcode::G_ANYEXT:
6184 case TargetOpcode::G_TRUNC:
6185 case TargetOpcode::G_FPTRUNC:
6186 case TargetOpcode::G_FPEXT:
6187 case TargetOpcode::G_FPTOSI:
6188 case TargetOpcode::G_FPTOUI:
6189 case TargetOpcode::G_FPTOSI_SAT:
6190 case TargetOpcode::G_FPTOUI_SAT:
6191 case TargetOpcode::G_SITOFP:
6192 case TargetOpcode::G_UITOFP: {
6193 Observer.changingInstr(MI);
6194 LLT SrcExtTy;
6195 LLT DstExtTy;
6196 if (TypeIdx == 0) {
6197 DstExtTy = MoreTy;
6198 SrcExtTy = LLT::fixed_vector(
6199 MoreTy.getNumElements(),
6200 MRI.getType(MI.getOperand(1).getReg()).getElementType());
6201 } else {
6202 DstExtTy = LLT::fixed_vector(
6203 MoreTy.getNumElements(),
6204 MRI.getType(MI.getOperand(0).getReg()).getElementType());
6205 SrcExtTy = MoreTy;
6207 moreElementsVectorSrc(MI, SrcExtTy, 1);
6208 moreElementsVectorDst(MI, DstExtTy, 0);
6209 Observer.changedInstr(MI);
6210 return Legalized;
6212 case TargetOpcode::G_ICMP:
6213 case TargetOpcode::G_FCMP: {
6214 if (TypeIdx != 1)
6215 return UnableToLegalize;
6217 Observer.changingInstr(MI);
6218 moreElementsVectorSrc(MI, MoreTy, 2);
6219 moreElementsVectorSrc(MI, MoreTy, 3);
6220 LLT CondTy = LLT::fixed_vector(
6221 MoreTy.getNumElements(),
6222 MRI.getType(MI.getOperand(0).getReg()).getElementType());
6223 moreElementsVectorDst(MI, CondTy, 0);
6224 Observer.changedInstr(MI);
6225 return Legalized;
6227 case TargetOpcode::G_BITCAST: {
6228 if (TypeIdx != 0)
6229 return UnableToLegalize;
6231 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
6232 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
6234 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
6235 if (coefficient % DstTy.getNumElements() != 0)
6236 return UnableToLegalize;
6238 coefficient = coefficient / DstTy.getNumElements();
6240 LLT NewTy = SrcTy.changeElementCount(
6241 ElementCount::get(coefficient, MoreTy.isScalable()));
6242 Observer.changingInstr(MI);
6243 moreElementsVectorSrc(MI, NewTy, 1);
6244 moreElementsVectorDst(MI, MoreTy, 0);
6245 Observer.changedInstr(MI);
6246 return Legalized;
6248 case TargetOpcode::G_VECREDUCE_FADD:
6249 case TargetOpcode::G_VECREDUCE_FMUL:
6250 case TargetOpcode::G_VECREDUCE_ADD:
6251 case TargetOpcode::G_VECREDUCE_MUL:
6252 case TargetOpcode::G_VECREDUCE_AND:
6253 case TargetOpcode::G_VECREDUCE_OR:
6254 case TargetOpcode::G_VECREDUCE_XOR:
6255 case TargetOpcode::G_VECREDUCE_SMAX:
6256 case TargetOpcode::G_VECREDUCE_SMIN:
6257 case TargetOpcode::G_VECREDUCE_UMAX:
6258 case TargetOpcode::G_VECREDUCE_UMIN: {
6259 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
6260 MachineOperand &MO = MI.getOperand(1);
6261 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
6262 auto NeutralElement = getNeutralElementForVecReduce(
6263 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
6265 LLT IdxTy(TLI.getVectorIdxTy(MIRBuilder.getDataLayout()));
6266 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
6267 i != e; i++) {
6268 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
6269 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
6270 NeutralElement, Idx);
6273 Observer.changingInstr(MI);
6274 MO.setReg(NewVec.getReg(0));
6275 Observer.changedInstr(MI);
6276 return Legalized;
6279 default:
6280 return UnableToLegalize;
6284 LegalizerHelper::LegalizeResult
6285 LegalizerHelper::equalizeVectorShuffleLengths(MachineInstr &MI) {
6286 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6287 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6288 unsigned MaskNumElts = Mask.size();
6289 unsigned SrcNumElts = SrcTy.getNumElements();
6290 LLT DestEltTy = DstTy.getElementType();
6292 if (MaskNumElts == SrcNumElts)
6293 return Legalized;
6295 if (MaskNumElts < SrcNumElts) {
6296 // Extend mask to match new destination vector size with
6297 // undef values.
6298 SmallVector<int, 16> NewMask(SrcNumElts, -1);
6299 llvm::copy(Mask, NewMask.begin());
6301 moreElementsVectorDst(MI, SrcTy, 0);
6302 MIRBuilder.setInstrAndDebugLoc(MI);
6303 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
6304 MI.getOperand(1).getReg(),
6305 MI.getOperand(2).getReg(), NewMask);
6306 MI.eraseFromParent();
6308 return Legalized;
6311 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
6312 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
6313 LLT PaddedTy = LLT::fixed_vector(PaddedMaskNumElts, DestEltTy);
6315 // Create new source vectors by concatenating the initial
6316 // source vectors with undefined vectors of the same size.
6317 auto Undef = MIRBuilder.buildUndef(SrcTy);
6318 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
6319 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
6320 MOps1[0] = MI.getOperand(1).getReg();
6321 MOps2[0] = MI.getOperand(2).getReg();
6323 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
6324 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
6326 // Readjust mask for new input vector length.
6327 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
6328 for (unsigned I = 0; I != MaskNumElts; ++I) {
6329 int Idx = Mask[I];
6330 if (Idx >= static_cast<int>(SrcNumElts))
6331 Idx += PaddedMaskNumElts - SrcNumElts;
6332 MappedOps[I] = Idx;
6335 // If we got more elements than required, extract subvector.
6336 if (MaskNumElts != PaddedMaskNumElts) {
6337 auto Shuffle =
6338 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
6340 SmallVector<Register, 16> Elts(MaskNumElts);
6341 for (unsigned I = 0; I < MaskNumElts; ++I) {
6342 Elts[I] =
6343 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
6344 .getReg(0);
6346 MIRBuilder.buildBuildVector(DstReg, Elts);
6347 } else {
6348 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
6351 MI.eraseFromParent();
6352 return LegalizerHelper::LegalizeResult::Legalized;
6355 LegalizerHelper::LegalizeResult
6356 LegalizerHelper::moreElementsVectorShuffle(MachineInstr &MI,
6357 unsigned int TypeIdx, LLT MoreTy) {
6358 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
6359 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6360 unsigned NumElts = DstTy.getNumElements();
6361 unsigned WidenNumElts = MoreTy.getNumElements();
6363 if (DstTy.isVector() && Src1Ty.isVector() &&
6364 DstTy.getNumElements() != Src1Ty.getNumElements()) {
6365 return equalizeVectorShuffleLengths(MI);
6368 if (TypeIdx != 0)
6369 return UnableToLegalize;
6371 // Expect a canonicalized shuffle.
6372 if (DstTy != Src1Ty || DstTy != Src2Ty)
6373 return UnableToLegalize;
6375 moreElementsVectorSrc(MI, MoreTy, 1);
6376 moreElementsVectorSrc(MI, MoreTy, 2);
6378 // Adjust mask based on new input vector length.
6379 SmallVector<int, 16> NewMask(WidenNumElts, -1);
6380 for (unsigned I = 0; I != NumElts; ++I) {
6381 int Idx = Mask[I];
6382 if (Idx < static_cast<int>(NumElts))
6383 NewMask[I] = Idx;
6384 else
6385 NewMask[I] = Idx - NumElts + WidenNumElts;
6387 moreElementsVectorDst(MI, MoreTy, 0);
6388 MIRBuilder.setInstrAndDebugLoc(MI);
6389 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
6390 MI.getOperand(1).getReg(),
6391 MI.getOperand(2).getReg(), NewMask);
6392 MI.eraseFromParent();
6393 return Legalized;
6396 void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
6397 ArrayRef<Register> Src1Regs,
6398 ArrayRef<Register> Src2Regs,
6399 LLT NarrowTy) {
6400 MachineIRBuilder &B = MIRBuilder;
6401 unsigned SrcParts = Src1Regs.size();
6402 unsigned DstParts = DstRegs.size();
6404 unsigned DstIdx = 0; // Low bits of the result.
6405 Register FactorSum =
6406 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
6407 DstRegs[DstIdx] = FactorSum;
6409 unsigned CarrySumPrevDstIdx;
6410 SmallVector<Register, 4> Factors;
6412 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
6413 // Collect low parts of muls for DstIdx.
6414 for (unsigned i = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
6415 i <= std::min(DstIdx, SrcParts - 1); ++i) {
6416 MachineInstrBuilder Mul =
6417 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
6418 Factors.push_back(Mul.getReg(0));
6420 // Collect high parts of muls from previous DstIdx.
6421 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
6422 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
6423 MachineInstrBuilder Umulh =
6424 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
6425 Factors.push_back(Umulh.getReg(0));
6427 // Add CarrySum from additions calculated for previous DstIdx.
6428 if (DstIdx != 1) {
6429 Factors.push_back(CarrySumPrevDstIdx);
6432 Register CarrySum;
6433 // Add all factors and accumulate all carries into CarrySum.
6434 if (DstIdx != DstParts - 1) {
6435 MachineInstrBuilder Uaddo =
6436 B.buildUAddo(NarrowTy, LLT::scalar(1), Factors[0], Factors[1]);
6437 FactorSum = Uaddo.getReg(0);
6438 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
6439 for (unsigned i = 2; i < Factors.size(); ++i) {
6440 MachineInstrBuilder Uaddo =
6441 B.buildUAddo(NarrowTy, LLT::scalar(1), FactorSum, Factors[i]);
6442 FactorSum = Uaddo.getReg(0);
6443 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
6444 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
6446 } else {
6447 // Since value for the next index is not calculated, neither is CarrySum.
6448 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
6449 for (unsigned i = 2; i < Factors.size(); ++i)
6450 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
6453 CarrySumPrevDstIdx = CarrySum;
6454 DstRegs[DstIdx] = FactorSum;
6455 Factors.clear();
6459 LegalizerHelper::LegalizeResult
6460 LegalizerHelper::narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx,
6461 LLT NarrowTy) {
6462 if (TypeIdx != 0)
6463 return UnableToLegalize;
6465 Register DstReg = MI.getOperand(0).getReg();
6466 LLT DstType = MRI.getType(DstReg);
6467 // FIXME: add support for vector types
6468 if (DstType.isVector())
6469 return UnableToLegalize;
6471 unsigned Opcode = MI.getOpcode();
6472 unsigned OpO, OpE, OpF;
6473 switch (Opcode) {
6474 case TargetOpcode::G_SADDO:
6475 case TargetOpcode::G_SADDE:
6476 case TargetOpcode::G_UADDO:
6477 case TargetOpcode::G_UADDE:
6478 case TargetOpcode::G_ADD:
6479 OpO = TargetOpcode::G_UADDO;
6480 OpE = TargetOpcode::G_UADDE;
6481 OpF = TargetOpcode::G_UADDE;
6482 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
6483 OpF = TargetOpcode::G_SADDE;
6484 break;
6485 case TargetOpcode::G_SSUBO:
6486 case TargetOpcode::G_SSUBE:
6487 case TargetOpcode::G_USUBO:
6488 case TargetOpcode::G_USUBE:
6489 case TargetOpcode::G_SUB:
6490 OpO = TargetOpcode::G_USUBO;
6491 OpE = TargetOpcode::G_USUBE;
6492 OpF = TargetOpcode::G_USUBE;
6493 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
6494 OpF = TargetOpcode::G_SSUBE;
6495 break;
6496 default:
6497 llvm_unreachable("Unexpected add/sub opcode!");
6500 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
6501 unsigned NumDefs = MI.getNumExplicitDefs();
6502 Register Src1 = MI.getOperand(NumDefs).getReg();
6503 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
6504 Register CarryDst, CarryIn;
6505 if (NumDefs == 2)
6506 CarryDst = MI.getOperand(1).getReg();
6507 if (MI.getNumOperands() == NumDefs + 3)
6508 CarryIn = MI.getOperand(NumDefs + 2).getReg();
6510 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
6511 LLT LeftoverTy, DummyTy;
6512 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
6513 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
6514 MIRBuilder, MRI);
6515 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
6516 MRI);
6518 int NarrowParts = Src1Regs.size();
6519 Src1Regs.append(Src1Left);
6520 Src2Regs.append(Src2Left);
6521 DstRegs.reserve(Src1Regs.size());
6523 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
6524 Register DstReg =
6525 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
6526 Register CarryOut;
6527 // Forward the final carry-out to the destination register
6528 if (i == e - 1 && CarryDst)
6529 CarryOut = CarryDst;
6530 else
6531 CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
6533 if (!CarryIn) {
6534 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
6535 {Src1Regs[i], Src2Regs[i]});
6536 } else if (i == e - 1) {
6537 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
6538 {Src1Regs[i], Src2Regs[i], CarryIn});
6539 } else {
6540 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
6541 {Src1Regs[i], Src2Regs[i], CarryIn});
6544 DstRegs.push_back(DstReg);
6545 CarryIn = CarryOut;
6547 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
6548 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
6549 ArrayRef(DstRegs).drop_front(NarrowParts));
6551 MI.eraseFromParent();
6552 return Legalized;
6555 LegalizerHelper::LegalizeResult
6556 LegalizerHelper::narrowScalarMul(MachineInstr &MI, LLT NarrowTy) {
6557 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
6559 LLT Ty = MRI.getType(DstReg);
6560 if (Ty.isVector())
6561 return UnableToLegalize;
6563 unsigned Size = Ty.getSizeInBits();
6564 unsigned NarrowSize = NarrowTy.getSizeInBits();
6565 if (Size % NarrowSize != 0)
6566 return UnableToLegalize;
6568 unsigned NumParts = Size / NarrowSize;
6569 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
6570 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
6572 SmallVector<Register, 2> Src1Parts, Src2Parts;
6573 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
6574 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
6575 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
6576 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
6578 // Take only high half of registers if this is high mul.
6579 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
6580 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
6581 MI.eraseFromParent();
6582 return Legalized;
6585 LegalizerHelper::LegalizeResult
6586 LegalizerHelper::narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx,
6587 LLT NarrowTy) {
6588 if (TypeIdx != 0)
6589 return UnableToLegalize;
6591 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
6593 Register Src = MI.getOperand(1).getReg();
6594 LLT SrcTy = MRI.getType(Src);
6596 // If all finite floats fit into the narrowed integer type, we can just swap
6597 // out the result type. This is practically only useful for conversions from
6598 // half to at least 16-bits, so just handle the one case.
6599 if (SrcTy.getScalarType() != LLT::scalar(16) ||
6600 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
6601 return UnableToLegalize;
6603 Observer.changingInstr(MI);
6604 narrowScalarDst(MI, NarrowTy, 0,
6605 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
6606 Observer.changedInstr(MI);
6607 return Legalized;
6610 LegalizerHelper::LegalizeResult
6611 LegalizerHelper::narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx,
6612 LLT NarrowTy) {
6613 if (TypeIdx != 1)
6614 return UnableToLegalize;
6616 uint64_t NarrowSize = NarrowTy.getSizeInBits();
6618 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
6619 // FIXME: add support for when SizeOp1 isn't an exact multiple of
6620 // NarrowSize.
6621 if (SizeOp1 % NarrowSize != 0)
6622 return UnableToLegalize;
6623 int NumParts = SizeOp1 / NarrowSize;
6625 SmallVector<Register, 2> SrcRegs, DstRegs;
6626 SmallVector<uint64_t, 2> Indexes;
6627 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
6628 MIRBuilder, MRI);
6630 Register OpReg = MI.getOperand(0).getReg();
6631 uint64_t OpStart = MI.getOperand(2).getImm();
6632 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
6633 for (int i = 0; i < NumParts; ++i) {
6634 unsigned SrcStart = i * NarrowSize;
6636 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
6637 // No part of the extract uses this subregister, ignore it.
6638 continue;
6639 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
6640 // The entire subregister is extracted, forward the value.
6641 DstRegs.push_back(SrcRegs[i]);
6642 continue;
6645 // OpSegStart is where this destination segment would start in OpReg if it
6646 // extended infinitely in both directions.
6647 int64_t ExtractOffset;
6648 uint64_t SegSize;
6649 if (OpStart < SrcStart) {
6650 ExtractOffset = 0;
6651 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
6652 } else {
6653 ExtractOffset = OpStart - SrcStart;
6654 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
6657 Register SegReg = SrcRegs[i];
6658 if (ExtractOffset != 0 || SegSize != NarrowSize) {
6659 // A genuine extract is needed.
6660 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
6661 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
6664 DstRegs.push_back(SegReg);
6667 Register DstReg = MI.getOperand(0).getReg();
6668 if (MRI.getType(DstReg).isVector())
6669 MIRBuilder.buildBuildVector(DstReg, DstRegs);
6670 else if (DstRegs.size() > 1)
6671 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
6672 else
6673 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
6674 MI.eraseFromParent();
6675 return Legalized;
6678 LegalizerHelper::LegalizeResult
6679 LegalizerHelper::narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx,
6680 LLT NarrowTy) {
6681 // FIXME: Don't know how to handle secondary types yet.
6682 if (TypeIdx != 0)
6683 return UnableToLegalize;
6685 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
6686 SmallVector<uint64_t, 2> Indexes;
6687 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
6688 LLT LeftoverTy;
6689 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
6690 LeftoverRegs, MIRBuilder, MRI);
6692 SrcRegs.append(LeftoverRegs);
6694 uint64_t NarrowSize = NarrowTy.getSizeInBits();
6695 Register OpReg = MI.getOperand(2).getReg();
6696 uint64_t OpStart = MI.getOperand(3).getImm();
6697 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
6698 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
6699 unsigned DstStart = I * NarrowSize;
6701 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
6702 // The entire subregister is defined by this insert, forward the new
6703 // value.
6704 DstRegs.push_back(OpReg);
6705 continue;
6708 Register SrcReg = SrcRegs[I];
6709 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
6710 // The leftover reg is smaller than NarrowTy, so we need to extend it.
6711 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
6712 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
6715 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
6716 // No part of the insert affects this subregister, forward the original.
6717 DstRegs.push_back(SrcReg);
6718 continue;
6721 // OpSegStart is where this destination segment would start in OpReg if it
6722 // extended infinitely in both directions.
6723 int64_t ExtractOffset, InsertOffset;
6724 uint64_t SegSize;
6725 if (OpStart < DstStart) {
6726 InsertOffset = 0;
6727 ExtractOffset = DstStart - OpStart;
6728 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
6729 } else {
6730 InsertOffset = OpStart - DstStart;
6731 ExtractOffset = 0;
6732 SegSize =
6733 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
6736 Register SegReg = OpReg;
6737 if (ExtractOffset != 0 || SegSize != OpSize) {
6738 // A genuine extract is needed.
6739 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
6740 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
6743 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
6744 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
6745 DstRegs.push_back(DstReg);
6748 uint64_t WideSize = DstRegs.size() * NarrowSize;
6749 Register DstReg = MI.getOperand(0).getReg();
6750 if (WideSize > RegTy.getSizeInBits()) {
6751 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
6752 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
6753 MIRBuilder.buildTrunc(DstReg, MergeReg);
6754 } else
6755 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
6757 MI.eraseFromParent();
6758 return Legalized;
6761 LegalizerHelper::LegalizeResult
6762 LegalizerHelper::narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx,
6763 LLT NarrowTy) {
6764 Register DstReg = MI.getOperand(0).getReg();
6765 LLT DstTy = MRI.getType(DstReg);
6767 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
6769 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
6770 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
6771 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
6772 LLT LeftoverTy;
6773 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
6774 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
6775 return UnableToLegalize;
6777 LLT Unused;
6778 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
6779 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
6780 llvm_unreachable("inconsistent extractParts result");
6782 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
6783 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
6784 {Src0Regs[I], Src1Regs[I]});
6785 DstRegs.push_back(Inst.getReg(0));
6788 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
6789 auto Inst = MIRBuilder.buildInstr(
6790 MI.getOpcode(),
6791 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
6792 DstLeftoverRegs.push_back(Inst.getReg(0));
6795 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
6796 LeftoverTy, DstLeftoverRegs);
6798 MI.eraseFromParent();
6799 return Legalized;
6802 LegalizerHelper::LegalizeResult
6803 LegalizerHelper::narrowScalarExt(MachineInstr &MI, unsigned TypeIdx,
6804 LLT NarrowTy) {
6805 if (TypeIdx != 0)
6806 return UnableToLegalize;
6808 auto [DstReg, SrcReg] = MI.getFirst2Regs();
6810 LLT DstTy = MRI.getType(DstReg);
6811 if (DstTy.isVector())
6812 return UnableToLegalize;
6814 SmallVector<Register, 8> Parts;
6815 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
6816 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
6817 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
6819 MI.eraseFromParent();
6820 return Legalized;
6823 LegalizerHelper::LegalizeResult
6824 LegalizerHelper::narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx,
6825 LLT NarrowTy) {
6826 if (TypeIdx != 0)
6827 return UnableToLegalize;
6829 Register CondReg = MI.getOperand(1).getReg();
6830 LLT CondTy = MRI.getType(CondReg);
6831 if (CondTy.isVector()) // TODO: Handle vselect
6832 return UnableToLegalize;
6834 Register DstReg = MI.getOperand(0).getReg();
6835 LLT DstTy = MRI.getType(DstReg);
6837 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
6838 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
6839 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
6840 LLT LeftoverTy;
6841 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
6842 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
6843 return UnableToLegalize;
6845 LLT Unused;
6846 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
6847 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
6848 llvm_unreachable("inconsistent extractParts result");
6850 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
6851 auto Select = MIRBuilder.buildSelect(NarrowTy,
6852 CondReg, Src1Regs[I], Src2Regs[I]);
6853 DstRegs.push_back(Select.getReg(0));
6856 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
6857 auto Select = MIRBuilder.buildSelect(
6858 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
6859 DstLeftoverRegs.push_back(Select.getReg(0));
6862 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
6863 LeftoverTy, DstLeftoverRegs);
6865 MI.eraseFromParent();
6866 return Legalized;
6869 LegalizerHelper::LegalizeResult
6870 LegalizerHelper::narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx,
6871 LLT NarrowTy) {
6872 if (TypeIdx != 1)
6873 return UnableToLegalize;
6875 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6876 unsigned NarrowSize = NarrowTy.getSizeInBits();
6878 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
6879 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF;
6881 MachineIRBuilder &B = MIRBuilder;
6882 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
6883 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
6884 auto C_0 = B.buildConstant(NarrowTy, 0);
6885 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
6886 UnmergeSrc.getReg(1), C_0);
6887 auto LoCTLZ = IsUndef ?
6888 B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0)) :
6889 B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
6890 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
6891 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
6892 auto HiCTLZ = B.buildCTLZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1));
6893 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
6895 MI.eraseFromParent();
6896 return Legalized;
6899 return UnableToLegalize;
6902 LegalizerHelper::LegalizeResult
6903 LegalizerHelper::narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx,
6904 LLT NarrowTy) {
6905 if (TypeIdx != 1)
6906 return UnableToLegalize;
6908 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6909 unsigned NarrowSize = NarrowTy.getSizeInBits();
6911 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
6912 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_UNDEF;
6914 MachineIRBuilder &B = MIRBuilder;
6915 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
6916 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
6917 auto C_0 = B.buildConstant(NarrowTy, 0);
6918 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
6919 UnmergeSrc.getReg(0), C_0);
6920 auto HiCTTZ = IsUndef ?
6921 B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(1)) :
6922 B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
6923 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
6924 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
6925 auto LoCTTZ = B.buildCTTZ_ZERO_UNDEF(DstTy, UnmergeSrc.getReg(0));
6926 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
6928 MI.eraseFromParent();
6929 return Legalized;
6932 return UnableToLegalize;
6935 LegalizerHelper::LegalizeResult
6936 LegalizerHelper::narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx,
6937 LLT NarrowTy) {
6938 if (TypeIdx != 1)
6939 return UnableToLegalize;
6941 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6942 unsigned NarrowSize = NarrowTy.getSizeInBits();
6944 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
6945 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
6947 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
6948 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
6949 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
6951 MI.eraseFromParent();
6952 return Legalized;
6955 return UnableToLegalize;
6958 LegalizerHelper::LegalizeResult
6959 LegalizerHelper::narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx,
6960 LLT NarrowTy) {
6961 if (TypeIdx != 1)
6962 return UnableToLegalize;
6964 MachineIRBuilder &B = MIRBuilder;
6965 Register ExpReg = MI.getOperand(2).getReg();
6966 LLT ExpTy = MRI.getType(ExpReg);
6968 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
6970 // Clamp the exponent to the range of the target type.
6971 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
6972 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
6973 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
6974 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
6976 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
6977 Observer.changingInstr(MI);
6978 MI.getOperand(2).setReg(Trunc.getReg(0));
6979 Observer.changedInstr(MI);
6980 return Legalized;
6983 LegalizerHelper::LegalizeResult
6984 LegalizerHelper::lowerBitCount(MachineInstr &MI) {
6985 unsigned Opc = MI.getOpcode();
6986 const auto &TII = MIRBuilder.getTII();
6987 auto isSupported = [this](const LegalityQuery &Q) {
6988 auto QAction = LI.getAction(Q).Action;
6989 return QAction == Legal || QAction == Libcall || QAction == Custom;
6991 switch (Opc) {
6992 default:
6993 return UnableToLegalize;
6994 case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
6995 // This trivially expands to CTLZ.
6996 Observer.changingInstr(MI);
6997 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
6998 Observer.changedInstr(MI);
6999 return Legalized;
7001 case TargetOpcode::G_CTLZ: {
7002 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7003 unsigned Len = SrcTy.getSizeInBits();
7005 if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {DstTy, SrcTy}})) {
7006 // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
7007 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_UNDEF(DstTy, SrcReg);
7008 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
7009 auto ICmp = MIRBuilder.buildICmp(
7010 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
7011 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7012 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
7013 MI.eraseFromParent();
7014 return Legalized;
7016 // for now, we do this:
7017 // NewLen = NextPowerOf2(Len);
7018 // x = x | (x >> 1);
7019 // x = x | (x >> 2);
7020 // ...
7021 // x = x | (x >>16);
7022 // x = x | (x >>32); // for 64-bit input
7023 // Upto NewLen/2
7024 // return Len - popcount(x);
7026 // Ref: "Hacker's Delight" by Henry Warren
7027 Register Op = SrcReg;
7028 unsigned NewLen = PowerOf2Ceil(Len);
7029 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
7030 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
7031 auto MIBOp = MIRBuilder.buildOr(
7032 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
7033 Op = MIBOp.getReg(0);
7035 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
7036 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
7037 MIBPop);
7038 MI.eraseFromParent();
7039 return Legalized;
7041 case TargetOpcode::G_CTTZ_ZERO_UNDEF: {
7042 // This trivially expands to CTTZ.
7043 Observer.changingInstr(MI);
7044 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
7045 Observer.changedInstr(MI);
7046 return Legalized;
7048 case TargetOpcode::G_CTTZ: {
7049 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7051 unsigned Len = SrcTy.getSizeInBits();
7052 if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {DstTy, SrcTy}})) {
7053 // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
7054 // zero.
7055 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_UNDEF(DstTy, SrcReg);
7056 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
7057 auto ICmp = MIRBuilder.buildICmp(
7058 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
7059 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7060 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
7061 MI.eraseFromParent();
7062 return Legalized;
7064 // for now, we use: { return popcount(~x & (x - 1)); }
7065 // unless the target has ctlz but not ctpop, in which case we use:
7066 // { return 32 - nlz(~x & (x-1)); }
7067 // Ref: "Hacker's Delight" by Henry Warren
7068 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
7069 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
7070 auto MIBTmp = MIRBuilder.buildAnd(
7071 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
7072 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
7073 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
7074 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
7075 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
7076 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
7077 MI.eraseFromParent();
7078 return Legalized;
7080 Observer.changingInstr(MI);
7081 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
7082 MI.getOperand(1).setReg(MIBTmp.getReg(0));
7083 Observer.changedInstr(MI);
7084 return Legalized;
7086 case TargetOpcode::G_CTPOP: {
7087 Register SrcReg = MI.getOperand(1).getReg();
7088 LLT Ty = MRI.getType(SrcReg);
7089 unsigned Size = Ty.getSizeInBits();
7090 MachineIRBuilder &B = MIRBuilder;
7092 // Count set bits in blocks of 2 bits. Default approach would be
7093 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
7094 // We use following formula instead:
7095 // B2Count = val - { (val >> 1) & 0x55555555 }
7096 // since it gives same result in blocks of 2 with one instruction less.
7097 auto C_1 = B.buildConstant(Ty, 1);
7098 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
7099 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
7100 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
7101 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
7102 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
7104 // In order to get count in blocks of 4 add values from adjacent block of 2.
7105 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
7106 auto C_2 = B.buildConstant(Ty, 2);
7107 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
7108 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
7109 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
7110 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
7111 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
7112 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
7114 // For count in blocks of 8 bits we don't have to mask high 4 bits before
7115 // addition since count value sits in range {0,...,8} and 4 bits are enough
7116 // to hold such binary values. After addition high 4 bits still hold count
7117 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
7118 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
7119 auto C_4 = B.buildConstant(Ty, 4);
7120 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
7121 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
7122 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
7123 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
7124 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
7126 assert(Size<=128 && "Scalar size is too large for CTPOP lower algorithm");
7127 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
7128 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
7129 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
7131 // Shift count result from 8 high bits to low bits.
7132 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
7134 auto IsMulSupported = [this](const LLT Ty) {
7135 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
7136 return Action == Legal || Action == WidenScalar || Action == Custom;
7138 if (IsMulSupported(Ty)) {
7139 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
7140 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
7141 } else {
7142 auto ResTmp = B8Count;
7143 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
7144 auto ShiftC = B.buildConstant(Ty, Shift);
7145 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
7146 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
7148 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
7150 MI.eraseFromParent();
7151 return Legalized;
7156 // Check that (every element of) Reg is undef or not an exact multiple of BW.
7157 static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo &MRI,
7158 Register Reg, unsigned BW) {
7159 return matchUnaryPredicate(
7160 MRI, Reg,
7161 [=](const Constant *C) {
7162 // Null constant here means an undef.
7163 const ConstantInt *CI = dyn_cast_or_null<ConstantInt>(C);
7164 return !CI || CI->getValue().urem(BW) != 0;
7166 /*AllowUndefs*/ true);
7169 LegalizerHelper::LegalizeResult
7170 LegalizerHelper::lowerFunnelShiftWithInverse(MachineInstr &MI) {
7171 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
7172 LLT Ty = MRI.getType(Dst);
7173 LLT ShTy = MRI.getType(Z);
7175 unsigned BW = Ty.getScalarSizeInBits();
7177 if (!isPowerOf2_32(BW))
7178 return UnableToLegalize;
7180 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
7181 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
7183 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
7184 // fshl X, Y, Z -> fshr X, Y, -Z
7185 // fshr X, Y, Z -> fshl X, Y, -Z
7186 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
7187 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
7188 } else {
7189 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
7190 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
7191 auto One = MIRBuilder.buildConstant(ShTy, 1);
7192 if (IsFSHL) {
7193 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
7194 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
7195 } else {
7196 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
7197 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
7200 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
7203 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
7204 MI.eraseFromParent();
7205 return Legalized;
7208 LegalizerHelper::LegalizeResult
7209 LegalizerHelper::lowerFunnelShiftAsShifts(MachineInstr &MI) {
7210 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
7211 LLT Ty = MRI.getType(Dst);
7212 LLT ShTy = MRI.getType(Z);
7214 const unsigned BW = Ty.getScalarSizeInBits();
7215 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
7217 Register ShX, ShY;
7218 Register ShAmt, InvShAmt;
7220 // FIXME: Emit optimized urem by constant instead of letting it expand later.
7221 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
7222 // fshl: X << C | Y >> (BW - C)
7223 // fshr: X << (BW - C) | Y >> C
7224 // where C = Z % BW is not zero
7225 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
7226 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
7227 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
7228 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
7229 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
7230 } else {
7231 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
7232 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
7233 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
7234 if (isPowerOf2_32(BW)) {
7235 // Z % BW -> Z & (BW - 1)
7236 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
7237 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
7238 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
7239 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
7240 } else {
7241 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
7242 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
7243 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
7246 auto One = MIRBuilder.buildConstant(ShTy, 1);
7247 if (IsFSHL) {
7248 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
7249 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
7250 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
7251 } else {
7252 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
7253 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
7254 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
7258 MIRBuilder.buildOr(Dst, ShX, ShY);
7259 MI.eraseFromParent();
7260 return Legalized;
7263 LegalizerHelper::LegalizeResult
7264 LegalizerHelper::lowerFunnelShift(MachineInstr &MI) {
7265 // These operations approximately do the following (while avoiding undefined
7266 // shifts by BW):
7267 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
7268 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
7269 Register Dst = MI.getOperand(0).getReg();
7270 LLT Ty = MRI.getType(Dst);
7271 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
7273 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
7274 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
7276 // TODO: Use smarter heuristic that accounts for vector legalization.
7277 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
7278 return lowerFunnelShiftAsShifts(MI);
7280 // This only works for powers of 2, fallback to shifts if it fails.
7281 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
7282 if (Result == UnableToLegalize)
7283 return lowerFunnelShiftAsShifts(MI);
7284 return Result;
7287 LegalizerHelper::LegalizeResult LegalizerHelper::lowerEXT(MachineInstr &MI) {
7288 auto [Dst, Src] = MI.getFirst2Regs();
7289 LLT DstTy = MRI.getType(Dst);
7290 LLT SrcTy = MRI.getType(Src);
7292 uint32_t DstTySize = DstTy.getSizeInBits();
7293 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
7294 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
7296 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
7297 !isPowerOf2_32(SrcTyScalarSize))
7298 return UnableToLegalize;
7300 // The step between extend is too large, split it by creating an intermediate
7301 // extend instruction
7302 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
7303 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
7304 // If the destination type is illegal, split it into multiple statements
7305 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
7306 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
7307 // Unmerge the vector
7308 LLT EltTy = MidTy.changeElementCount(
7309 MidTy.getElementCount().divideCoefficientBy(2));
7310 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
7312 // ZExt the vectors
7313 LLT ZExtResTy = DstTy.changeElementCount(
7314 DstTy.getElementCount().divideCoefficientBy(2));
7315 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
7316 {UnmergeSrc.getReg(0)});
7317 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
7318 {UnmergeSrc.getReg(1)});
7320 // Merge the ending vectors
7321 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
7323 MI.eraseFromParent();
7324 return Legalized;
7326 return UnableToLegalize;
7329 LegalizerHelper::LegalizeResult LegalizerHelper::lowerTRUNC(MachineInstr &MI) {
7330 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
7331 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
7332 // Similar to how operand splitting is done in SelectiondDAG, we can handle
7333 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
7334 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
7335 // %lo16(<4 x s16>) = G_TRUNC %inlo
7336 // %hi16(<4 x s16>) = G_TRUNC %inhi
7337 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
7338 // %res(<8 x s8>) = G_TRUNC %in16
7340 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
7342 Register DstReg = MI.getOperand(0).getReg();
7343 Register SrcReg = MI.getOperand(1).getReg();
7344 LLT DstTy = MRI.getType(DstReg);
7345 LLT SrcTy = MRI.getType(SrcReg);
7347 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
7348 isPowerOf2_32(DstTy.getScalarSizeInBits()) &&
7349 isPowerOf2_32(SrcTy.getNumElements()) &&
7350 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
7351 // Split input type.
7352 LLT SplitSrcTy = SrcTy.changeElementCount(
7353 SrcTy.getElementCount().divideCoefficientBy(2));
7355 // First, split the source into two smaller vectors.
7356 SmallVector<Register, 2> SplitSrcs;
7357 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
7359 // Truncate the splits into intermediate narrower elements.
7360 LLT InterTy;
7361 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
7362 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
7363 else
7364 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
7365 for (unsigned I = 0; I < SplitSrcs.size(); ++I) {
7366 SplitSrcs[I] = MIRBuilder.buildTrunc(InterTy, SplitSrcs[I]).getReg(0);
7369 // Combine the new truncates into one vector
7370 auto Merge = MIRBuilder.buildMergeLikeInstr(
7371 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
7373 // Truncate the new vector to the final result type
7374 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
7375 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
7376 else
7377 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
7379 MI.eraseFromParent();
7381 return Legalized;
7383 return UnableToLegalize;
7386 LegalizerHelper::LegalizeResult
7387 LegalizerHelper::lowerRotateWithReverseRotate(MachineInstr &MI) {
7388 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
7389 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
7390 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
7391 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
7392 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
7393 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
7394 MI.eraseFromParent();
7395 return Legalized;
7398 LegalizerHelper::LegalizeResult LegalizerHelper::lowerRotate(MachineInstr &MI) {
7399 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
7401 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
7402 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
7404 MIRBuilder.setInstrAndDebugLoc(MI);
7406 // If a rotate in the other direction is supported, use it.
7407 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
7408 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
7409 isPowerOf2_32(EltSizeInBits))
7410 return lowerRotateWithReverseRotate(MI);
7412 // If a funnel shift is supported, use it.
7413 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
7414 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
7415 bool IsFShLegal = false;
7416 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
7417 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
7418 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
7419 Register R3) {
7420 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
7421 MI.eraseFromParent();
7422 return Legalized;
7424 // If a funnel shift in the other direction is supported, use it.
7425 if (IsFShLegal) {
7426 return buildFunnelShift(FShOpc, Dst, Src, Amt);
7427 } else if (isPowerOf2_32(EltSizeInBits)) {
7428 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
7429 return buildFunnelShift(RevFsh, Dst, Src, Amt);
7433 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
7434 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
7435 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
7436 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
7437 Register ShVal;
7438 Register RevShiftVal;
7439 if (isPowerOf2_32(EltSizeInBits)) {
7440 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
7441 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
7442 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
7443 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
7444 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
7445 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
7446 RevShiftVal =
7447 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
7448 } else {
7449 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
7450 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
7451 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
7452 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
7453 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
7454 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
7455 auto One = MIRBuilder.buildConstant(AmtTy, 1);
7456 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
7457 RevShiftVal =
7458 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
7460 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal);
7461 MI.eraseFromParent();
7462 return Legalized;
7465 // Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
7466 // representation.
7467 LegalizerHelper::LegalizeResult
7468 LegalizerHelper::lowerU64ToF32BitOps(MachineInstr &MI) {
7469 auto [Dst, Src] = MI.getFirst2Regs();
7470 const LLT S64 = LLT::scalar(64);
7471 const LLT S32 = LLT::scalar(32);
7472 const LLT S1 = LLT::scalar(1);
7474 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
7476 // unsigned cul2f(ulong u) {
7477 // uint lz = clz(u);
7478 // uint e = (u != 0) ? 127U + 63U - lz : 0;
7479 // u = (u << lz) & 0x7fffffffffffffffUL;
7480 // ulong t = u & 0xffffffffffUL;
7481 // uint v = (e << 23) | (uint)(u >> 40);
7482 // uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
7483 // return as_float(v + r);
7484 // }
7486 auto Zero32 = MIRBuilder.buildConstant(S32, 0);
7487 auto Zero64 = MIRBuilder.buildConstant(S64, 0);
7489 auto LZ = MIRBuilder.buildCTLZ_ZERO_UNDEF(S32, Src);
7491 auto K = MIRBuilder.buildConstant(S32, 127U + 63U);
7492 auto Sub = MIRBuilder.buildSub(S32, K, LZ);
7494 auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);
7495 auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);
7497 auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);
7498 auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);
7500 auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);
7502 auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);
7503 auto T = MIRBuilder.buildAnd(S64, U, Mask1);
7505 auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));
7506 auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));
7507 auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));
7509 auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);
7510 auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);
7511 auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);
7512 auto One = MIRBuilder.buildConstant(S32, 1);
7514 auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);
7515 auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);
7516 auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);
7517 MIRBuilder.buildAdd(Dst, V, R);
7519 MI.eraseFromParent();
7520 return Legalized;
7523 // Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
7524 // operations and G_SITOFP
7525 LegalizerHelper::LegalizeResult
7526 LegalizerHelper::lowerU64ToF32WithSITOFP(MachineInstr &MI) {
7527 auto [Dst, Src] = MI.getFirst2Regs();
7528 const LLT S64 = LLT::scalar(64);
7529 const LLT S32 = LLT::scalar(32);
7530 const LLT S1 = LLT::scalar(1);
7532 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
7534 // For i64 < INT_MAX we simply reuse SITOFP.
7535 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
7536 // saved before division, convert to float by SITOFP, multiply the result
7537 // by 2.
7538 auto One = MIRBuilder.buildConstant(S64, 1);
7539 auto Zero = MIRBuilder.buildConstant(S64, 0);
7540 // Result if Src < INT_MAX
7541 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
7542 // Result if Src >= INT_MAX
7543 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
7544 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
7545 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
7546 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
7547 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
7548 // Check if the original value is larger than INT_MAX by comparing with
7549 // zero to pick one of the two conversions.
7550 auto IsLarge =
7551 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
7552 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
7554 MI.eraseFromParent();
7555 return Legalized;
7558 // Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
7559 // IEEE double representation.
7560 LegalizerHelper::LegalizeResult
7561 LegalizerHelper::lowerU64ToF64BitFloatOps(MachineInstr &MI) {
7562 auto [Dst, Src] = MI.getFirst2Regs();
7563 const LLT S64 = LLT::scalar(64);
7564 const LLT S32 = LLT::scalar(32);
7566 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
7568 // We create double value from 32 bit parts with 32 exponent difference.
7569 // Note that + and - are float operations that adjust the implicit leading
7570 // one, the bases 2^52 and 2^84 are for illustrative purposes.
7572 // X = 2^52 * 1.0...LowBits
7573 // Y = 2^84 * 1.0...HighBits
7574 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
7575 // = - 2^52 * 1.0...HighBits
7576 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
7577 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
7578 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
7579 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
7580 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
7581 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
7583 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
7584 LowBits = MIRBuilder.buildZExt(S64, LowBits);
7585 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
7586 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
7587 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
7588 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
7589 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
7591 MI.eraseFromParent();
7592 return Legalized;
7595 LegalizerHelper::LegalizeResult LegalizerHelper::lowerUITOFP(MachineInstr &MI) {
7596 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
7598 if (SrcTy == LLT::scalar(1)) {
7599 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
7600 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
7601 MIRBuilder.buildSelect(Dst, Src, True, False);
7602 MI.eraseFromParent();
7603 return Legalized;
7606 if (SrcTy != LLT::scalar(64))
7607 return UnableToLegalize;
7609 if (DstTy == LLT::scalar(32))
7610 // TODO: SelectionDAG has several alternative expansions to port which may
7611 // be more reasonable depending on the available instructions. We also need
7612 // a more advanced mechanism to choose an optimal version depending on
7613 // target features such as sitofp or CTLZ availability.
7614 return lowerU64ToF32WithSITOFP(MI);
7616 if (DstTy == LLT::scalar(64))
7617 return lowerU64ToF64BitFloatOps(MI);
7619 return UnableToLegalize;
7622 LegalizerHelper::LegalizeResult LegalizerHelper::lowerSITOFP(MachineInstr &MI) {
7623 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
7625 const LLT S64 = LLT::scalar(64);
7626 const LLT S32 = LLT::scalar(32);
7627 const LLT S1 = LLT::scalar(1);
7629 if (SrcTy == S1) {
7630 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
7631 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
7632 MIRBuilder.buildSelect(Dst, Src, True, False);
7633 MI.eraseFromParent();
7634 return Legalized;
7637 if (SrcTy != S64)
7638 return UnableToLegalize;
7640 if (DstTy == S32) {
7641 // signed cl2f(long l) {
7642 // long s = l >> 63;
7643 // float r = cul2f((l + s) ^ s);
7644 // return s ? -r : r;
7645 // }
7646 Register L = Src;
7647 auto SignBit = MIRBuilder.buildConstant(S64, 63);
7648 auto S = MIRBuilder.buildAShr(S64, L, SignBit);
7650 auto LPlusS = MIRBuilder.buildAdd(S64, L, S);
7651 auto Xor = MIRBuilder.buildXor(S64, LPlusS, S);
7652 auto R = MIRBuilder.buildUITOFP(S32, Xor);
7654 auto RNeg = MIRBuilder.buildFNeg(S32, R);
7655 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, S,
7656 MIRBuilder.buildConstant(S64, 0));
7657 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
7658 MI.eraseFromParent();
7659 return Legalized;
7662 return UnableToLegalize;
7665 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOUI(MachineInstr &MI) {
7666 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
7667 const LLT S64 = LLT::scalar(64);
7668 const LLT S32 = LLT::scalar(32);
7670 if (SrcTy != S64 && SrcTy != S32)
7671 return UnableToLegalize;
7672 if (DstTy != S32 && DstTy != S64)
7673 return UnableToLegalize;
7675 // FPTOSI gives same result as FPTOUI for positive signed integers.
7676 // FPTOUI needs to deal with fp values that convert to unsigned integers
7677 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
7679 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
7680 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
7681 : APFloat::IEEEdouble(),
7682 APInt::getZero(SrcTy.getSizeInBits()));
7683 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
7685 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
7687 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
7688 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
7689 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
7690 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
7691 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
7692 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
7693 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
7695 const LLT S1 = LLT::scalar(1);
7697 MachineInstrBuilder FCMP =
7698 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
7699 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
7701 MI.eraseFromParent();
7702 return Legalized;
7705 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPTOSI(MachineInstr &MI) {
7706 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
7707 const LLT S64 = LLT::scalar(64);
7708 const LLT S32 = LLT::scalar(32);
7710 // FIXME: Only f32 to i64 conversions are supported.
7711 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
7712 return UnableToLegalize;
7714 // Expand f32 -> i64 conversion
7715 // This algorithm comes from compiler-rt's implementation of fixsfdi:
7716 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
7718 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
7720 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
7721 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
7723 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
7724 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
7726 auto SignMask = MIRBuilder.buildConstant(SrcTy,
7727 APInt::getSignMask(SrcEltBits));
7728 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
7729 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
7730 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
7731 Sign = MIRBuilder.buildSExt(DstTy, Sign);
7733 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
7734 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
7735 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
7737 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
7738 R = MIRBuilder.buildZExt(DstTy, R);
7740 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
7741 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
7742 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
7743 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
7745 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
7746 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
7748 const LLT S1 = LLT::scalar(1);
7749 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
7750 S1, Exponent, ExponentLoBit);
7752 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
7754 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
7755 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
7757 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
7759 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
7760 S1, Exponent, ZeroSrcTy);
7762 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
7763 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
7765 MI.eraseFromParent();
7766 return Legalized;
7769 LegalizerHelper::LegalizeResult
7770 LegalizerHelper::lowerFPTOINT_SAT(MachineInstr &MI) {
7771 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
7773 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
7774 unsigned SatWidth = DstTy.getScalarSizeInBits();
7776 // Determine minimum and maximum integer values and their corresponding
7777 // floating-point values.
7778 APInt MinInt, MaxInt;
7779 if (IsSigned) {
7780 MinInt = APInt::getSignedMinValue(SatWidth);
7781 MaxInt = APInt::getSignedMaxValue(SatWidth);
7782 } else {
7783 MinInt = APInt::getMinValue(SatWidth);
7784 MaxInt = APInt::getMaxValue(SatWidth);
7787 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
7788 APFloat MinFloat(Semantics);
7789 APFloat MaxFloat(Semantics);
7791 APFloat::opStatus MinStatus =
7792 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
7793 APFloat::opStatus MaxStatus =
7794 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
7795 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
7796 !(MaxStatus & APFloat::opStatus::opInexact);
7798 // If the integer bounds are exactly representable as floats, emit a
7799 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
7800 // and selects.
7801 if (AreExactFloatBounds) {
7802 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
7803 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
7804 auto MaxP = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT,
7805 SrcTy.changeElementSize(1), Src, MaxC);
7806 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
7807 // Clamp by MaxFloat from above. NaN cannot occur.
7808 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
7809 auto MinP =
7810 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, SrcTy.changeElementSize(1), Max,
7811 MinC, MachineInstr::FmNoNans);
7812 auto Min =
7813 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
7814 // Convert clamped value to integer. In the unsigned case we're done,
7815 // because we mapped NaN to MinFloat, which will cast to zero.
7816 if (!IsSigned) {
7817 MIRBuilder.buildFPTOUI(Dst, Min);
7818 MI.eraseFromParent();
7819 return Legalized;
7822 // Otherwise, select 0 if Src is NaN.
7823 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
7824 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,
7825 DstTy.changeElementSize(1), Src, Src);
7826 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
7827 FpToInt);
7828 MI.eraseFromParent();
7829 return Legalized;
7832 // Result of direct conversion. The assumption here is that the operation is
7833 // non-trapping and it's fine to apply it to an out-of-range value if we
7834 // select it away later.
7835 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
7836 : MIRBuilder.buildFPTOUI(DstTy, Src);
7838 // If Src ULT MinFloat, select MinInt. In particular, this also selects
7839 // MinInt if Src is NaN.
7840 auto ULT =
7841 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, SrcTy.changeElementSize(1), Src,
7842 MIRBuilder.buildFConstant(SrcTy, MinFloat));
7843 auto Max = MIRBuilder.buildSelect(
7844 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
7845 // If Src OGT MaxFloat, select MaxInt.
7846 auto OGT =
7847 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, SrcTy.changeElementSize(1), Src,
7848 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
7850 // In the unsigned case we are done, because we mapped NaN to MinInt, which
7851 // is already zero.
7852 if (!IsSigned) {
7853 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
7854 Max);
7855 MI.eraseFromParent();
7856 return Legalized;
7859 // Otherwise, select 0 if Src is NaN.
7860 auto Min = MIRBuilder.buildSelect(
7861 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
7862 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO,
7863 DstTy.changeElementSize(1), Src, Src);
7864 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
7865 MI.eraseFromParent();
7866 return Legalized;
7869 // f64 -> f16 conversion using round-to-nearest-even rounding mode.
7870 LegalizerHelper::LegalizeResult
7871 LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr &MI) {
7872 const LLT S1 = LLT::scalar(1);
7873 const LLT S32 = LLT::scalar(32);
7875 auto [Dst, Src] = MI.getFirst2Regs();
7876 assert(MRI.getType(Dst).getScalarType() == LLT::scalar(16) &&
7877 MRI.getType(Src).getScalarType() == LLT::scalar(64));
7879 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
7880 return UnableToLegalize;
7882 if (MIRBuilder.getMF().getTarget().Options.UnsafeFPMath) {
7883 unsigned Flags = MI.getFlags();
7884 auto Src32 = MIRBuilder.buildFPTrunc(S32, Src, Flags);
7885 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
7886 MI.eraseFromParent();
7887 return Legalized;
7890 const unsigned ExpMask = 0x7ff;
7891 const unsigned ExpBiasf64 = 1023;
7892 const unsigned ExpBiasf16 = 15;
7894 auto Unmerge = MIRBuilder.buildUnmerge(S32, Src);
7895 Register U = Unmerge.getReg(0);
7896 Register UH = Unmerge.getReg(1);
7898 auto E = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 20));
7899 E = MIRBuilder.buildAnd(S32, E, MIRBuilder.buildConstant(S32, ExpMask));
7901 // Subtract the fp64 exponent bias (1023) to get the real exponent and
7902 // add the f16 bias (15) to get the biased exponent for the f16 format.
7903 E = MIRBuilder.buildAdd(
7904 S32, E, MIRBuilder.buildConstant(S32, -ExpBiasf64 + ExpBiasf16));
7906 auto M = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 8));
7907 M = MIRBuilder.buildAnd(S32, M, MIRBuilder.buildConstant(S32, 0xffe));
7909 auto MaskedSig = MIRBuilder.buildAnd(S32, UH,
7910 MIRBuilder.buildConstant(S32, 0x1ff));
7911 MaskedSig = MIRBuilder.buildOr(S32, MaskedSig, U);
7913 auto Zero = MIRBuilder.buildConstant(S32, 0);
7914 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
7915 auto Lo40Set = MIRBuilder.buildZExt(S32, SigCmpNE0);
7916 M = MIRBuilder.buildOr(S32, M, Lo40Set);
7918 // (M != 0 ? 0x0200 : 0) | 0x7c00;
7919 auto Bits0x200 = MIRBuilder.buildConstant(S32, 0x0200);
7920 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
7921 auto SelectCC = MIRBuilder.buildSelect(S32, CmpM_NE0, Bits0x200, Zero);
7923 auto Bits0x7c00 = MIRBuilder.buildConstant(S32, 0x7c00);
7924 auto I = MIRBuilder.buildOr(S32, SelectCC, Bits0x7c00);
7926 // N = M | (E << 12);
7927 auto EShl12 = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 12));
7928 auto N = MIRBuilder.buildOr(S32, M, EShl12);
7930 // B = clamp(1-E, 0, 13);
7931 auto One = MIRBuilder.buildConstant(S32, 1);
7932 auto OneSubExp = MIRBuilder.buildSub(S32, One, E);
7933 auto B = MIRBuilder.buildSMax(S32, OneSubExp, Zero);
7934 B = MIRBuilder.buildSMin(S32, B, MIRBuilder.buildConstant(S32, 13));
7936 auto SigSetHigh = MIRBuilder.buildOr(S32, M,
7937 MIRBuilder.buildConstant(S32, 0x1000));
7939 auto D = MIRBuilder.buildLShr(S32, SigSetHigh, B);
7940 auto D0 = MIRBuilder.buildShl(S32, D, B);
7942 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
7943 D0, SigSetHigh);
7944 auto D1 = MIRBuilder.buildZExt(S32, D0_NE_SigSetHigh);
7945 D = MIRBuilder.buildOr(S32, D, D1);
7947 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
7948 auto V = MIRBuilder.buildSelect(S32, CmpELtOne, D, N);
7950 auto VLow3 = MIRBuilder.buildAnd(S32, V, MIRBuilder.buildConstant(S32, 7));
7951 V = MIRBuilder.buildLShr(S32, V, MIRBuilder.buildConstant(S32, 2));
7953 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
7954 MIRBuilder.buildConstant(S32, 3));
7955 auto V0 = MIRBuilder.buildZExt(S32, VLow3Eq3);
7957 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
7958 MIRBuilder.buildConstant(S32, 5));
7959 auto V1 = MIRBuilder.buildZExt(S32, VLow3Gt5);
7961 V1 = MIRBuilder.buildOr(S32, V0, V1);
7962 V = MIRBuilder.buildAdd(S32, V, V1);
7964 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1,
7965 E, MIRBuilder.buildConstant(S32, 30));
7966 V = MIRBuilder.buildSelect(S32, CmpEGt30,
7967 MIRBuilder.buildConstant(S32, 0x7c00), V);
7969 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1,
7970 E, MIRBuilder.buildConstant(S32, 1039));
7971 V = MIRBuilder.buildSelect(S32, CmpEGt1039, I, V);
7973 // Extract the sign bit.
7974 auto Sign = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 16));
7975 Sign = MIRBuilder.buildAnd(S32, Sign, MIRBuilder.buildConstant(S32, 0x8000));
7977 // Insert the sign bit
7978 V = MIRBuilder.buildOr(S32, Sign, V);
7980 MIRBuilder.buildTrunc(Dst, V);
7981 MI.eraseFromParent();
7982 return Legalized;
7985 LegalizerHelper::LegalizeResult
7986 LegalizerHelper::lowerFPTRUNC(MachineInstr &MI) {
7987 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
7988 const LLT S64 = LLT::scalar(64);
7989 const LLT S16 = LLT::scalar(16);
7991 if (DstTy.getScalarType() == S16 && SrcTy.getScalarType() == S64)
7992 return lowerFPTRUNC_F64_TO_F16(MI);
7994 return UnableToLegalize;
7997 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFPOWI(MachineInstr &MI) {
7998 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
7999 LLT Ty = MRI.getType(Dst);
8001 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
8002 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
8003 MI.eraseFromParent();
8004 return Legalized;
8007 static CmpInst::Predicate minMaxToCompare(unsigned Opc) {
8008 switch (Opc) {
8009 case TargetOpcode::G_SMIN:
8010 return CmpInst::ICMP_SLT;
8011 case TargetOpcode::G_SMAX:
8012 return CmpInst::ICMP_SGT;
8013 case TargetOpcode::G_UMIN:
8014 return CmpInst::ICMP_ULT;
8015 case TargetOpcode::G_UMAX:
8016 return CmpInst::ICMP_UGT;
8017 default:
8018 llvm_unreachable("not in integer min/max");
8022 LegalizerHelper::LegalizeResult LegalizerHelper::lowerMinMax(MachineInstr &MI) {
8023 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
8025 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
8026 LLT CmpType = MRI.getType(Dst).changeElementSize(1);
8028 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
8029 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
8031 MI.eraseFromParent();
8032 return Legalized;
8035 LegalizerHelper::LegalizeResult
8036 LegalizerHelper::lowerThreewayCompare(MachineInstr &MI) {
8037 GSUCmp *Cmp = cast<GSUCmp>(&MI);
8039 Register Dst = Cmp->getReg(0);
8040 LLT DstTy = MRI.getType(Dst);
8041 LLT SrcTy = MRI.getType(Cmp->getReg(1));
8042 LLT CmpTy = DstTy.changeElementSize(1);
8044 CmpInst::Predicate LTPredicate = Cmp->isSigned()
8045 ? CmpInst::Predicate::ICMP_SLT
8046 : CmpInst::Predicate::ICMP_ULT;
8047 CmpInst::Predicate GTPredicate = Cmp->isSigned()
8048 ? CmpInst::Predicate::ICMP_SGT
8049 : CmpInst::Predicate::ICMP_UGT;
8051 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
8052 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
8053 Cmp->getRHSReg());
8054 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
8055 Cmp->getRHSReg());
8057 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
8058 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
8059 if (TLI.shouldExpandCmpUsingSelects(getApproximateEVTForLLT(SrcTy, Ctx)) ||
8060 BC == TargetLowering::UndefinedBooleanContent) {
8061 auto One = MIRBuilder.buildConstant(DstTy, 1);
8062 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
8064 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
8065 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
8066 } else {
8067 if (BC == TargetLowering::ZeroOrNegativeOneBooleanContent)
8068 std::swap(IsGT, IsLT);
8069 // Extend boolean results to DstTy, which is at least i2, before subtracting
8070 // them.
8071 unsigned BoolExtOp =
8072 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
8073 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
8074 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
8075 MIRBuilder.buildSub(Dst, IsGT, IsLT);
8078 MI.eraseFromParent();
8079 return Legalized;
8082 LegalizerHelper::LegalizeResult
8083 LegalizerHelper::lowerFCopySign(MachineInstr &MI) {
8084 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
8085 const int Src0Size = Src0Ty.getScalarSizeInBits();
8086 const int Src1Size = Src1Ty.getScalarSizeInBits();
8088 auto SignBitMask = MIRBuilder.buildConstant(
8089 Src0Ty, APInt::getSignMask(Src0Size));
8091 auto NotSignBitMask = MIRBuilder.buildConstant(
8092 Src0Ty, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
8094 Register And0 = MIRBuilder.buildAnd(Src0Ty, Src0, NotSignBitMask).getReg(0);
8095 Register And1;
8096 if (Src0Ty == Src1Ty) {
8097 And1 = MIRBuilder.buildAnd(Src1Ty, Src1, SignBitMask).getReg(0);
8098 } else if (Src0Size > Src1Size) {
8099 auto ShiftAmt = MIRBuilder.buildConstant(Src0Ty, Src0Size - Src1Size);
8100 auto Zext = MIRBuilder.buildZExt(Src0Ty, Src1);
8101 auto Shift = MIRBuilder.buildShl(Src0Ty, Zext, ShiftAmt);
8102 And1 = MIRBuilder.buildAnd(Src0Ty, Shift, SignBitMask).getReg(0);
8103 } else {
8104 auto ShiftAmt = MIRBuilder.buildConstant(Src1Ty, Src1Size - Src0Size);
8105 auto Shift = MIRBuilder.buildLShr(Src1Ty, Src1, ShiftAmt);
8106 auto Trunc = MIRBuilder.buildTrunc(Src0Ty, Shift);
8107 And1 = MIRBuilder.buildAnd(Src0Ty, Trunc, SignBitMask).getReg(0);
8110 // Be careful about setting nsz/nnan/ninf on every instruction, since the
8111 // constants are a nan and -0.0, but the final result should preserve
8112 // everything.
8113 unsigned Flags = MI.getFlags();
8115 // We masked the sign bit and the not-sign bit, so these are disjoint.
8116 Flags |= MachineInstr::Disjoint;
8118 MIRBuilder.buildOr(Dst, And0, And1, Flags);
8120 MI.eraseFromParent();
8121 return Legalized;
8124 LegalizerHelper::LegalizeResult
8125 LegalizerHelper::lowerFMinNumMaxNum(MachineInstr &MI) {
8126 unsigned NewOp = MI.getOpcode() == TargetOpcode::G_FMINNUM ?
8127 TargetOpcode::G_FMINNUM_IEEE : TargetOpcode::G_FMAXNUM_IEEE;
8129 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
8130 LLT Ty = MRI.getType(Dst);
8132 if (!MI.getFlag(MachineInstr::FmNoNans)) {
8133 // Insert canonicalizes if it's possible we need to quiet to get correct
8134 // sNaN behavior.
8136 // Note this must be done here, and not as an optimization combine in the
8137 // absence of a dedicate quiet-snan instruction as we're using an
8138 // omni-purpose G_FCANONICALIZE.
8139 if (!isKnownNeverSNaN(Src0, MRI))
8140 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
8142 if (!isKnownNeverSNaN(Src1, MRI))
8143 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
8146 // If there are no nans, it's safe to simply replace this with the non-IEEE
8147 // version.
8148 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
8149 MI.eraseFromParent();
8150 return Legalized;
8153 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFMad(MachineInstr &MI) {
8154 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
8155 Register DstReg = MI.getOperand(0).getReg();
8156 LLT Ty = MRI.getType(DstReg);
8157 unsigned Flags = MI.getFlags();
8159 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
8160 Flags);
8161 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
8162 MI.eraseFromParent();
8163 return Legalized;
8166 LegalizerHelper::LegalizeResult
8167 LegalizerHelper::lowerIntrinsicRound(MachineInstr &MI) {
8168 auto [DstReg, X] = MI.getFirst2Regs();
8169 const unsigned Flags = MI.getFlags();
8170 const LLT Ty = MRI.getType(DstReg);
8171 const LLT CondTy = Ty.changeElementSize(1);
8173 // round(x) =>
8174 // t = trunc(x);
8175 // d = fabs(x - t);
8176 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
8177 // return t + o;
8179 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
8181 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
8182 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
8184 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
8185 auto Cmp =
8186 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
8188 // Could emit G_UITOFP instead
8189 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
8190 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
8191 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
8192 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
8194 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
8196 MI.eraseFromParent();
8197 return Legalized;
8200 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFFloor(MachineInstr &MI) {
8201 auto [DstReg, SrcReg] = MI.getFirst2Regs();
8202 unsigned Flags = MI.getFlags();
8203 LLT Ty = MRI.getType(DstReg);
8204 const LLT CondTy = Ty.changeElementSize(1);
8206 // result = trunc(src);
8207 // if (src < 0.0 && src != result)
8208 // result += -1.0.
8210 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
8211 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
8213 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
8214 SrcReg, Zero, Flags);
8215 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
8216 SrcReg, Trunc, Flags);
8217 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
8218 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
8220 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
8221 MI.eraseFromParent();
8222 return Legalized;
8225 LegalizerHelper::LegalizeResult
8226 LegalizerHelper::lowerMergeValues(MachineInstr &MI) {
8227 const unsigned NumOps = MI.getNumOperands();
8228 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
8229 unsigned PartSize = Src0Ty.getSizeInBits();
8231 LLT WideTy = LLT::scalar(DstTy.getSizeInBits());
8232 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
8234 for (unsigned I = 2; I != NumOps; ++I) {
8235 const unsigned Offset = (I - 1) * PartSize;
8237 Register SrcReg = MI.getOperand(I).getReg();
8238 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
8240 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
8241 MRI.createGenericVirtualRegister(WideTy);
8243 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
8244 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
8245 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
8246 ResultReg = NextResult;
8249 if (DstTy.isPointer()) {
8250 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
8251 DstTy.getAddressSpace())) {
8252 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
8253 return UnableToLegalize;
8256 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
8259 MI.eraseFromParent();
8260 return Legalized;
8263 LegalizerHelper::LegalizeResult
8264 LegalizerHelper::lowerUnmergeValues(MachineInstr &MI) {
8265 const unsigned NumDst = MI.getNumOperands() - 1;
8266 Register SrcReg = MI.getOperand(NumDst).getReg();
8267 Register Dst0Reg = MI.getOperand(0).getReg();
8268 LLT DstTy = MRI.getType(Dst0Reg);
8269 if (DstTy.isPointer())
8270 return UnableToLegalize; // TODO
8272 SrcReg = coerceToScalar(SrcReg);
8273 if (!SrcReg)
8274 return UnableToLegalize;
8276 // Expand scalarizing unmerge as bitcast to integer and shift.
8277 LLT IntTy = MRI.getType(SrcReg);
8279 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
8281 const unsigned DstSize = DstTy.getSizeInBits();
8282 unsigned Offset = DstSize;
8283 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
8284 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
8285 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
8286 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
8289 MI.eraseFromParent();
8290 return Legalized;
8293 /// Lower a vector extract or insert by writing the vector to a stack temporary
8294 /// and reloading the element or vector.
8296 /// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
8297 /// =>
8298 /// %stack_temp = G_FRAME_INDEX
8299 /// G_STORE %vec, %stack_temp
8300 /// %idx = clamp(%idx, %vec.getNumElements())
8301 /// %element_ptr = G_PTR_ADD %stack_temp, %idx
8302 /// %dst = G_LOAD %element_ptr
8303 LegalizerHelper::LegalizeResult
8304 LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr &MI) {
8305 Register DstReg = MI.getOperand(0).getReg();
8306 Register SrcVec = MI.getOperand(1).getReg();
8307 Register InsertVal;
8308 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
8309 InsertVal = MI.getOperand(2).getReg();
8311 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
8313 LLT VecTy = MRI.getType(SrcVec);
8314 LLT EltTy = VecTy.getElementType();
8315 unsigned NumElts = VecTy.getNumElements();
8317 int64_t IdxVal;
8318 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
8319 SmallVector<Register, 8> SrcRegs;
8320 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
8322 if (InsertVal) {
8323 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
8324 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
8325 } else {
8326 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
8329 MI.eraseFromParent();
8330 return Legalized;
8333 if (!EltTy.isByteSized()) { // Not implemented.
8334 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
8335 return UnableToLegalize;
8338 unsigned EltBytes = EltTy.getSizeInBytes();
8339 Align VecAlign = getStackTemporaryAlignment(VecTy);
8340 Align EltAlign;
8342 MachinePointerInfo PtrInfo;
8343 auto StackTemp = createStackTemporary(
8344 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
8345 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
8347 // Get the pointer to the element, and be sure not to hit undefined behavior
8348 // if the index is out of bounds.
8349 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
8351 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
8352 int64_t Offset = IdxVal * EltBytes;
8353 PtrInfo = PtrInfo.getWithOffset(Offset);
8354 EltAlign = commonAlignment(VecAlign, Offset);
8355 } else {
8356 // We lose information with a variable offset.
8357 EltAlign = getStackTemporaryAlignment(EltTy);
8358 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
8361 if (InsertVal) {
8362 // Write the inserted element
8363 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
8365 // Reload the whole vector.
8366 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
8367 } else {
8368 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
8371 MI.eraseFromParent();
8372 return Legalized;
8375 LegalizerHelper::LegalizeResult
8376 LegalizerHelper::lowerShuffleVector(MachineInstr &MI) {
8377 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
8378 MI.getFirst3RegLLTs();
8379 LLT IdxTy = LLT::scalar(32);
8381 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
8382 Register Undef;
8383 SmallVector<Register, 32> BuildVec;
8384 LLT EltTy = DstTy.getScalarType();
8386 for (int Idx : Mask) {
8387 if (Idx < 0) {
8388 if (!Undef.isValid())
8389 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
8390 BuildVec.push_back(Undef);
8391 continue;
8394 if (Src0Ty.isScalar()) {
8395 BuildVec.push_back(Idx == 0 ? Src0Reg : Src1Reg);
8396 } else {
8397 int NumElts = Src0Ty.getNumElements();
8398 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
8399 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
8400 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
8401 auto Extract = MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK);
8402 BuildVec.push_back(Extract.getReg(0));
8406 if (DstTy.isScalar())
8407 MIRBuilder.buildCopy(DstReg, BuildVec[0]);
8408 else
8409 MIRBuilder.buildBuildVector(DstReg, BuildVec);
8410 MI.eraseFromParent();
8411 return Legalized;
8414 LegalizerHelper::LegalizeResult
8415 LegalizerHelper::lowerVECTOR_COMPRESS(llvm::MachineInstr &MI) {
8416 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
8417 MI.getFirst4RegLLTs();
8419 if (VecTy.isScalableVector())
8420 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
8422 Align VecAlign = getStackTemporaryAlignment(VecTy);
8423 MachinePointerInfo PtrInfo;
8424 Register StackPtr =
8425 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
8426 PtrInfo)
8427 .getReg(0);
8428 MachinePointerInfo ValPtrInfo =
8429 MachinePointerInfo::getUnknownStack(*MI.getMF());
8431 LLT IdxTy = LLT::scalar(32);
8432 LLT ValTy = VecTy.getElementType();
8433 Align ValAlign = getStackTemporaryAlignment(ValTy);
8435 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
8437 bool HasPassthru =
8438 MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;
8440 if (HasPassthru)
8441 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
8443 Register LastWriteVal;
8444 std::optional<APInt> PassthruSplatVal =
8445 isConstantOrConstantSplatVector(*MRI.getVRegDef(Passthru), MRI);
8447 if (PassthruSplatVal.has_value()) {
8448 LastWriteVal =
8449 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
8450 } else if (HasPassthru) {
8451 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
8452 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
8453 {LLT::scalar(32)}, {Popcount});
8455 Register LastElmtPtr =
8456 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
8457 LastWriteVal =
8458 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
8459 .getReg(0);
8462 unsigned NumElmts = VecTy.getNumElements();
8463 for (unsigned I = 0; I < NumElmts; ++I) {
8464 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
8465 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
8466 Register ElmtPtr =
8467 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
8468 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
8470 LLT MaskITy = MaskTy.getElementType();
8471 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
8472 if (MaskITy.getSizeInBits() > 1)
8473 MaskI = MIRBuilder.buildTrunc(LLT::scalar(1), MaskI);
8475 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
8476 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
8478 if (HasPassthru && I == NumElmts - 1) {
8479 auto EndOfVector =
8480 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
8481 auto AllLanesSelected = MIRBuilder.buildICmp(
8482 CmpInst::ICMP_UGT, LLT::scalar(1), OutPos, EndOfVector);
8483 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
8484 {OutPos, EndOfVector});
8485 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
8487 LastWriteVal =
8488 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
8489 .getReg(0);
8490 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
8494 // TODO: Use StackPtr's FrameIndex alignment.
8495 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
8497 MI.eraseFromParent();
8498 return Legalized;
8501 Register LegalizerHelper::getDynStackAllocTargetPtr(Register SPReg,
8502 Register AllocSize,
8503 Align Alignment,
8504 LLT PtrTy) {
8505 LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits());
8507 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
8508 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
8510 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
8511 // have to generate an extra instruction to negate the alloc and then use
8512 // G_PTR_ADD to add the negative offset.
8513 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
8514 if (Alignment > Align(1)) {
8515 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
8516 AlignMask.negate();
8517 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
8518 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
8521 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
8524 LegalizerHelper::LegalizeResult
8525 LegalizerHelper::lowerDynStackAlloc(MachineInstr &MI) {
8526 const auto &MF = *MI.getMF();
8527 const auto &TFI = *MF.getSubtarget().getFrameLowering();
8528 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
8529 return UnableToLegalize;
8531 Register Dst = MI.getOperand(0).getReg();
8532 Register AllocSize = MI.getOperand(1).getReg();
8533 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
8535 LLT PtrTy = MRI.getType(Dst);
8536 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
8537 Register SPTmp =
8538 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
8540 MIRBuilder.buildCopy(SPReg, SPTmp);
8541 MIRBuilder.buildCopy(Dst, SPTmp);
8543 MI.eraseFromParent();
8544 return Legalized;
8547 LegalizerHelper::LegalizeResult
8548 LegalizerHelper::lowerStackSave(MachineInstr &MI) {
8549 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
8550 if (!StackPtr)
8551 return UnableToLegalize;
8553 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
8554 MI.eraseFromParent();
8555 return Legalized;
8558 LegalizerHelper::LegalizeResult
8559 LegalizerHelper::lowerStackRestore(MachineInstr &MI) {
8560 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
8561 if (!StackPtr)
8562 return UnableToLegalize;
8564 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
8565 MI.eraseFromParent();
8566 return Legalized;
8569 LegalizerHelper::LegalizeResult
8570 LegalizerHelper::lowerExtract(MachineInstr &MI) {
8571 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8572 unsigned Offset = MI.getOperand(2).getImm();
8574 // Extract sub-vector or one element
8575 if (SrcTy.isVector()) {
8576 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
8577 unsigned DstSize = DstTy.getSizeInBits();
8579 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
8580 (Offset + DstSize <= SrcTy.getSizeInBits())) {
8581 // Unmerge and allow access to each Src element for the artifact combiner.
8582 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
8584 // Take element(s) we need to extract and copy it (merge them).
8585 SmallVector<Register, 8> SubVectorElts;
8586 for (unsigned Idx = Offset / SrcEltSize;
8587 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
8588 SubVectorElts.push_back(Unmerge.getReg(Idx));
8590 if (SubVectorElts.size() == 1)
8591 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
8592 else
8593 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
8595 MI.eraseFromParent();
8596 return Legalized;
8600 if (DstTy.isScalar() &&
8601 (SrcTy.isScalar() ||
8602 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
8603 LLT SrcIntTy = SrcTy;
8604 if (!SrcTy.isScalar()) {
8605 SrcIntTy = LLT::scalar(SrcTy.getSizeInBits());
8606 SrcReg = MIRBuilder.buildBitcast(SrcIntTy, SrcReg).getReg(0);
8609 if (Offset == 0)
8610 MIRBuilder.buildTrunc(DstReg, SrcReg);
8611 else {
8612 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
8613 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
8614 MIRBuilder.buildTrunc(DstReg, Shr);
8617 MI.eraseFromParent();
8618 return Legalized;
8621 return UnableToLegalize;
8624 LegalizerHelper::LegalizeResult LegalizerHelper::lowerInsert(MachineInstr &MI) {
8625 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
8626 uint64_t Offset = MI.getOperand(3).getImm();
8628 LLT DstTy = MRI.getType(Src);
8629 LLT InsertTy = MRI.getType(InsertSrc);
8631 // Insert sub-vector or one element
8632 if (DstTy.isVector() && !InsertTy.isPointer()) {
8633 LLT EltTy = DstTy.getElementType();
8634 unsigned EltSize = EltTy.getSizeInBits();
8635 unsigned InsertSize = InsertTy.getSizeInBits();
8637 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
8638 (Offset + InsertSize <= DstTy.getSizeInBits())) {
8639 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
8640 SmallVector<Register, 8> DstElts;
8641 unsigned Idx = 0;
8642 // Elements from Src before insert start Offset
8643 for (; Idx < Offset / EltSize; ++Idx) {
8644 DstElts.push_back(UnmergeSrc.getReg(Idx));
8647 // Replace elements in Src with elements from InsertSrc
8648 if (InsertTy.getSizeInBits() > EltSize) {
8649 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
8650 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
8651 ++Idx, ++i) {
8652 DstElts.push_back(UnmergeInsertSrc.getReg(i));
8654 } else {
8655 DstElts.push_back(InsertSrc);
8656 ++Idx;
8659 // Remaining elements from Src after insert
8660 for (; Idx < DstTy.getNumElements(); ++Idx) {
8661 DstElts.push_back(UnmergeSrc.getReg(Idx));
8664 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
8665 MI.eraseFromParent();
8666 return Legalized;
8670 if (InsertTy.isVector() ||
8671 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
8672 return UnableToLegalize;
8674 const DataLayout &DL = MIRBuilder.getDataLayout();
8675 if ((DstTy.isPointer() &&
8676 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace())) ||
8677 (InsertTy.isPointer() &&
8678 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace()))) {
8679 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
8680 return UnableToLegalize;
8683 LLT IntDstTy = DstTy;
8685 if (!DstTy.isScalar()) {
8686 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
8687 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
8690 if (!InsertTy.isScalar()) {
8691 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
8692 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
8695 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
8696 if (Offset != 0) {
8697 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
8698 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
8701 APInt MaskVal = APInt::getBitsSetWithWrap(
8702 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
8704 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
8705 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
8706 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
8708 MIRBuilder.buildCast(Dst, Or);
8709 MI.eraseFromParent();
8710 return Legalized;
8713 LegalizerHelper::LegalizeResult
8714 LegalizerHelper::lowerSADDO_SSUBO(MachineInstr &MI) {
8715 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
8716 MI.getFirst4RegLLTs();
8717 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
8719 LLT Ty = Dst0Ty;
8720 LLT BoolTy = Dst1Ty;
8722 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
8724 if (IsAdd)
8725 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
8726 else
8727 MIRBuilder.buildSub(NewDst0, LHS, RHS);
8729 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
8731 auto Zero = MIRBuilder.buildConstant(Ty, 0);
8733 // For an addition, the result should be less than one of the operands (LHS)
8734 // if and only if the other operand (RHS) is negative, otherwise there will
8735 // be overflow.
8736 // For a subtraction, the result should be less than one of the operands
8737 // (LHS) if and only if the other operand (RHS) is (non-zero) positive,
8738 // otherwise there will be overflow.
8739 auto ResultLowerThanLHS =
8740 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
8741 auto ConditionRHS = MIRBuilder.buildICmp(
8742 IsAdd ? CmpInst::ICMP_SLT : CmpInst::ICMP_SGT, BoolTy, RHS, Zero);
8744 MIRBuilder.buildXor(Dst1, ConditionRHS, ResultLowerThanLHS);
8746 MIRBuilder.buildCopy(Dst0, NewDst0);
8747 MI.eraseFromParent();
8749 return Legalized;
8752 LegalizerHelper::LegalizeResult
8753 LegalizerHelper::lowerAddSubSatToMinMax(MachineInstr &MI) {
8754 auto [Res, LHS, RHS] = MI.getFirst3Regs();
8755 LLT Ty = MRI.getType(Res);
8756 bool IsSigned;
8757 bool IsAdd;
8758 unsigned BaseOp;
8759 switch (MI.getOpcode()) {
8760 default:
8761 llvm_unreachable("unexpected addsat/subsat opcode");
8762 case TargetOpcode::G_UADDSAT:
8763 IsSigned = false;
8764 IsAdd = true;
8765 BaseOp = TargetOpcode::G_ADD;
8766 break;
8767 case TargetOpcode::G_SADDSAT:
8768 IsSigned = true;
8769 IsAdd = true;
8770 BaseOp = TargetOpcode::G_ADD;
8771 break;
8772 case TargetOpcode::G_USUBSAT:
8773 IsSigned = false;
8774 IsAdd = false;
8775 BaseOp = TargetOpcode::G_SUB;
8776 break;
8777 case TargetOpcode::G_SSUBSAT:
8778 IsSigned = true;
8779 IsAdd = false;
8780 BaseOp = TargetOpcode::G_SUB;
8781 break;
8784 if (IsSigned) {
8785 // sadd.sat(a, b) ->
8786 // hi = 0x7fffffff - smax(a, 0)
8787 // lo = 0x80000000 - smin(a, 0)
8788 // a + smin(smax(lo, b), hi)
8789 // ssub.sat(a, b) ->
8790 // lo = smax(a, -1) - 0x7fffffff
8791 // hi = smin(a, -1) - 0x80000000
8792 // a - smin(smax(lo, b), hi)
8793 // TODO: AMDGPU can use a "median of 3" instruction here:
8794 // a +/- med3(lo, b, hi)
8795 uint64_t NumBits = Ty.getScalarSizeInBits();
8796 auto MaxVal =
8797 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
8798 auto MinVal =
8799 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
8800 MachineInstrBuilder Hi, Lo;
8801 if (IsAdd) {
8802 auto Zero = MIRBuilder.buildConstant(Ty, 0);
8803 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
8804 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
8805 } else {
8806 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
8807 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
8808 MaxVal);
8809 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
8810 MinVal);
8812 auto RHSClamped =
8813 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
8814 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
8815 } else {
8816 // uadd.sat(a, b) -> a + umin(~a, b)
8817 // usub.sat(a, b) -> a - umin(a, b)
8818 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
8819 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
8820 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
8823 MI.eraseFromParent();
8824 return Legalized;
8827 LegalizerHelper::LegalizeResult
8828 LegalizerHelper::lowerAddSubSatToAddoSubo(MachineInstr &MI) {
8829 auto [Res, LHS, RHS] = MI.getFirst3Regs();
8830 LLT Ty = MRI.getType(Res);
8831 LLT BoolTy = Ty.changeElementSize(1);
8832 bool IsSigned;
8833 bool IsAdd;
8834 unsigned OverflowOp;
8835 switch (MI.getOpcode()) {
8836 default:
8837 llvm_unreachable("unexpected addsat/subsat opcode");
8838 case TargetOpcode::G_UADDSAT:
8839 IsSigned = false;
8840 IsAdd = true;
8841 OverflowOp = TargetOpcode::G_UADDO;
8842 break;
8843 case TargetOpcode::G_SADDSAT:
8844 IsSigned = true;
8845 IsAdd = true;
8846 OverflowOp = TargetOpcode::G_SADDO;
8847 break;
8848 case TargetOpcode::G_USUBSAT:
8849 IsSigned = false;
8850 IsAdd = false;
8851 OverflowOp = TargetOpcode::G_USUBO;
8852 break;
8853 case TargetOpcode::G_SSUBSAT:
8854 IsSigned = true;
8855 IsAdd = false;
8856 OverflowOp = TargetOpcode::G_SSUBO;
8857 break;
8860 auto OverflowRes =
8861 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
8862 Register Tmp = OverflowRes.getReg(0);
8863 Register Ov = OverflowRes.getReg(1);
8864 MachineInstrBuilder Clamp;
8865 if (IsSigned) {
8866 // sadd.sat(a, b) ->
8867 // {tmp, ov} = saddo(a, b)
8868 // ov ? (tmp >>s 31) + 0x80000000 : r
8869 // ssub.sat(a, b) ->
8870 // {tmp, ov} = ssubo(a, b)
8871 // ov ? (tmp >>s 31) + 0x80000000 : r
8872 uint64_t NumBits = Ty.getScalarSizeInBits();
8873 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
8874 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
8875 auto MinVal =
8876 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
8877 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
8878 } else {
8879 // uadd.sat(a, b) ->
8880 // {tmp, ov} = uaddo(a, b)
8881 // ov ? 0xffffffff : tmp
8882 // usub.sat(a, b) ->
8883 // {tmp, ov} = usubo(a, b)
8884 // ov ? 0 : tmp
8885 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
8887 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
8889 MI.eraseFromParent();
8890 return Legalized;
8893 LegalizerHelper::LegalizeResult
8894 LegalizerHelper::lowerShlSat(MachineInstr &MI) {
8895 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
8896 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
8897 "Expected shlsat opcode!");
8898 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
8899 auto [Res, LHS, RHS] = MI.getFirst3Regs();
8900 LLT Ty = MRI.getType(Res);
8901 LLT BoolTy = Ty.changeElementSize(1);
8903 unsigned BW = Ty.getScalarSizeInBits();
8904 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
8905 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
8906 : MIRBuilder.buildLShr(Ty, Result, RHS);
8908 MachineInstrBuilder SatVal;
8909 if (IsSigned) {
8910 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
8911 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
8912 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
8913 MIRBuilder.buildConstant(Ty, 0));
8914 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
8915 } else {
8916 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
8918 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
8919 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
8921 MI.eraseFromParent();
8922 return Legalized;
8925 LegalizerHelper::LegalizeResult LegalizerHelper::lowerBswap(MachineInstr &MI) {
8926 auto [Dst, Src] = MI.getFirst2Regs();
8927 const LLT Ty = MRI.getType(Src);
8928 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
8929 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
8931 // Swap most and least significant byte, set remaining bytes in Res to zero.
8932 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
8933 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
8934 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
8935 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
8937 // Set i-th high/low byte in Res to i-th low/high byte from Src.
8938 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
8939 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
8940 APInt APMask(SizeInBytes * 8, 0xFF << (i * 8));
8941 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
8942 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
8943 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
8944 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
8945 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
8946 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
8947 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
8948 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
8949 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
8950 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
8952 Res.getInstr()->getOperand(0).setReg(Dst);
8954 MI.eraseFromParent();
8955 return Legalized;
8958 //{ (Src & Mask) >> N } | { (Src << N) & Mask }
8959 static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B,
8960 MachineInstrBuilder Src, const APInt &Mask) {
8961 const LLT Ty = Dst.getLLTTy(*B.getMRI());
8962 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
8963 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
8964 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
8965 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
8966 return B.buildOr(Dst, LHS, RHS);
8969 LegalizerHelper::LegalizeResult
8970 LegalizerHelper::lowerBitreverse(MachineInstr &MI) {
8971 auto [Dst, Src] = MI.getFirst2Regs();
8972 const LLT Ty = MRI.getType(Src);
8973 unsigned Size = Ty.getScalarSizeInBits();
8975 if (Size >= 8) {
8976 MachineInstrBuilder BSWAP =
8977 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {Ty}, {Src});
8979 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
8980 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
8981 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
8982 MachineInstrBuilder Swap4 =
8983 SwapN(4, Ty, MIRBuilder, BSWAP, APInt::getSplat(Size, APInt(8, 0xF0)));
8985 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
8986 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
8987 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
8988 MachineInstrBuilder Swap2 =
8989 SwapN(2, Ty, MIRBuilder, Swap4, APInt::getSplat(Size, APInt(8, 0xCC)));
8991 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
8992 // 6|7
8993 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
8994 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
8995 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
8996 } else {
8997 // Expand bitreverse for types smaller than 8 bits.
8998 MachineInstrBuilder Tmp;
8999 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
9000 MachineInstrBuilder Tmp2;
9001 if (I < J) {
9002 auto ShAmt = MIRBuilder.buildConstant(Ty, J - I);
9003 Tmp2 = MIRBuilder.buildShl(Ty, Src, ShAmt);
9004 } else {
9005 auto ShAmt = MIRBuilder.buildConstant(Ty, I - J);
9006 Tmp2 = MIRBuilder.buildLShr(Ty, Src, ShAmt);
9009 auto Mask = MIRBuilder.buildConstant(Ty, 1ULL << J);
9010 Tmp2 = MIRBuilder.buildAnd(Ty, Tmp2, Mask);
9011 if (I == 0)
9012 Tmp = Tmp2;
9013 else
9014 Tmp = MIRBuilder.buildOr(Ty, Tmp, Tmp2);
9016 MIRBuilder.buildCopy(Dst, Tmp);
9019 MI.eraseFromParent();
9020 return Legalized;
9023 LegalizerHelper::LegalizeResult
9024 LegalizerHelper::lowerReadWriteRegister(MachineInstr &MI) {
9025 MachineFunction &MF = MIRBuilder.getMF();
9027 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
9028 int NameOpIdx = IsRead ? 1 : 0;
9029 int ValRegIndex = IsRead ? 0 : 1;
9031 Register ValReg = MI.getOperand(ValRegIndex).getReg();
9032 const LLT Ty = MRI.getType(ValReg);
9033 const MDString *RegStr = cast<MDString>(
9034 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
9036 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
9037 if (!PhysReg.isValid())
9038 return UnableToLegalize;
9040 if (IsRead)
9041 MIRBuilder.buildCopy(ValReg, PhysReg);
9042 else
9043 MIRBuilder.buildCopy(PhysReg, ValReg);
9045 MI.eraseFromParent();
9046 return Legalized;
9049 LegalizerHelper::LegalizeResult
9050 LegalizerHelper::lowerSMULH_UMULH(MachineInstr &MI) {
9051 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
9052 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
9053 Register Result = MI.getOperand(0).getReg();
9054 LLT OrigTy = MRI.getType(Result);
9055 auto SizeInBits = OrigTy.getScalarSizeInBits();
9056 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
9058 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
9059 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
9060 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
9061 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
9063 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
9064 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
9065 MIRBuilder.buildTrunc(Result, Shifted);
9067 MI.eraseFromParent();
9068 return Legalized;
9071 LegalizerHelper::LegalizeResult
9072 LegalizerHelper::lowerISFPCLASS(MachineInstr &MI) {
9073 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9074 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
9076 if (Mask == fcNone) {
9077 MIRBuilder.buildConstant(DstReg, 0);
9078 MI.eraseFromParent();
9079 return Legalized;
9081 if (Mask == fcAllFlags) {
9082 MIRBuilder.buildConstant(DstReg, 1);
9083 MI.eraseFromParent();
9084 return Legalized;
9087 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
9088 // version
9090 unsigned BitSize = SrcTy.getScalarSizeInBits();
9091 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
9093 LLT IntTy = LLT::scalar(BitSize);
9094 if (SrcTy.isVector())
9095 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
9096 auto AsInt = MIRBuilder.buildCopy(IntTy, SrcReg);
9098 // Various masks.
9099 APInt SignBit = APInt::getSignMask(BitSize);
9100 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
9101 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
9102 APInt ExpMask = Inf;
9103 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
9104 APInt QNaNBitMask =
9105 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
9106 APInt InvertionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
9108 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
9109 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
9110 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
9111 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
9112 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
9114 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
9115 auto Sign =
9116 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
9118 auto Res = MIRBuilder.buildConstant(DstTy, 0);
9119 // Clang doesn't support capture of structured bindings:
9120 LLT DstTyCopy = DstTy;
9121 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
9122 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
9125 // Tests that involve more than one class should be processed first.
9126 if ((Mask & fcFinite) == fcFinite) {
9127 // finite(V) ==> abs(V) u< exp_mask
9128 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
9129 ExpMaskC));
9130 Mask &= ~fcFinite;
9131 } else if ((Mask & fcFinite) == fcPosFinite) {
9132 // finite(V) && V > 0 ==> V u< exp_mask
9133 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
9134 ExpMaskC));
9135 Mask &= ~fcPosFinite;
9136 } else if ((Mask & fcFinite) == fcNegFinite) {
9137 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
9138 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
9139 ExpMaskC);
9140 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
9141 appendToRes(And);
9142 Mask &= ~fcNegFinite;
9145 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
9146 // fcZero | fcSubnormal => test all exponent bits are 0
9147 // TODO: Handle sign bit specific cases
9148 // TODO: Handle inverted case
9149 if (PartialCheck == (fcZero | fcSubnormal)) {
9150 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
9151 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
9152 ExpBits, ZeroC));
9153 Mask &= ~PartialCheck;
9157 // Check for individual classes.
9158 if (FPClassTest PartialCheck = Mask & fcZero) {
9159 if (PartialCheck == fcPosZero)
9160 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
9161 AsInt, ZeroC));
9162 else if (PartialCheck == fcZero)
9163 appendToRes(
9164 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
9165 else // fcNegZero
9166 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
9167 AsInt, SignBitC));
9170 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
9171 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
9172 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
9173 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
9174 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
9175 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
9176 auto SubnormalRes =
9177 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
9178 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
9179 if (PartialCheck == fcNegSubnormal)
9180 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
9181 appendToRes(SubnormalRes);
9184 if (FPClassTest PartialCheck = Mask & fcInf) {
9185 if (PartialCheck == fcPosInf)
9186 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
9187 AsInt, InfC));
9188 else if (PartialCheck == fcInf)
9189 appendToRes(
9190 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
9191 else { // fcNegInf
9192 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
9193 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
9194 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
9195 AsInt, NegInfC));
9199 if (FPClassTest PartialCheck = Mask & fcNan) {
9200 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
9201 if (PartialCheck == fcNan) {
9202 // isnan(V) ==> abs(V) u> int(inf)
9203 appendToRes(
9204 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
9205 } else if (PartialCheck == fcQNan) {
9206 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
9207 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
9208 InfWithQnanBitC));
9209 } else { // fcSNan
9210 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
9211 // abs(V) u< (unsigned(Inf) | quiet_bit)
9212 auto IsNan =
9213 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
9214 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
9215 Abs, InfWithQnanBitC);
9216 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
9220 if (FPClassTest PartialCheck = Mask & fcNormal) {
9221 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
9222 // (max_exp-1))
9223 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
9224 auto ExpMinusOne = MIRBuilder.buildSub(
9225 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
9226 APInt MaxExpMinusOne = ExpMask - ExpLSB;
9227 auto NormalRes =
9228 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
9229 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
9230 if (PartialCheck == fcNegNormal)
9231 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
9232 else if (PartialCheck == fcPosNormal) {
9233 auto PosSign = MIRBuilder.buildXor(
9234 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InvertionMask));
9235 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
9237 appendToRes(NormalRes);
9240 MIRBuilder.buildCopy(DstReg, Res);
9241 MI.eraseFromParent();
9242 return Legalized;
9245 LegalizerHelper::LegalizeResult LegalizerHelper::lowerSelect(MachineInstr &MI) {
9246 // Implement G_SELECT in terms of XOR, AND, OR.
9247 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
9248 MI.getFirst4RegLLTs();
9250 bool IsEltPtr = DstTy.isPointerOrPointerVector();
9251 if (IsEltPtr) {
9252 LLT ScalarPtrTy = LLT::scalar(DstTy.getScalarSizeInBits());
9253 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
9254 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
9255 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
9256 DstTy = NewTy;
9259 if (MaskTy.isScalar()) {
9260 // Turn the scalar condition into a vector condition mask if needed.
9262 Register MaskElt = MaskReg;
9264 // The condition was potentially zero extended before, but we want a sign
9265 // extended boolean.
9266 if (MaskTy != LLT::scalar(1))
9267 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
9269 // Continue the sign extension (or truncate) to match the data type.
9270 MaskElt =
9271 MIRBuilder.buildSExtOrTrunc(DstTy.getScalarType(), MaskElt).getReg(0);
9273 if (DstTy.isVector()) {
9274 // Generate a vector splat idiom.
9275 auto ShufSplat = MIRBuilder.buildShuffleSplat(DstTy, MaskElt);
9276 MaskReg = ShufSplat.getReg(0);
9277 } else {
9278 MaskReg = MaskElt;
9280 MaskTy = DstTy;
9281 } else if (!DstTy.isVector()) {
9282 // Cannot handle the case that mask is a vector and dst is a scalar.
9283 return UnableToLegalize;
9286 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
9287 return UnableToLegalize;
9290 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
9291 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
9292 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
9293 if (IsEltPtr) {
9294 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
9295 MIRBuilder.buildIntToPtr(DstReg, Or);
9296 } else {
9297 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
9299 MI.eraseFromParent();
9300 return Legalized;
9303 LegalizerHelper::LegalizeResult LegalizerHelper::lowerDIVREM(MachineInstr &MI) {
9304 // Split DIVREM into individual instructions.
9305 unsigned Opcode = MI.getOpcode();
9307 MIRBuilder.buildInstr(
9308 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
9309 : TargetOpcode::G_UDIV,
9310 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
9311 MIRBuilder.buildInstr(
9312 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
9313 : TargetOpcode::G_UREM,
9314 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
9315 MI.eraseFromParent();
9316 return Legalized;
9319 LegalizerHelper::LegalizeResult
9320 LegalizerHelper::lowerAbsToAddXor(MachineInstr &MI) {
9321 // Expand %res = G_ABS %a into:
9322 // %v1 = G_ASHR %a, scalar_size-1
9323 // %v2 = G_ADD %a, %v1
9324 // %res = G_XOR %v2, %v1
9325 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
9326 Register OpReg = MI.getOperand(1).getReg();
9327 auto ShiftAmt =
9328 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
9329 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
9330 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
9331 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
9332 MI.eraseFromParent();
9333 return Legalized;
9336 LegalizerHelper::LegalizeResult
9337 LegalizerHelper::lowerAbsToMaxNeg(MachineInstr &MI) {
9338 // Expand %res = G_ABS %a into:
9339 // %v1 = G_CONSTANT 0
9340 // %v2 = G_SUB %v1, %a
9341 // %res = G_SMAX %a, %v2
9342 Register SrcReg = MI.getOperand(1).getReg();
9343 LLT Ty = MRI.getType(SrcReg);
9344 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9345 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
9346 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
9347 MI.eraseFromParent();
9348 return Legalized;
9351 LegalizerHelper::LegalizeResult
9352 LegalizerHelper::lowerAbsToCNeg(MachineInstr &MI) {
9353 Register SrcReg = MI.getOperand(1).getReg();
9354 Register DestReg = MI.getOperand(0).getReg();
9355 LLT Ty = MRI.getType(SrcReg), IType = LLT::scalar(1);
9356 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
9357 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
9358 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
9359 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
9360 MI.eraseFromParent();
9361 return Legalized;
9364 LegalizerHelper::LegalizeResult LegalizerHelper::lowerFAbs(MachineInstr &MI) {
9365 Register SrcReg = MI.getOperand(1).getReg();
9366 Register DstReg = MI.getOperand(0).getReg();
9368 LLT Ty = MRI.getType(DstReg);
9370 // Reset sign bit
9371 MIRBuilder.buildAnd(
9372 DstReg, SrcReg,
9373 MIRBuilder.buildConstant(
9374 Ty, APInt::getSignedMaxValue(Ty.getScalarSizeInBits())));
9376 MI.eraseFromParent();
9377 return Legalized;
9380 LegalizerHelper::LegalizeResult
9381 LegalizerHelper::lowerVectorReduction(MachineInstr &MI) {
9382 Register SrcReg = MI.getOperand(1).getReg();
9383 LLT SrcTy = MRI.getType(SrcReg);
9384 LLT DstTy = MRI.getType(SrcReg);
9386 // The source could be a scalar if the IR type was <1 x sN>.
9387 if (SrcTy.isScalar()) {
9388 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
9389 return UnableToLegalize; // FIXME: handle extension.
9390 // This can be just a plain copy.
9391 Observer.changingInstr(MI);
9392 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
9393 Observer.changedInstr(MI);
9394 return Legalized;
9396 return UnableToLegalize;
9399 LegalizerHelper::LegalizeResult LegalizerHelper::lowerVAArg(MachineInstr &MI) {
9400 MachineFunction &MF = *MI.getMF();
9401 const DataLayout &DL = MIRBuilder.getDataLayout();
9402 LLVMContext &Ctx = MF.getFunction().getContext();
9403 Register ListPtr = MI.getOperand(1).getReg();
9404 LLT PtrTy = MRI.getType(ListPtr);
9406 // LstPtr is a pointer to the head of the list. Get the address
9407 // of the head of the list.
9408 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
9409 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
9410 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
9411 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
9413 const Align A(MI.getOperand(2).getImm());
9414 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
9415 if (A > TLI.getMinStackArgumentAlignment()) {
9416 Register AlignAmt =
9417 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
9418 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
9419 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
9420 VAList = AndDst.getReg(0);
9423 // Increment the pointer, VAList, to the next vaarg
9424 // The list should be bumped by the size of element in the current head of
9425 // list.
9426 Register Dst = MI.getOperand(0).getReg();
9427 LLT LLTTy = MRI.getType(Dst);
9428 Type *Ty = getTypeForLLT(LLTTy, Ctx);
9429 auto IncAmt =
9430 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
9431 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
9433 // Store the increment VAList to the legalized pointer
9434 MachineMemOperand *StoreMMO = MF.getMachineMemOperand(
9435 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
9436 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
9437 // Load the actual argument out of the pointer VAList
9438 Align EltAlignment = DL.getABITypeAlign(Ty);
9439 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
9440 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
9441 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
9443 MI.eraseFromParent();
9444 return Legalized;
9447 static bool shouldLowerMemFuncForSize(const MachineFunction &MF) {
9448 // On Darwin, -Os means optimize for size without hurting performance, so
9449 // only really optimize for size when -Oz (MinSize) is used.
9450 if (MF.getTarget().getTargetTriple().isOSDarwin())
9451 return MF.getFunction().hasMinSize();
9452 return MF.getFunction().hasOptSize();
9455 // Returns a list of types to use for memory op lowering in MemOps. A partial
9456 // port of findOptimalMemOpLowering in TargetLowering.
9457 static bool findGISelOptimalMemOpLowering(std::vector<LLT> &MemOps,
9458 unsigned Limit, const MemOp &Op,
9459 unsigned DstAS, unsigned SrcAS,
9460 const AttributeList &FuncAttributes,
9461 const TargetLowering &TLI) {
9462 if (Op.isMemcpyWithFixedDstAlign() && Op.getSrcAlign() < Op.getDstAlign())
9463 return false;
9465 LLT Ty = TLI.getOptimalMemOpLLT(Op, FuncAttributes);
9467 if (Ty == LLT()) {
9468 // Use the largest scalar type whose alignment constraints are satisfied.
9469 // We only need to check DstAlign here as SrcAlign is always greater or
9470 // equal to DstAlign (or zero).
9471 Ty = LLT::scalar(64);
9472 if (Op.isFixedDstAlign())
9473 while (Op.getDstAlign() < Ty.getSizeInBytes() &&
9474 !TLI.allowsMisalignedMemoryAccesses(Ty, DstAS, Op.getDstAlign()))
9475 Ty = LLT::scalar(Ty.getSizeInBytes());
9476 assert(Ty.getSizeInBits() > 0 && "Could not find valid type");
9477 // FIXME: check for the largest legal type we can load/store to.
9480 unsigned NumMemOps = 0;
9481 uint64_t Size = Op.size();
9482 while (Size) {
9483 unsigned TySize = Ty.getSizeInBytes();
9484 while (TySize > Size) {
9485 // For now, only use non-vector load / store's for the left-over pieces.
9486 LLT NewTy = Ty;
9487 // FIXME: check for mem op safety and legality of the types. Not all of
9488 // SDAGisms map cleanly to GISel concepts.
9489 if (NewTy.isVector())
9490 NewTy = NewTy.getSizeInBits() > 64 ? LLT::scalar(64) : LLT::scalar(32);
9491 NewTy = LLT::scalar(llvm::bit_floor(NewTy.getSizeInBits() - 1));
9492 unsigned NewTySize = NewTy.getSizeInBytes();
9493 assert(NewTySize > 0 && "Could not find appropriate type");
9495 // If the new LLT cannot cover all of the remaining bits, then consider
9496 // issuing a (or a pair of) unaligned and overlapping load / store.
9497 unsigned Fast;
9498 // Need to get a VT equivalent for allowMisalignedMemoryAccesses().
9499 MVT VT = getMVTForLLT(Ty);
9500 if (NumMemOps && Op.allowOverlap() && NewTySize < Size &&
9501 TLI.allowsMisalignedMemoryAccesses(
9502 VT, DstAS, Op.isFixedDstAlign() ? Op.getDstAlign() : Align(1),
9503 MachineMemOperand::MONone, &Fast) &&
9504 Fast)
9505 TySize = Size;
9506 else {
9507 Ty = NewTy;
9508 TySize = NewTySize;
9512 if (++NumMemOps > Limit)
9513 return false;
9515 MemOps.push_back(Ty);
9516 Size -= TySize;
9519 return true;
9522 // Get a vectorized representation of the memset value operand, GISel edition.
9523 static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB) {
9524 MachineRegisterInfo &MRI = *MIB.getMRI();
9525 unsigned NumBits = Ty.getScalarSizeInBits();
9526 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
9527 if (!Ty.isVector() && ValVRegAndVal) {
9528 APInt Scalar = ValVRegAndVal->Value.trunc(8);
9529 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
9530 return MIB.buildConstant(Ty, SplatVal).getReg(0);
9533 // Extend the byte value to the larger type, and then multiply by a magic
9534 // value 0x010101... in order to replicate it across every byte.
9535 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
9536 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
9537 return MIB.buildConstant(Ty, 0).getReg(0);
9540 LLT ExtType = Ty.getScalarType();
9541 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
9542 if (NumBits > 8) {
9543 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
9544 auto MagicMI = MIB.buildConstant(ExtType, Magic);
9545 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
9548 // For vector types create a G_BUILD_VECTOR.
9549 if (Ty.isVector())
9550 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
9552 return Val;
9555 LegalizerHelper::LegalizeResult
9556 LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
9557 uint64_t KnownLen, Align Alignment,
9558 bool IsVolatile) {
9559 auto &MF = *MI.getParent()->getParent();
9560 const auto &TLI = *MF.getSubtarget().getTargetLowering();
9561 auto &DL = MF.getDataLayout();
9562 LLVMContext &C = MF.getFunction().getContext();
9564 assert(KnownLen != 0 && "Have a zero length memset length!");
9566 bool DstAlignCanChange = false;
9567 MachineFrameInfo &MFI = MF.getFrameInfo();
9568 bool OptSize = shouldLowerMemFuncForSize(MF);
9570 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
9571 if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
9572 DstAlignCanChange = true;
9574 unsigned Limit = TLI.getMaxStoresPerMemset(OptSize);
9575 std::vector<LLT> MemOps;
9577 const auto &DstMMO = **MI.memoperands_begin();
9578 MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
9580 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
9581 bool IsZeroVal = ValVRegAndVal && ValVRegAndVal->Value == 0;
9583 if (!findGISelOptimalMemOpLowering(MemOps, Limit,
9584 MemOp::Set(KnownLen, DstAlignCanChange,
9585 Alignment,
9586 /*IsZeroMemset=*/IsZeroVal,
9587 /*IsVolatile=*/IsVolatile),
9588 DstPtrInfo.getAddrSpace(), ~0u,
9589 MF.getFunction().getAttributes(), TLI))
9590 return UnableToLegalize;
9592 if (DstAlignCanChange) {
9593 // Get an estimate of the type from the LLT.
9594 Type *IRTy = getTypeForLLT(MemOps[0], C);
9595 Align NewAlign = DL.getABITypeAlign(IRTy);
9596 if (NewAlign > Alignment) {
9597 Alignment = NewAlign;
9598 unsigned FI = FIDef->getOperand(1).getIndex();
9599 // Give the stack frame object a larger alignment if needed.
9600 if (MFI.getObjectAlign(FI) < Alignment)
9601 MFI.setObjectAlignment(FI, Alignment);
9605 MachineIRBuilder MIB(MI);
9606 // Find the largest store and generate the bit pattern for it.
9607 LLT LargestTy = MemOps[0];
9608 for (unsigned i = 1; i < MemOps.size(); i++)
9609 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
9610 LargestTy = MemOps[i];
9612 // The memset stored value is always defined as an s8, so in order to make it
9613 // work with larger store types we need to repeat the bit pattern across the
9614 // wider type.
9615 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
9617 if (!MemSetValue)
9618 return UnableToLegalize;
9620 // Generate the stores. For each store type in the list, we generate the
9621 // matching store of that type to the destination address.
9622 LLT PtrTy = MRI.getType(Dst);
9623 unsigned DstOff = 0;
9624 unsigned Size = KnownLen;
9625 for (unsigned I = 0; I < MemOps.size(); I++) {
9626 LLT Ty = MemOps[I];
9627 unsigned TySize = Ty.getSizeInBytes();
9628 if (TySize > Size) {
9629 // Issuing an unaligned load / store pair that overlaps with the previous
9630 // pair. Adjust the offset accordingly.
9631 assert(I == MemOps.size() - 1 && I != 0);
9632 DstOff -= TySize - Size;
9635 // If this store is smaller than the largest store see whether we can get
9636 // the smaller value for free with a truncate.
9637 Register Value = MemSetValue;
9638 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
9639 MVT VT = getMVTForLLT(Ty);
9640 MVT LargestVT = getMVTForLLT(LargestTy);
9641 if (!LargestTy.isVector() && !Ty.isVector() &&
9642 TLI.isTruncateFree(LargestVT, VT))
9643 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
9644 else
9645 Value = getMemsetValue(Val, Ty, MIB);
9646 if (!Value)
9647 return UnableToLegalize;
9650 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
9652 Register Ptr = Dst;
9653 if (DstOff != 0) {
9654 auto Offset =
9655 MIB.buildConstant(LLT::scalar(PtrTy.getSizeInBits()), DstOff);
9656 Ptr = MIB.buildPtrAdd(PtrTy, Dst, Offset).getReg(0);
9659 MIB.buildStore(Value, Ptr, *StoreMMO);
9660 DstOff += Ty.getSizeInBytes();
9661 Size -= TySize;
9664 MI.eraseFromParent();
9665 return Legalized;
9668 LegalizerHelper::LegalizeResult
9669 LegalizerHelper::lowerMemcpyInline(MachineInstr &MI) {
9670 assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);
9672 auto [Dst, Src, Len] = MI.getFirst3Regs();
9674 const auto *MMOIt = MI.memoperands_begin();
9675 const MachineMemOperand *MemOp = *MMOIt;
9676 bool IsVolatile = MemOp->isVolatile();
9678 // See if this is a constant length copy
9679 auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);
9680 // FIXME: support dynamically sized G_MEMCPY_INLINE
9681 assert(LenVRegAndVal &&
9682 "inline memcpy with dynamic size is not yet supported");
9683 uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();
9684 if (KnownLen == 0) {
9685 MI.eraseFromParent();
9686 return Legalized;
9689 const auto &DstMMO = **MI.memoperands_begin();
9690 const auto &SrcMMO = **std::next(MI.memoperands_begin());
9691 Align DstAlign = DstMMO.getBaseAlign();
9692 Align SrcAlign = SrcMMO.getBaseAlign();
9694 return lowerMemcpyInline(MI, Dst, Src, KnownLen, DstAlign, SrcAlign,
9695 IsVolatile);
9698 LegalizerHelper::LegalizeResult
9699 LegalizerHelper::lowerMemcpyInline(MachineInstr &MI, Register Dst, Register Src,
9700 uint64_t KnownLen, Align DstAlign,
9701 Align SrcAlign, bool IsVolatile) {
9702 assert(MI.getOpcode() == TargetOpcode::G_MEMCPY_INLINE);
9703 return lowerMemcpy(MI, Dst, Src, KnownLen,
9704 std::numeric_limits<uint64_t>::max(), DstAlign, SrcAlign,
9705 IsVolatile);
9708 LegalizerHelper::LegalizeResult
9709 LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
9710 uint64_t KnownLen, uint64_t Limit, Align DstAlign,
9711 Align SrcAlign, bool IsVolatile) {
9712 auto &MF = *MI.getParent()->getParent();
9713 const auto &TLI = *MF.getSubtarget().getTargetLowering();
9714 auto &DL = MF.getDataLayout();
9715 LLVMContext &C = MF.getFunction().getContext();
9717 assert(KnownLen != 0 && "Have a zero length memcpy length!");
9719 bool DstAlignCanChange = false;
9720 MachineFrameInfo &MFI = MF.getFrameInfo();
9721 Align Alignment = std::min(DstAlign, SrcAlign);
9723 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
9724 if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
9725 DstAlignCanChange = true;
9727 // FIXME: infer better src pointer alignment like SelectionDAG does here.
9728 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
9729 // if the memcpy is in a tail call position.
9731 std::vector<LLT> MemOps;
9733 const auto &DstMMO = **MI.memoperands_begin();
9734 const auto &SrcMMO = **std::next(MI.memoperands_begin());
9735 MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
9736 MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();
9738 if (!findGISelOptimalMemOpLowering(
9739 MemOps, Limit,
9740 MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,
9741 IsVolatile),
9742 DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),
9743 MF.getFunction().getAttributes(), TLI))
9744 return UnableToLegalize;
9746 if (DstAlignCanChange) {
9747 // Get an estimate of the type from the LLT.
9748 Type *IRTy = getTypeForLLT(MemOps[0], C);
9749 Align NewAlign = DL.getABITypeAlign(IRTy);
9751 // Don't promote to an alignment that would require dynamic stack
9752 // realignment.
9753 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
9754 if (!TRI->hasStackRealignment(MF))
9755 if (MaybeAlign StackAlign = DL.getStackAlignment())
9756 NewAlign = std::min(NewAlign, *StackAlign);
9758 if (NewAlign > Alignment) {
9759 Alignment = NewAlign;
9760 unsigned FI = FIDef->getOperand(1).getIndex();
9761 // Give the stack frame object a larger alignment if needed.
9762 if (MFI.getObjectAlign(FI) < Alignment)
9763 MFI.setObjectAlignment(FI, Alignment);
9767 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
9769 MachineIRBuilder MIB(MI);
9770 // Now we need to emit a pair of load and stores for each of the types we've
9771 // collected. I.e. for each type, generate a load from the source pointer of
9772 // that type width, and then generate a corresponding store to the dest buffer
9773 // of that value loaded. This can result in a sequence of loads and stores
9774 // mixed types, depending on what the target specifies as good types to use.
9775 unsigned CurrOffset = 0;
9776 unsigned Size = KnownLen;
9777 for (auto CopyTy : MemOps) {
9778 // Issuing an unaligned load / store pair that overlaps with the previous
9779 // pair. Adjust the offset accordingly.
9780 if (CopyTy.getSizeInBytes() > Size)
9781 CurrOffset -= CopyTy.getSizeInBytes() - Size;
9783 // Construct MMOs for the accesses.
9784 auto *LoadMMO =
9785 MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
9786 auto *StoreMMO =
9787 MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
9789 // Create the load.
9790 Register LoadPtr = Src;
9791 Register Offset;
9792 if (CurrOffset != 0) {
9793 LLT SrcTy = MRI.getType(Src);
9794 Offset = MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset)
9795 .getReg(0);
9796 LoadPtr = MIB.buildPtrAdd(SrcTy, Src, Offset).getReg(0);
9798 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
9800 // Create the store.
9801 Register StorePtr = Dst;
9802 if (CurrOffset != 0) {
9803 LLT DstTy = MRI.getType(Dst);
9804 StorePtr = MIB.buildPtrAdd(DstTy, Dst, Offset).getReg(0);
9806 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
9807 CurrOffset += CopyTy.getSizeInBytes();
9808 Size -= CopyTy.getSizeInBytes();
9811 MI.eraseFromParent();
9812 return Legalized;
9815 LegalizerHelper::LegalizeResult
9816 LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
9817 uint64_t KnownLen, Align DstAlign, Align SrcAlign,
9818 bool IsVolatile) {
9819 auto &MF = *MI.getParent()->getParent();
9820 const auto &TLI = *MF.getSubtarget().getTargetLowering();
9821 auto &DL = MF.getDataLayout();
9822 LLVMContext &C = MF.getFunction().getContext();
9824 assert(KnownLen != 0 && "Have a zero length memmove length!");
9826 bool DstAlignCanChange = false;
9827 MachineFrameInfo &MFI = MF.getFrameInfo();
9828 bool OptSize = shouldLowerMemFuncForSize(MF);
9829 Align Alignment = std::min(DstAlign, SrcAlign);
9831 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
9832 if (FIDef && !MFI.isFixedObjectIndex(FIDef->getOperand(1).getIndex()))
9833 DstAlignCanChange = true;
9835 unsigned Limit = TLI.getMaxStoresPerMemmove(OptSize);
9836 std::vector<LLT> MemOps;
9838 const auto &DstMMO = **MI.memoperands_begin();
9839 const auto &SrcMMO = **std::next(MI.memoperands_begin());
9840 MachinePointerInfo DstPtrInfo = DstMMO.getPointerInfo();
9841 MachinePointerInfo SrcPtrInfo = SrcMMO.getPointerInfo();
9843 // FIXME: SelectionDAG always passes false for 'AllowOverlap', apparently due
9844 // to a bug in it's findOptimalMemOpLowering implementation. For now do the
9845 // same thing here.
9846 if (!findGISelOptimalMemOpLowering(
9847 MemOps, Limit,
9848 MemOp::Copy(KnownLen, DstAlignCanChange, Alignment, SrcAlign,
9849 /*IsVolatile*/ true),
9850 DstPtrInfo.getAddrSpace(), SrcPtrInfo.getAddrSpace(),
9851 MF.getFunction().getAttributes(), TLI))
9852 return UnableToLegalize;
9854 if (DstAlignCanChange) {
9855 // Get an estimate of the type from the LLT.
9856 Type *IRTy = getTypeForLLT(MemOps[0], C);
9857 Align NewAlign = DL.getABITypeAlign(IRTy);
9859 // Don't promote to an alignment that would require dynamic stack
9860 // realignment.
9861 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
9862 if (!TRI->hasStackRealignment(MF))
9863 if (MaybeAlign StackAlign = DL.getStackAlignment())
9864 NewAlign = std::min(NewAlign, *StackAlign);
9866 if (NewAlign > Alignment) {
9867 Alignment = NewAlign;
9868 unsigned FI = FIDef->getOperand(1).getIndex();
9869 // Give the stack frame object a larger alignment if needed.
9870 if (MFI.getObjectAlign(FI) < Alignment)
9871 MFI.setObjectAlignment(FI, Alignment);
9875 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
9877 MachineIRBuilder MIB(MI);
9878 // Memmove requires that we perform the loads first before issuing the stores.
9879 // Apart from that, this loop is pretty much doing the same thing as the
9880 // memcpy codegen function.
9881 unsigned CurrOffset = 0;
9882 SmallVector<Register, 16> LoadVals;
9883 for (auto CopyTy : MemOps) {
9884 // Construct MMO for the load.
9885 auto *LoadMMO =
9886 MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
9888 // Create the load.
9889 Register LoadPtr = Src;
9890 if (CurrOffset != 0) {
9891 LLT SrcTy = MRI.getType(Src);
9892 auto Offset =
9893 MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset);
9894 LoadPtr = MIB.buildPtrAdd(SrcTy, Src, Offset).getReg(0);
9896 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
9897 CurrOffset += CopyTy.getSizeInBytes();
9900 CurrOffset = 0;
9901 for (unsigned I = 0; I < MemOps.size(); ++I) {
9902 LLT CopyTy = MemOps[I];
9903 // Now store the values loaded.
9904 auto *StoreMMO =
9905 MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
9907 Register StorePtr = Dst;
9908 if (CurrOffset != 0) {
9909 LLT DstTy = MRI.getType(Dst);
9910 auto Offset =
9911 MIB.buildConstant(LLT::scalar(DstTy.getSizeInBits()), CurrOffset);
9912 StorePtr = MIB.buildPtrAdd(DstTy, Dst, Offset).getReg(0);
9914 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
9915 CurrOffset += CopyTy.getSizeInBytes();
9917 MI.eraseFromParent();
9918 return Legalized;
9921 LegalizerHelper::LegalizeResult
9922 LegalizerHelper::lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen) {
9923 const unsigned Opc = MI.getOpcode();
9924 // This combine is fairly complex so it's not written with a separate
9925 // matcher function.
9926 assert((Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMMOVE ||
9927 Opc == TargetOpcode::G_MEMSET) &&
9928 "Expected memcpy like instruction");
9930 auto MMOIt = MI.memoperands_begin();
9931 const MachineMemOperand *MemOp = *MMOIt;
9933 Align DstAlign = MemOp->getBaseAlign();
9934 Align SrcAlign;
9935 auto [Dst, Src, Len] = MI.getFirst3Regs();
9937 if (Opc != TargetOpcode::G_MEMSET) {
9938 assert(MMOIt != MI.memoperands_end() && "Expected a second MMO on MI");
9939 MemOp = *(++MMOIt);
9940 SrcAlign = MemOp->getBaseAlign();
9943 // See if this is a constant length copy
9944 auto LenVRegAndVal = getIConstantVRegValWithLookThrough(Len, MRI);
9945 if (!LenVRegAndVal)
9946 return UnableToLegalize;
9947 uint64_t KnownLen = LenVRegAndVal->Value.getZExtValue();
9949 if (KnownLen == 0) {
9950 MI.eraseFromParent();
9951 return Legalized;
9954 bool IsVolatile = MemOp->isVolatile();
9955 if (Opc == TargetOpcode::G_MEMCPY_INLINE)
9956 return lowerMemcpyInline(MI, Dst, Src, KnownLen, DstAlign, SrcAlign,
9957 IsVolatile);
9959 // Don't try to optimize volatile.
9960 if (IsVolatile)
9961 return UnableToLegalize;
9963 if (MaxLen && KnownLen > MaxLen)
9964 return UnableToLegalize;
9966 if (Opc == TargetOpcode::G_MEMCPY) {
9967 auto &MF = *MI.getParent()->getParent();
9968 const auto &TLI = *MF.getSubtarget().getTargetLowering();
9969 bool OptSize = shouldLowerMemFuncForSize(MF);
9970 uint64_t Limit = TLI.getMaxStoresPerMemcpy(OptSize);
9971 return lowerMemcpy(MI, Dst, Src, KnownLen, Limit, DstAlign, SrcAlign,
9972 IsVolatile);
9974 if (Opc == TargetOpcode::G_MEMMOVE)
9975 return lowerMemmove(MI, Dst, Src, KnownLen, DstAlign, SrcAlign, IsVolatile);
9976 if (Opc == TargetOpcode::G_MEMSET)
9977 return lowerMemset(MI, Dst, Src, KnownLen, DstAlign, IsVolatile);
9978 return UnableToLegalize;