LLVM 24.0.0git
LegalizerHelper.cpp
Go to the documentation of this file.
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.
12//
13//===----------------------------------------------------------------------===//
14
36#include "llvm/Support/Debug.h"
40#include <cassert>
41#include <numeric>
42#include <optional>
43
44#define DEBUG_TYPE "legalizer"
45
46using namespace llvm;
47using namespace LegalizeActions;
48using namespace MIPatternMatch;
49
50/// Choose an insertion point for a conversion of an incoming PHI value.
51/// Values available before an invoke must be converted before it, so the
52/// conversion also executes on the unwind edge. An invoke result is defined
53/// after G_INVOKE_REGION_START and is only available on the normal edge.
56 const MachineRegisterInfo &MRI) {
57 auto InsertPt = MBB.getFirstTerminatorForward();
58 // Only invoke regions need the extra definition-order check.
59 if (InsertPt == MBB.end() ||
60 InsertPt->getOpcode() != TargetOpcode::G_INVOKE_REGION_START)
61 return InsertPt;
62
63 MachineInstr *Def = MRI.getVRegDef(Reg);
64 if (Def->getParent() == &MBB)
65 for (auto I = InsertPt, E = MBB.end(); I != E; ++I)
66 if (&*I == Def)
67 return std::next(I);
68 return InsertPt;
69}
70
71/// Try to break down \p OrigTy into \p NarrowTy sized pieces.
72///
73/// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
74/// with any leftover piece as type \p LeftoverTy
75///
76/// Returns -1 in the first element of the pair if the breakdown is not
77/// satisfiable.
78static std::pair<int, int>
79getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
80 assert(!LeftoverTy.isValid() && "this is an out argument");
81
82 unsigned Size = OrigTy.getSizeInBits();
83 unsigned NarrowSize = NarrowTy.getSizeInBits();
84 unsigned NumParts = Size / NarrowSize;
85 unsigned LeftoverSize = Size - NumParts * NarrowSize;
86 assert(Size > NarrowSize);
87
88 if (LeftoverSize == 0)
89 return {NumParts, 0};
90
91 if (NarrowTy.isVector()) {
92 unsigned EltSize = OrigTy.getScalarSizeInBits();
93 if (LeftoverSize % EltSize != 0)
94 return {-1, -1};
95 LeftoverTy = OrigTy.changeElementCount(
96 ElementCount::getFixed(LeftoverSize / EltSize));
97 } else {
98 LeftoverTy = LLT::integer(LeftoverSize);
99 }
100
101 int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
102 return std::make_pair(NumParts, NumLeftover);
103}
104
106
107 if (!Ty.isScalar())
108 return nullptr;
109
110 switch (Ty.getSizeInBits()) {
111 case 16:
112 return Type::getHalfTy(Ctx);
113 case 32:
114 return Type::getFloatTy(Ctx);
115 case 64:
116 return Type::getDoubleTy(Ctx);
117 case 80:
118 return Type::getX86_FP80Ty(Ctx);
119 case 128:
120 return Type::getFP128Ty(Ctx);
121 default:
122 return nullptr;
123 }
124}
125
128 MachineIRBuilder &Builder,
129 const LibcallLoweringInfo *Libcalls)
130 : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
131 LI(*MF.getSubtarget().getLegalizerInfo()),
132 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls) {}
133
137 const LibcallLoweringInfo *Libcalls,
139 : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
140 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls), VT(VT) {}
141
144 LostDebugLocObserver &LocObserver) {
145 LLVM_DEBUG(dbgs() << "\nLegalizing: " << MI);
146
147 MIRBuilder.setInstrAndDebugLoc(MI);
148
149 if (isa<GIntrinsic>(MI))
150 return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
151 auto Step = LI.getAction(MI, MRI);
152 switch (Step.Action) {
153 case Legal:
154 LLVM_DEBUG(dbgs() << ".. Already legal\n");
155 return AlreadyLegal;
156 case Libcall:
157 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
158 return libcall(MI, LocObserver);
159 case NarrowScalar:
160 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
161 return narrowScalar(MI, Step.TypeIdx, Step.NewType);
162 case WidenScalar:
163 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
164 return widenScalar(MI, Step.TypeIdx, Step.NewType);
165 case Bitcast:
166 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
167 return bitcast(MI, Step.TypeIdx, Step.NewType);
168 case Lower:
169 LLVM_DEBUG(dbgs() << ".. Lower\n");
170 return lower(MI, Step.TypeIdx, Step.NewType);
171 case FewerElements:
172 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
173 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
174 case MoreElements:
175 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
176 return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
177 case Custom:
178 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
179 return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
181 default:
182 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
183 return UnableToLegalize;
184 }
185}
186
187void LegalizerHelper::insertParts(Register DstReg,
188 LLT ResultTy, LLT PartTy,
189 ArrayRef<Register> PartRegs,
190 LLT LeftoverTy,
191 ArrayRef<Register> LeftoverRegs) {
192 if (!LeftoverTy.isValid()) {
193 assert(LeftoverRegs.empty());
194
195 if (!ResultTy.isVector()) {
196 MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
197 return;
198 }
199
200 if (PartTy.isVector())
201 MIRBuilder.buildConcatVectors(DstReg, PartRegs);
202 else
203 MIRBuilder.buildBuildVector(DstReg, PartRegs);
204 return;
205 }
206
207 // Merge sub-vectors with different number of elements and insert into DstReg.
208 if (ResultTy.isVector()) {
209 assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
210 SmallVector<Register, 8> AllRegs(PartRegs);
211 AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());
212 return mergeMixedSubvectors(DstReg, AllRegs);
213 }
214
215 SmallVector<Register> GCDRegs;
216 LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
217 for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
218 extractGCDType(GCDRegs, GCDTy, PartReg);
219 LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
220 buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
221}
222
223void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
224 Register Reg) {
225 LLT Ty = MRI.getType(Reg);
227 extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
228 MIRBuilder, MRI);
229 Elts.append(RegElts);
230}
231
232/// Merge \p PartRegs with different types into \p DstReg.
233void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
234 ArrayRef<Register> PartRegs) {
236 for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
237 appendVectorElts(AllElts, PartRegs[i]);
238
239 Register Leftover = PartRegs[PartRegs.size() - 1];
240 if (!MRI.getType(Leftover).isVector())
241 AllElts.push_back(Leftover);
242 else
243 appendVectorElts(AllElts, Leftover);
244
245 MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
246}
247
248/// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
250 const MachineInstr &MI) {
251 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
252
253 const int StartIdx = Regs.size();
254 const int NumResults = MI.getNumOperands() - 1;
255 Regs.resize(Regs.size() + NumResults);
256 for (int I = 0; I != NumResults; ++I)
257 Regs[StartIdx + I] = MI.getOperand(I).getReg();
258}
259
260void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
261 LLT GCDTy, Register SrcReg) {
262 LLT SrcTy = MRI.getType(SrcReg);
263 if (SrcTy == GCDTy) {
264 // If the source already evenly divides the result type, we don't need to do
265 // anything.
266 Parts.push_back(SrcReg);
267 } else {
268 // Need to split into common type sized pieces.
269 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
270 getUnmergeResults(Parts, *Unmerge);
271 }
272}
273
274LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
275 LLT NarrowTy, Register SrcReg) {
276 LLT SrcTy = MRI.getType(SrcReg);
277 LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
278 extractGCDType(Parts, GCDTy, SrcReg);
279 return GCDTy;
280}
281
282LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
284 unsigned PadStrategy) {
285 LLT LCMTy = getLCMType(DstTy, NarrowTy);
286
287 int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
288 int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
289 int NumOrigSrc = VRegs.size();
290
291 Register PadReg;
292
293 // Get a value we can use to pad the source value if the sources won't evenly
294 // cover the result type.
295 if (NumOrigSrc < NumParts * NumSubParts) {
296 if (PadStrategy == TargetOpcode::G_ZEXT)
297 PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
298 else if (PadStrategy == TargetOpcode::G_ANYEXT)
299 PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
300 else {
301 assert(PadStrategy == TargetOpcode::G_SEXT);
302
303 // Shift the sign bit of the low register through the high register.
304 auto ShiftAmt =
305 MIRBuilder.buildConstant(LLT::integer(64), GCDTy.getSizeInBits() - 1);
306 PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
307 }
308 }
309
310 // Registers for the final merge to be produced.
312
313 // Registers needed for intermediate merges, which will be merged into a
314 // source for Remerge.
315 SmallVector<Register, 4> SubMerge(NumSubParts);
316
317 // Once we've fully read off the end of the original source bits, we can reuse
318 // the same high bits for remaining padding elements.
319 Register AllPadReg;
320
321 // Build merges to the LCM type to cover the original result type.
322 for (int I = 0; I != NumParts; ++I) {
323 bool AllMergePartsArePadding = true;
324
325 // Build the requested merges to the requested type.
326 for (int J = 0; J != NumSubParts; ++J) {
327 int Idx = I * NumSubParts + J;
328 if (Idx >= NumOrigSrc) {
329 SubMerge[J] = PadReg;
330 continue;
331 }
332
333 SubMerge[J] = VRegs[Idx];
334
335 // There are meaningful bits here we can't reuse later.
336 AllMergePartsArePadding = false;
337 }
338
339 // If we've filled up a complete piece with padding bits, we can directly
340 // emit the natural sized constant if applicable, rather than a merge of
341 // smaller constants.
342 if (AllMergePartsArePadding && !AllPadReg) {
343 if (PadStrategy == TargetOpcode::G_ANYEXT)
344 AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
345 else if (PadStrategy == TargetOpcode::G_ZEXT)
346 AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
347
348 // If this is a sign extension, we can't materialize a trivial constant
349 // with the right type and have to produce a merge.
350 }
351
352 if (AllPadReg) {
353 // Avoid creating additional instructions if we're just adding additional
354 // copies of padding bits.
355 Remerge[I] = AllPadReg;
356 continue;
357 }
358
359 if (NumSubParts == 1)
360 Remerge[I] = SubMerge[0];
361 else
362 Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
363
364 // In the sign extend padding case, re-use the first all-signbit merge.
365 if (AllMergePartsArePadding && !AllPadReg)
366 AllPadReg = Remerge[I];
367 }
368
369 VRegs = std::move(Remerge);
370 return LCMTy;
371}
372
373void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
374 ArrayRef<Register> RemergeRegs) {
375 LLT DstTy = MRI.getType(DstReg);
376
377 // Create the merge to the widened source, and extract the relevant bits into
378 // the result.
379
380 if (DstTy == LCMTy) {
381 MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
382 return;
383 }
384
385 auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
386 if (DstTy.isScalar() && LCMTy.isScalar()) {
387 MIRBuilder.buildTrunc(DstReg, Remerge);
388 return;
389 }
390
391 if (LCMTy.isVector()) {
392 unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
393 SmallVector<Register, 8> UnmergeDefs(NumDefs);
394 UnmergeDefs[0] = DstReg;
395 for (unsigned I = 1; I != NumDefs; ++I)
396 UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
397
398 MIRBuilder.buildUnmerge(UnmergeDefs,
399 MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
400 return;
401 }
402
403 llvm_unreachable("unhandled case");
404}
405
406static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
407#define RTLIBCASE_INT(LibcallPrefix) \
408 do { \
409 switch (Size) { \
410 case 32: \
411 return RTLIB::LibcallPrefix##32; \
412 case 64: \
413 return RTLIB::LibcallPrefix##64; \
414 case 128: \
415 return RTLIB::LibcallPrefix##128; \
416 default: \
417 llvm_unreachable("unexpected size"); \
418 } \
419 } while (0)
420
421#define RTLIBCASE(LibcallPrefix) \
422 do { \
423 switch (Size) { \
424 case 32: \
425 return RTLIB::LibcallPrefix##32; \
426 case 64: \
427 return RTLIB::LibcallPrefix##64; \
428 case 80: \
429 return RTLIB::LibcallPrefix##80; \
430 case 128: \
431 return RTLIB::LibcallPrefix##128; \
432 default: \
433 llvm_unreachable("unexpected size"); \
434 } \
435 } while (0)
436
437 switch (Opcode) {
438 case TargetOpcode::G_LROUND:
439 RTLIBCASE(LROUND_F);
440 case TargetOpcode::G_LLROUND:
441 RTLIBCASE(LLROUND_F);
442 case TargetOpcode::G_MUL:
443 RTLIBCASE_INT(MUL_I);
444 case TargetOpcode::G_SDIV:
445 RTLIBCASE_INT(SDIV_I);
446 case TargetOpcode::G_UDIV:
447 RTLIBCASE_INT(UDIV_I);
448 case TargetOpcode::G_SREM:
449 RTLIBCASE_INT(SREM_I);
450 case TargetOpcode::G_UREM:
451 RTLIBCASE_INT(UREM_I);
452 case TargetOpcode::G_CTLZ_ZERO_POISON:
453 RTLIBCASE_INT(CTLZ_I);
454 case TargetOpcode::G_FADD:
455 RTLIBCASE(ADD_F);
456 case TargetOpcode::G_FSUB:
457 RTLIBCASE(SUB_F);
458 case TargetOpcode::G_FMUL:
459 RTLIBCASE(MUL_F);
460 case TargetOpcode::G_FDIV:
461 RTLIBCASE(DIV_F);
462 case TargetOpcode::G_FEXP:
463 RTLIBCASE(EXP_F);
464 case TargetOpcode::G_FEXP2:
465 RTLIBCASE(EXP2_F);
466 case TargetOpcode::G_FEXP10:
467 RTLIBCASE(EXP10_F);
468 case TargetOpcode::G_FREM:
469 RTLIBCASE(REM_F);
470 case TargetOpcode::G_FPOW:
471 RTLIBCASE(POW_F);
472 case TargetOpcode::G_FPOWI:
473 RTLIBCASE(POWI_F);
474 case TargetOpcode::G_FMA:
475 RTLIBCASE(FMA_F);
476 case TargetOpcode::G_FSIN:
477 RTLIBCASE(SIN_F);
478 case TargetOpcode::G_FCOS:
479 RTLIBCASE(COS_F);
480 case TargetOpcode::G_FTAN:
481 RTLIBCASE(TAN_F);
482 case TargetOpcode::G_FASIN:
483 RTLIBCASE(ASIN_F);
484 case TargetOpcode::G_FACOS:
485 RTLIBCASE(ACOS_F);
486 case TargetOpcode::G_FATAN:
487 RTLIBCASE(ATAN_F);
488 case TargetOpcode::G_FATAN2:
489 RTLIBCASE(ATAN2_F);
490 case TargetOpcode::G_FSINH:
491 RTLIBCASE(SINH_F);
492 case TargetOpcode::G_FCOSH:
493 RTLIBCASE(COSH_F);
494 case TargetOpcode::G_FTANH:
495 RTLIBCASE(TANH_F);
496 case TargetOpcode::G_FSINCOS:
497 RTLIBCASE(SINCOS_F);
498 case TargetOpcode::G_FMODF:
499 RTLIBCASE(MODF_F);
500 case TargetOpcode::G_FLOG10:
501 RTLIBCASE(LOG10_F);
502 case TargetOpcode::G_FLOG:
503 RTLIBCASE(LOG_F);
504 case TargetOpcode::G_FLOG2:
505 RTLIBCASE(LOG2_F);
506 case TargetOpcode::G_FLDEXP:
507 RTLIBCASE(LDEXP_F);
508 case TargetOpcode::G_FCEIL:
509 RTLIBCASE(CEIL_F);
510 case TargetOpcode::G_FFLOOR:
511 RTLIBCASE(FLOOR_F);
512 case TargetOpcode::G_FMINNUM:
513 RTLIBCASE(FMIN_F);
514 case TargetOpcode::G_FMAXNUM:
515 RTLIBCASE(FMAX_F);
516 case TargetOpcode::G_FMINIMUMNUM:
517 RTLIBCASE(FMINIMUM_NUM_F);
518 case TargetOpcode::G_FMAXIMUMNUM:
519 RTLIBCASE(FMAXIMUM_NUM_F);
520 case TargetOpcode::G_FSQRT:
521 RTLIBCASE(SQRT_F);
522 case TargetOpcode::G_FRINT:
523 RTLIBCASE(RINT_F);
524 case TargetOpcode::G_FNEARBYINT:
525 RTLIBCASE(NEARBYINT_F);
526 case TargetOpcode::G_INTRINSIC_TRUNC:
527 RTLIBCASE(TRUNC_F);
528 case TargetOpcode::G_INTRINSIC_ROUND:
529 RTLIBCASE(ROUND_F);
530 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
531 RTLIBCASE(ROUNDEVEN_F);
532 case TargetOpcode::G_INTRINSIC_LRINT:
533 RTLIBCASE(LRINT_F);
534 case TargetOpcode::G_INTRINSIC_LLRINT:
535 RTLIBCASE(LLRINT_F);
536 }
537 llvm_unreachable("Unknown libcall function");
538#undef RTLIBCASE_INT
539#undef RTLIBCASE
540}
541
544 return TLI.supportSwiftError() &&
545 MF.getFunction().getAttributes().hasAttrSomewhere(
546 Attribute::SwiftError);
547}
548
549/// True if an instruction is in tail position in its caller. Intended for
550/// legalizing libcalls as tail calls when possible.
553 const TargetInstrInfo &TII,
555 MachineBasicBlock &MBB = *MI.getParent();
556 const Function &F = MBB.getParent()->getFunction();
557
558 // Conservatively require the attributes of the call to match those of
559 // the return. Ignore NoAlias and NonNull because they don't affect the
560 // call sequence.
561 AttributeList CallerAttrs = F.getAttributes();
562 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
563 .removeAttribute(Attribute::NoAlias)
564 .removeAttribute(Attribute::NonNull)
565 .hasAttributes())
566 return false;
567
568 // It's not safe to eliminate the sign / zero extension of the return value.
569 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
570 CallerAttrs.hasRetAttr(Attribute::SExt))
571 return false;
572
573 // Check if tail calls have been disabled in this function.
574 if (F.getFnAttribute("disable-tail-calls").getValueAsBool())
575 return false;
576
577 // Only tail call if the following instruction is a standard return or if we
578 // have a `thisreturn` callee, and a sequence like:
579 //
580 // G_MEMCPY %0, %1, %2
581 // $x0 = COPY %0
582 // RET_ReallyLR implicit $x0
583 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
584 if (Next != MBB.instr_end() && Next->isCopy()) {
585 if (MI.getOpcode() == TargetOpcode::G_BZERO)
586 return false;
587
588 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
589 // mempy/etc routines return the same parameter. For other it will be the
590 // returned value.
591 Register VReg = MI.getOperand(0).getReg();
592 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
593 return false;
594
595 Register PReg = Next->getOperand(0).getReg();
596 if (!PReg.isPhysical())
597 return false;
598
599 auto Ret = next_nodbg(Next, MBB.instr_end());
600 if (Ret == MBB.instr_end() || !Ret->isReturn())
601 return false;
602
603 if (Ret->getNumImplicitOperands() != 1)
604 return false;
605
606 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
607 return false;
608
609 // Skip over the COPY that we just validated.
610 Next = Ret;
611 }
612
613 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
614 return false;
615
616 return true;
617}
618
620 const char *Name, const CallLowering::ArgInfo &Result,
622 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
623 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
624
626 Info.CallConv = CC;
627 Info.Callee = MachineOperand::CreateES(Name);
628 Info.OrigRet = Result;
629 if (MI)
630 Info.IsTailCall =
631 (Result.Ty->isVoidTy() ||
632 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
633 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
634 *MIRBuilder.getMRI()) &&
635 // Lowering doesn't support tail calling inside a function with
636 // a swifterror argument yet.
638
639 llvm::append_range(Info.OrigArgs, Args);
640 if (!CLI.lowerCall(MIRBuilder, Info))
642
643 if (MI && Info.LoweredTailCall) {
644 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
645
646 // Check debug locations before removing the return.
647 LocObserver.checkpoint(true);
648
649 // We must have a return following the call (or debug insts) to get past
650 // isLibCallInTailPosition.
651 do {
652 MachineInstr *Next = MI->getNextNode();
653 assert(Next &&
654 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
655 "Expected instr following MI to be return or debug inst?");
656 // We lowered a tail call, so the call is now the return from the block.
657 // Delete the old return.
658 Next->eraseFromParent();
659 } while (MI->getNextNode());
660
661 // We expect to lose the debug location from the return.
662 LocObserver.checkpoint(false);
663 }
665}
666
668 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
670 MachineInstr *MI) const {
671 if (!Libcalls)
673
674 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
675 if (LibcallImpl == RTLIB::Unsupported)
677
679 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
680 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
681}
682
683// Useful for libcalls where all operands have the same type.
686 unsigned Size, Type *OpType,
687 LostDebugLocObserver &LocObserver) const {
688 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
689
690 // FIXME: What does the original arg index mean here?
692 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
693 Args.push_back({MO.getReg(), OpType, 0});
694 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
695 LocObserver, &MI);
696}
697
698LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
699 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
700 LostDebugLocObserver &LocObserver) {
701 MachineFunction &MF = *MI.getMF();
703
704 Register DstSin = MI.getOperand(0).getReg();
705 Register DstCos = MI.getOperand(1).getReg();
706 Register Src = MI.getOperand(2).getReg();
707 LLT DstTy = MRI.getType(DstSin);
708
709 int MemSize = DstTy.getSizeInBytes();
710 Align Alignment = getStackTemporaryAlignment(DstTy);
712 unsigned AddrSpace = DL.getAllocaAddrSpace();
713 MachinePointerInfo PtrInfo;
714
715 Register StackPtrSin =
716 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
717 .getReg(0);
718 Register StackPtrCos =
719 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
720 .getReg(0);
721
722 auto &Ctx = MF.getFunction().getContext();
723 auto LibcallResult = createLibcall(
724 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
725 {{Src, OpType, 0},
726 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
727 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
728 LocObserver, &MI);
729
730 if (LibcallResult != LegalizeResult::Legalized)
732
734 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
736 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
737
738 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
739 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
740 MI.eraseFromParent();
741
743}
744
746LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
747 unsigned Size, Type *OpType,
748 LostDebugLocObserver &LocObserver) {
749 MachineFunction &MF = MIRBuilder.getMF();
750 MachineRegisterInfo &MRI = MF.getRegInfo();
751
752 Register DstFrac = MI.getOperand(0).getReg();
753 Register DstInt = MI.getOperand(1).getReg();
754 Register Src = MI.getOperand(2).getReg();
755 LLT DstTy = MRI.getType(DstFrac);
756
757 int MemSize = DstTy.getSizeInBytes();
759 const DataLayout &DL = MIRBuilder.getDataLayout();
760 unsigned AddrSpace = DL.getAllocaAddrSpace();
761 MachinePointerInfo PtrInfo;
762
763 Register StackPtrInt =
764 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
765 .getReg(0);
766
767 auto &Ctx = MF.getFunction().getContext();
768 auto LibcallResult = createLibcall(
769 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
770 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
771 LocObserver, &MI);
772
773 if (LibcallResult != LegalizeResult::Legalized)
775
777 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
778
779 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
780 MI.eraseFromParent();
781
783}
784
785static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
786 Type *FromType) {
787 auto ToMVT = MVT::getVT(ToType);
788 auto FromMVT = MVT::getVT(FromType);
789
790 switch (Opcode) {
791 case TargetOpcode::G_FPEXT:
792 return RTLIB::getFPEXT(FromMVT, ToMVT);
793 case TargetOpcode::G_FPTRUNC:
794 return RTLIB::getFPROUND(FromMVT, ToMVT);
795 case TargetOpcode::G_FPTOSI:
796 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
797 case TargetOpcode::G_FPTOUI:
798 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
799 case TargetOpcode::G_SITOFP:
800 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
801 case TargetOpcode::G_UITOFP:
802 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
803 }
804 llvm_unreachable("Unsupported libcall function");
805}
806
808 MachineInstr &MI, Type *ToType, Type *FromType,
809 LostDebugLocObserver &LocObserver, bool IsSigned) const {
810 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
811 if (FromType->isIntegerTy()) {
812 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
813 Arg.Flags[0].setSExt();
814 else
815 Arg.Flags[0].setZExt();
816 }
817
818 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
819 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
820 LocObserver, &MI);
821}
822
825 LostDebugLocObserver &LocObserver) const {
826 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
827
829 // Add all the args, except for the last which is an imm denoting 'tail'.
830 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
831 Register Reg = MI.getOperand(i).getReg();
832
833 // Need derive an IR type for call lowering.
834 LLT OpLLT = MRI.getType(Reg);
835 Type *OpTy = nullptr;
836 if (OpLLT.isPointer())
837 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
838 else
839 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
840 Args.push_back({Reg, OpTy, 0});
841 }
842
843 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
844 RTLIB::Libcall RTLibcall;
845 unsigned Opc = MI.getOpcode();
846 switch (Opc) {
847 case TargetOpcode::G_BZERO:
848 RTLibcall = RTLIB::BZERO;
849 break;
850 case TargetOpcode::G_MEMCPY:
851 RTLibcall = RTLIB::MEMCPY;
852 Args[0].Flags[0].setReturned();
853 break;
854 case TargetOpcode::G_MEMMOVE:
855 RTLibcall = RTLIB::MEMMOVE;
856 Args[0].Flags[0].setReturned();
857 break;
858 case TargetOpcode::G_MEMSET:
859 RTLibcall = RTLIB::MEMSET;
860 Args[0].Flags[0].setReturned();
861 break;
862 default:
863 llvm_unreachable("unsupported opcode");
864 }
865
866 if (!Libcalls) // FIXME: Should be mandatory
868
869 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
870
871 // Unsupported libcall on the target.
872 if (RTLibcallImpl == RTLIB::Unsupported) {
873 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
874 << MIRBuilder.getTII().getName(Opc) << "\n");
876 }
877
879 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
880
881 StringRef LibcallName =
883 Info.Callee = MachineOperand::CreateES(LibcallName.data());
884 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
885 Info.IsTailCall =
886 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
887 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI) &&
888 // Lowering doesn't support tail calling inside a function with
889 // a swifterror argument yet.
891
892 llvm::append_range(Info.OrigArgs, Args);
893 if (!CLI.lowerCall(MIRBuilder, Info))
895
896 if (Info.LoweredTailCall) {
897 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
898
899 // Check debug locations before removing the return.
900 LocObserver.checkpoint(true);
901
902 // We must have a return following the call (or debug insts) to get past
903 // isLibCallInTailPosition.
904 do {
905 MachineInstr *Next = MI.getNextNode();
906 assert(Next &&
907 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
908 "Expected instr following MI to be return or debug inst?");
909 // We lowered a tail call, so the call is now the return from the block.
910 // Delete the old return.
911 Next->eraseFromParent();
912 } while (MI.getNextNode());
913
914 // We expect to lose the debug location from the return.
915 LocObserver.checkpoint(false);
916 }
917
919}
920
921static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
922 unsigned Opc = MI.getOpcode();
923 auto &AtomicMI = cast<GMemOperation>(MI);
924 auto &MMO = AtomicMI.getMMO();
925 auto Ordering = MMO.getMergedOrdering();
926 LLT MemType = MMO.getMemoryType();
927 uint64_t MemSize = MemType.getSizeInBytes();
928 if (MemType.isVector())
929 return RTLIB::UNKNOWN_LIBCALL;
930
931#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
932#define LCALL5(A) \
933 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
934 switch (Opc) {
935 case TargetOpcode::G_ATOMIC_CMPXCHG:
936 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
937 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
938 return getOutlineAtomicHelper(LC, Ordering, MemSize);
939 }
940 case TargetOpcode::G_ATOMICRMW_XCHG: {
941 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
942 return getOutlineAtomicHelper(LC, Ordering, MemSize);
943 }
944 case TargetOpcode::G_ATOMICRMW_ADD:
945 case TargetOpcode::G_ATOMICRMW_SUB: {
946 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
947 return getOutlineAtomicHelper(LC, Ordering, MemSize);
948 }
949 case TargetOpcode::G_ATOMICRMW_AND: {
950 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
951 return getOutlineAtomicHelper(LC, Ordering, MemSize);
952 }
953 case TargetOpcode::G_ATOMICRMW_OR: {
954 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
955 return getOutlineAtomicHelper(LC, Ordering, MemSize);
956 }
957 case TargetOpcode::G_ATOMICRMW_XOR: {
958 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
959 return getOutlineAtomicHelper(LC, Ordering, MemSize);
960 }
961 default:
962 return RTLIB::UNKNOWN_LIBCALL;
963 }
964#undef LCALLS
965#undef LCALL5
966}
967
970 auto &Ctx = MIRBuilder.getContext();
971
972 Type *RetTy;
973 SmallVector<Register> RetRegs;
975 unsigned Opc = MI.getOpcode();
976 switch (Opc) {
977 case TargetOpcode::G_ATOMIC_CMPXCHG:
978 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
980 LLT SuccessLLT;
981 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
982 MI.getFirst4RegLLTs();
983 RetRegs.push_back(Ret);
984 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
985 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
986 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
987 NewLLT) = MI.getFirst5RegLLTs();
988 RetRegs.push_back(Success);
989 RetTy = StructType::get(
990 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
991 }
992 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
993 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
994 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
995 break;
996 }
997 case TargetOpcode::G_ATOMICRMW_XCHG:
998 case TargetOpcode::G_ATOMICRMW_ADD:
999 case TargetOpcode::G_ATOMICRMW_SUB:
1000 case TargetOpcode::G_ATOMICRMW_AND:
1001 case TargetOpcode::G_ATOMICRMW_OR:
1002 case TargetOpcode::G_ATOMICRMW_XOR: {
1003 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
1004 RetRegs.push_back(Ret);
1005 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
1006 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
1007 Val =
1008 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
1009 .getReg(0);
1010 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
1011 Val =
1012 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
1013 .getReg(0);
1014 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
1015 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
1016 break;
1017 }
1018 default:
1019 llvm_unreachable("unsupported opcode");
1020 }
1021
1022 if (!Libcalls) // FIXME: Should be mandatory
1024
1025 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
1026 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
1027 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
1028
1029 // Unsupported libcall on the target.
1030 if (RTLibcallImpl == RTLIB::Unsupported) {
1031 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
1032 << MIRBuilder.getTII().getName(Opc) << "\n");
1034 }
1035
1037 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1038
1039 StringRef LibcallName =
1041 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1042 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1043
1044 llvm::append_range(Info.OrigArgs, Args);
1045 if (!CLI.lowerCall(MIRBuilder, Info))
1047
1049}
1050
1051static RTLIB::Libcall
1053 RTLIB::Libcall RTLibcall;
1054 switch (MI.getOpcode()) {
1055 case TargetOpcode::G_GET_FPENV:
1056 RTLibcall = RTLIB::FEGETENV;
1057 break;
1058 case TargetOpcode::G_SET_FPENV:
1059 case TargetOpcode::G_RESET_FPENV:
1060 RTLibcall = RTLIB::FESETENV;
1061 break;
1062 case TargetOpcode::G_GET_FPMODE:
1063 RTLibcall = RTLIB::FEGETMODE;
1064 break;
1065 case TargetOpcode::G_SET_FPMODE:
1066 case TargetOpcode::G_RESET_FPMODE:
1067 RTLibcall = RTLIB::FESETMODE;
1068 break;
1069 default:
1070 llvm_unreachable("Unexpected opcode");
1071 }
1072 return RTLibcall;
1073}
1074
1075// Some library functions that read FP state (fegetmode, fegetenv) write the
1076// state into a region in memory. IR intrinsics that do the same operations
1077// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1078// intrinsics via the library functions, we need to use temporary variable,
1079// for example:
1080//
1081// %0:_(s32) = G_GET_FPMODE
1082//
1083// is transformed to:
1084//
1085// %1:_(p0) = G_FRAME_INDEX %stack.0
1086// BL &fegetmode
1087// %0:_(s32) = G_LOAD % 1
1088//
1090LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1091 LostDebugLocObserver &LocObserver) {
1092 const DataLayout &DL = MIRBuilder.getDataLayout();
1093 auto &MF = MIRBuilder.getMF();
1094 auto &MRI = *MIRBuilder.getMRI();
1095 auto &Ctx = MF.getFunction().getContext();
1096
1097 // Create temporary, where library function will put the read state.
1098 Register Dst = MI.getOperand(0).getReg();
1099 LLT StateTy = MRI.getType(Dst);
1100 TypeSize StateSize = StateTy.getSizeInBytes();
1101 Align TempAlign = getStackTemporaryAlignment(StateTy);
1102 MachinePointerInfo TempPtrInfo;
1103 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1104
1105 // Create a call to library function, with the temporary as an argument.
1106 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1107 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1108 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1109 auto Res = createLibcall(
1110 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1111 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1112 nullptr);
1113 if (Res != LegalizerHelper::Legalized)
1114 return Res;
1115
1116 // Create a load from the temporary.
1117 MachineMemOperand *MMO = MF.getMachineMemOperand(
1118 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1119 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1120
1122}
1123
1124// Similar to `createGetStateLibcall` the function calls a library function
1125// using transient space in stack. In this case the library function reads
1126// content of memory region.
1128LegalizerHelper::createSetStateLibcall(MachineInstr &MI,
1129 LostDebugLocObserver &LocObserver) {
1130 const DataLayout &DL = MIRBuilder.getDataLayout();
1131 auto &MF = MIRBuilder.getMF();
1132 auto &MRI = *MIRBuilder.getMRI();
1133 auto &Ctx = MF.getFunction().getContext();
1134
1135 // Create temporary, where library function will get the new state.
1136 Register Src = MI.getOperand(0).getReg();
1137 LLT StateTy = MRI.getType(Src);
1138 TypeSize StateSize = StateTy.getSizeInBytes();
1139 Align TempAlign = getStackTemporaryAlignment(StateTy);
1140 MachinePointerInfo TempPtrInfo;
1141 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1142
1143 // Put the new state into the temporary.
1144 MachineMemOperand *MMO = MF.getMachineMemOperand(
1145 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1146 MIRBuilder.buildStore(Src, Temp, *MMO);
1147
1148 // Create a call to library function, with the temporary as an argument.
1149 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1150 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1151 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1152 return createLibcall(RTLibcall,
1153 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1154 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1155 LocObserver, nullptr);
1156}
1157
1158/// Returns the corresponding libcall for the given Pred and
1159/// the ICMP predicate that should be generated to compare with #0
1160/// after the libcall.
1161static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1163#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1164 do { \
1165 switch (Size) { \
1166 case 32: \
1167 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1168 case 64: \
1169 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1170 case 128: \
1171 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1172 default: \
1173 llvm_unreachable("unexpected size"); \
1174 } \
1175 } while (0)
1176
1177 // These use the three-way (-1/0/1) compare libcalls, whose result is tested
1178 // against 0 with a signed integer predicate. Unordered (UO) is a boolean.
1179 switch (Pred) {
1180 case CmpInst::FCMP_OEQ:
1181 RTLIBCASE_CMP(FCMP3_PRED_OEQ_F, CmpInst::ICMP_EQ);
1182 case CmpInst::FCMP_UNE:
1183 RTLIBCASE_CMP(FCMP3_PRED_UNE_F, CmpInst::ICMP_NE);
1184 case CmpInst::FCMP_OGE:
1185 RTLIBCASE_CMP(FCMP3_PRED_OGE_F, CmpInst::ICMP_SGE);
1186 case CmpInst::FCMP_OLT:
1187 RTLIBCASE_CMP(FCMP3_PRED_OLT_F, CmpInst::ICMP_SLT);
1188 case CmpInst::FCMP_OLE:
1189 RTLIBCASE_CMP(FCMP3_PRED_OLE_F, CmpInst::ICMP_SLE);
1190 case CmpInst::FCMP_OGT:
1191 RTLIBCASE_CMP(FCMP3_PRED_OGT_F, CmpInst::ICMP_SGT);
1192 case CmpInst::FCMP_UNO:
1194 default:
1195 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1196 }
1197}
1198
1200LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1201 LostDebugLocObserver &LocObserver) {
1202 auto &MF = MIRBuilder.getMF();
1203 auto &Ctx = MF.getFunction().getContext();
1204 const GFCmp *Cmp = cast<GFCmp>(&MI);
1205
1206 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1207 unsigned Size = OpLLT.getSizeInBits();
1208 if ((Size != 32 && Size != 64 && Size != 128) ||
1209 OpLLT != MRI.getType(Cmp->getRHSReg()))
1210 return UnableToLegalize;
1211
1212 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1213
1214 // DstReg type is s32
1215 const Register DstReg = Cmp->getReg(0);
1216 LLT DstTy = MRI.getType(DstReg);
1217 const auto Cond = Cmp->getCond();
1218 Type *RetTy = TLI.getCmpLibcallReturnType(Ctx);
1219
1220 // Reference:
1221 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1222 // Generates a libcall followed by ICMP.
1223 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1224 const CmpInst::Predicate ICmpPred,
1225 const DstOp &Res) -> Register {
1226 // FCMP libcall returns an integer, and needs an ICMP with #0.
1227 LLT TempLLT = LLT::integer(RetTy->getIntegerBitWidth());
1228 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1229 // Generate libcall, holding result in Temp
1230 const auto Status = createLibcall(
1231 Libcall, {Temp, RetTy, 0},
1232 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1233 LocObserver, &MI);
1234 if (Status != Legalized)
1235 return {};
1236
1237 // Compare temp with #0 to get the final result.
1238 return MIRBuilder
1239 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1240 .getReg(0);
1241 };
1242
1243 // Simple case if we have a direct mapping from predicate to libcall
1244 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1245 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1246 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1247 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1248 return Legalized;
1249 }
1250 return UnableToLegalize;
1251 }
1252
1253 // No direct mapping found, should be generated as combination of libcalls.
1254
1255 switch (Cond) {
1256 case CmpInst::FCMP_UEQ: {
1257 // FCMP_UEQ: unordered or equal
1258 // Convert into (FCMP_OEQ || FCMP_UNO).
1259
1260 const auto [OeqLibcall, OeqPred] =
1262 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1263
1264 const auto [UnoLibcall, UnoPred] =
1266 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1267 if (Oeq && Uno)
1268 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1269 else
1270 return UnableToLegalize;
1271
1272 break;
1273 }
1274 case CmpInst::FCMP_ONE: {
1275 // FCMP_ONE: ordered and operands are unequal
1276 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1277
1278 // We inverse the predicate instead of generating a NOT
1279 // to save one instruction.
1280 // On AArch64 isel can even select two cmp into a single ccmp.
1281 const auto [OeqLibcall, OeqPred] =
1283 const auto NotOeq =
1284 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1285
1286 const auto [UnoLibcall, UnoPred] =
1288 const auto NotUno =
1289 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1290
1291 if (NotOeq && NotUno)
1292 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1293 else
1294 return UnableToLegalize;
1295
1296 break;
1297 }
1298 case CmpInst::FCMP_ULT:
1299 case CmpInst::FCMP_UGE:
1300 case CmpInst::FCMP_UGT:
1301 case CmpInst::FCMP_ULE:
1302 case CmpInst::FCMP_ORD: {
1303 // Convert into: !(inverse(Pred))
1304 // E.g. FCMP_ULT becomes !FCMP_OGE
1305 // This is equivalent to the following, but saves some instructions.
1306 // MIRBuilder.buildNot(
1307 // PredTy,
1308 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1309 // Op1, Op2));
1310 const auto [InversedLibcall, InversedPred] =
1312 if (!BuildLibcall(InversedLibcall,
1313 CmpInst::getInversePredicate(InversedPred), DstReg))
1314 return UnableToLegalize;
1315 break;
1316 }
1317 default:
1318 return UnableToLegalize;
1319 }
1320
1321 return Legalized;
1322}
1323
1324// The function is used to legalize operations that set default environment
1325// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1326// On most targets supported in glibc FE_DFL_MODE is defined as
1327// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1328// it is not true, the target must provide custom lowering.
1330LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1331 LostDebugLocObserver &LocObserver) {
1332 const DataLayout &DL = MIRBuilder.getDataLayout();
1333 auto &MF = MIRBuilder.getMF();
1334 auto &Ctx = MF.getFunction().getContext();
1335
1336 // Create an argument for the library function.
1337 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1338 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1339 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1340 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1341 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1342 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1343 MIRBuilder.buildIntToPtr(Dest, DefValue);
1344
1345 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1346 return createLibcall(
1347 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1348 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1349}
1350
1353 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1354
1355 switch (MI.getOpcode()) {
1356 default:
1357 return UnableToLegalize;
1358 case TargetOpcode::G_MUL:
1359 case TargetOpcode::G_SDIV:
1360 case TargetOpcode::G_UDIV:
1361 case TargetOpcode::G_SREM:
1362 case TargetOpcode::G_UREM:
1363 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1364 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1365 unsigned Size = LLTy.getSizeInBits();
1366 Type *HLTy = IntegerType::get(Ctx, Size);
1367 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1368 if (Status != Legalized)
1369 return Status;
1370 break;
1371 }
1372 case TargetOpcode::G_FADD:
1373 case TargetOpcode::G_FSUB:
1374 case TargetOpcode::G_FMUL:
1375 case TargetOpcode::G_FDIV:
1376 case TargetOpcode::G_FMA:
1377 case TargetOpcode::G_FPOW:
1378 case TargetOpcode::G_FREM:
1379 case TargetOpcode::G_FCOS:
1380 case TargetOpcode::G_FSIN:
1381 case TargetOpcode::G_FTAN:
1382 case TargetOpcode::G_FACOS:
1383 case TargetOpcode::G_FASIN:
1384 case TargetOpcode::G_FATAN:
1385 case TargetOpcode::G_FATAN2:
1386 case TargetOpcode::G_FCOSH:
1387 case TargetOpcode::G_FSINH:
1388 case TargetOpcode::G_FTANH:
1389 case TargetOpcode::G_FLOG10:
1390 case TargetOpcode::G_FLOG:
1391 case TargetOpcode::G_FLOG2:
1392 case TargetOpcode::G_FEXP:
1393 case TargetOpcode::G_FEXP2:
1394 case TargetOpcode::G_FEXP10:
1395 case TargetOpcode::G_FCEIL:
1396 case TargetOpcode::G_FFLOOR:
1397 case TargetOpcode::G_FMINNUM:
1398 case TargetOpcode::G_FMAXNUM:
1399 case TargetOpcode::G_FMINIMUMNUM:
1400 case TargetOpcode::G_FMAXIMUMNUM:
1401 case TargetOpcode::G_FSQRT:
1402 case TargetOpcode::G_FRINT:
1403 case TargetOpcode::G_FNEARBYINT:
1404 case TargetOpcode::G_INTRINSIC_TRUNC:
1405 case TargetOpcode::G_INTRINSIC_ROUND:
1406 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1407 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1408 unsigned Size = LLTy.getSizeInBits();
1409 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1410 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1411 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1412 return UnableToLegalize;
1413 }
1414 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1415 if (Status != Legalized)
1416 return Status;
1417 break;
1418 }
1419 case TargetOpcode::G_FSINCOS: {
1420 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1421 unsigned Size = LLTy.getSizeInBits();
1422 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1423 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1424 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1425 return UnableToLegalize;
1426 }
1427 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1428 }
1429 case TargetOpcode::G_FMODF: {
1430 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1431 unsigned Size = LLTy.getSizeInBits();
1432 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1433 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1434 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1435 return UnableToLegalize;
1436 }
1437 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1438 }
1439 case TargetOpcode::G_LROUND:
1440 case TargetOpcode::G_LLROUND:
1441 case TargetOpcode::G_INTRINSIC_LRINT:
1442 case TargetOpcode::G_INTRINSIC_LLRINT: {
1443 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1444 unsigned Size = LLTy.getSizeInBits();
1445 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1446 Type *ITy = IntegerType::get(
1447 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1448 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1449 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1450 return UnableToLegalize;
1451 }
1452 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1454 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1455 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1456 if (Status != Legalized)
1457 return Status;
1458 MI.eraseFromParent();
1459 return Legalized;
1460 }
1461 case TargetOpcode::G_FPOWI:
1462 case TargetOpcode::G_FLDEXP: {
1463 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1464 unsigned Size = LLTy.getSizeInBits();
1465 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1466 Type *ITy = IntegerType::get(
1467 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1468 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1469 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1470 return UnableToLegalize;
1471 }
1472 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1474 {MI.getOperand(1).getReg(), HLTy, 0},
1475 {MI.getOperand(2).getReg(), ITy, 1}};
1476 Args[1].Flags[0].setSExt();
1478 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1479 if (Status != Legalized)
1480 return Status;
1481 break;
1482 }
1483 case TargetOpcode::G_FPEXT:
1484 case TargetOpcode::G_FPTRUNC: {
1485 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1486 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1487 if (!FromTy || !ToTy)
1488 return UnableToLegalize;
1489 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1490 if (Status != Legalized)
1491 return Status;
1492 break;
1493 }
1494 case TargetOpcode::G_FCMP: {
1495 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1496 if (Status != Legalized)
1497 return Status;
1498 MI.eraseFromParent();
1499 return Status;
1500 }
1501 case TargetOpcode::G_FPTOSI:
1502 case TargetOpcode::G_FPTOUI: {
1503 // FIXME: Support other types
1504 Type *FromTy =
1505 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1506 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1507 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1508 return UnableToLegalize;
1510 FromTy, LocObserver);
1511 if (Status != Legalized)
1512 return Status;
1513 break;
1514 }
1515 case TargetOpcode::G_SITOFP:
1516 case TargetOpcode::G_UITOFP: {
1517 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1518 Type *ToTy =
1519 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1520 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1521 return UnableToLegalize;
1522 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1524 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1525 if (Status != Legalized)
1526 return Status;
1527 break;
1528 }
1529 case TargetOpcode::G_ATOMICRMW_XCHG:
1530 case TargetOpcode::G_ATOMICRMW_ADD:
1531 case TargetOpcode::G_ATOMICRMW_SUB:
1532 case TargetOpcode::G_ATOMICRMW_AND:
1533 case TargetOpcode::G_ATOMICRMW_OR:
1534 case TargetOpcode::G_ATOMICRMW_XOR:
1535 case TargetOpcode::G_ATOMIC_CMPXCHG:
1536 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1538 if (Status != Legalized)
1539 return Status;
1540 break;
1541 }
1542 case TargetOpcode::G_BZERO:
1543 case TargetOpcode::G_MEMCPY:
1544 case TargetOpcode::G_MEMMOVE:
1545 case TargetOpcode::G_MEMSET: {
1546 LegalizeResult Result =
1547 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1548 if (Result != Legalized)
1549 return Result;
1550 MI.eraseFromParent();
1551 return Result;
1552 }
1553 case TargetOpcode::G_GET_FPENV:
1554 case TargetOpcode::G_GET_FPMODE: {
1555 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1556 if (Result != Legalized)
1557 return Result;
1558 break;
1559 }
1560 case TargetOpcode::G_SET_FPENV:
1561 case TargetOpcode::G_SET_FPMODE: {
1562 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1563 if (Result != Legalized)
1564 return Result;
1565 break;
1566 }
1567 case TargetOpcode::G_RESET_FPENV:
1568 case TargetOpcode::G_RESET_FPMODE: {
1569 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1570 if (Result != Legalized)
1571 return Result;
1572 break;
1573 }
1574 }
1575
1576 MI.eraseFromParent();
1577 return Legalized;
1578}
1579
1581 unsigned TypeIdx,
1582 LLT NarrowTy) {
1583 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1584 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1585
1586 switch (MI.getOpcode()) {
1587 default:
1588 return UnableToLegalize;
1589 case TargetOpcode::G_IMPLICIT_DEF: {
1590 Register DstReg = MI.getOperand(0).getReg();
1591 LLT DstTy = MRI.getType(DstReg);
1592
1593 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1594 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1595 // FIXME: Although this would also be legal for the general case, it causes
1596 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1597 // combines not being hit). This seems to be a problem related to the
1598 // artifact combiner.
1599 if (SizeOp0 % NarrowSize != 0) {
1600 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1601 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1602 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1603
1604 MI.eraseFromParent();
1605 return Legalized;
1606 }
1607
1608 int NumParts = SizeOp0 / NarrowSize;
1609
1611 for (int i = 0; i < NumParts; ++i)
1612 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1613
1614 if (DstTy.isVector())
1615 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1616 else
1617 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1618 MI.eraseFromParent();
1619 return Legalized;
1620 }
1621 case TargetOpcode::G_CONSTANT: {
1622 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1623 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1624 unsigned TotalSize = Ty.getSizeInBits();
1625 unsigned NarrowSize = NarrowTy.getSizeInBits();
1626 int NumParts = TotalSize / NarrowSize;
1627
1628 SmallVector<Register, 4> PartRegs;
1629 for (int I = 0; I != NumParts; ++I) {
1630 unsigned Offset = I * NarrowSize;
1631 auto K = MIRBuilder.buildConstant(NarrowTy,
1632 Val.lshr(Offset).trunc(NarrowSize));
1633 PartRegs.push_back(K.getReg(0));
1634 }
1635
1636 LLT LeftoverTy;
1637 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1638 SmallVector<Register, 1> LeftoverRegs;
1639 if (LeftoverBits != 0) {
1640 LeftoverTy = LLT::scalar(LeftoverBits);
1641 auto K = MIRBuilder.buildConstant(
1642 LeftoverTy,
1643 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1644 LeftoverRegs.push_back(K.getReg(0));
1645 }
1646
1647 insertParts(MI.getOperand(0).getReg(),
1648 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1649
1650 MI.eraseFromParent();
1651 return Legalized;
1652 }
1653 case TargetOpcode::G_SEXT:
1654 case TargetOpcode::G_ZEXT:
1655 case TargetOpcode::G_ANYEXT:
1656 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1657 case TargetOpcode::G_TRUNC: {
1658 if (TypeIdx != 1)
1659 return UnableToLegalize;
1660
1661 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1662 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1663 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1664 return UnableToLegalize;
1665 }
1666
1667 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1668 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1669 MI.eraseFromParent();
1670 return Legalized;
1671 }
1672 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1673 case TargetOpcode::G_FREEZE: {
1674 if (TypeIdx != 0)
1675 return UnableToLegalize;
1676
1677 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1678 // Should widen scalar first
1679 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1680 return UnableToLegalize;
1681
1682 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1684 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1685 Parts.push_back(
1686 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1687 .getReg(0));
1688 }
1689
1690 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1691 MI.eraseFromParent();
1692 return Legalized;
1693 }
1694 case TargetOpcode::G_ADD:
1695 case TargetOpcode::G_SUB:
1696 case TargetOpcode::G_SADDO:
1697 case TargetOpcode::G_SSUBO:
1698 case TargetOpcode::G_SADDE:
1699 case TargetOpcode::G_SSUBE:
1700 case TargetOpcode::G_UADDO:
1701 case TargetOpcode::G_USUBO:
1702 case TargetOpcode::G_UADDE:
1703 case TargetOpcode::G_USUBE:
1704 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1705 case TargetOpcode::G_MUL:
1706 case TargetOpcode::G_UMULH:
1707 case TargetOpcode::G_SMULH:
1708 return narrowScalarMul(MI, NarrowTy);
1709 case TargetOpcode::G_EXTRACT:
1710 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1711 case TargetOpcode::G_INSERT:
1712 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1713 case TargetOpcode::G_LOAD: {
1714 auto &LoadMI = cast<GLoad>(MI);
1715 Register DstReg = LoadMI.getDstReg();
1716 LLT DstTy = MRI.getType(DstReg);
1717 if (DstTy.isVector())
1718 return UnableToLegalize;
1719
1720 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1721 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1722 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1723 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1724 LoadMI.eraseFromParent();
1725 return Legalized;
1726 }
1727
1728 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1729 }
1730 case TargetOpcode::G_ZEXTLOAD:
1731 case TargetOpcode::G_SEXTLOAD:
1732 case TargetOpcode::G_FPEXTLOAD: {
1733 auto &LoadMI = cast<GExtLoad>(MI);
1734 Register DstReg = LoadMI.getDstReg();
1735 Register PtrReg = LoadMI.getPointerReg();
1736
1737 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1738 auto &MMO = LoadMI.getMMO();
1739 unsigned MemSize = MMO.getSizeInBits().getValue();
1740
1741 if (MemSize == NarrowSize) {
1742 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1743 } else if (MemSize < NarrowSize) {
1744 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1745 } else if (MemSize > NarrowSize) {
1746 // FIXME: Need to split the load.
1747 return UnableToLegalize;
1748 }
1749
1750 if (isa<GZExtLoad>(LoadMI))
1751 MIRBuilder.buildZExt(DstReg, TmpReg);
1752 else if (isa<GSExtLoad>(LoadMI))
1753 MIRBuilder.buildSExt(DstReg, TmpReg);
1754 else
1755 MIRBuilder.buildFPExt(DstReg, TmpReg);
1756
1757 LoadMI.eraseFromParent();
1758 return Legalized;
1759 }
1760 case TargetOpcode::G_STORE: {
1761 auto &StoreMI = cast<GStore>(MI);
1762
1763 Register SrcReg = StoreMI.getValueReg();
1764 LLT SrcTy = MRI.getType(SrcReg);
1765 if (SrcTy.isVector())
1766 return UnableToLegalize;
1767
1768 int NumParts = SizeOp0 / NarrowSize;
1769 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1770 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1771 if (SrcTy.isVector() && LeftoverBits != 0)
1772 return UnableToLegalize;
1773
1774 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1775 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1776 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1777 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1778 StoreMI.eraseFromParent();
1779 return Legalized;
1780 }
1781
1782 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1783 }
1784 case TargetOpcode::G_FPTRUNCSTORE: {
1785 auto &StoreMI = cast<GFPTruncStore>(MI);
1786 Register SrcReg = StoreMI.getValueReg();
1787 Register PtrReg = StoreMI.getPointerReg();
1788
1789 auto &MMO = StoreMI.getMMO();
1790 unsigned MemSize = MMO.getSizeInBits().getValue();
1791 if (MemSize > NarrowSize) {
1792 return UnableToLegalize;
1793 }
1794
1795 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1796 if (MemSize == NarrowSize) {
1797 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1798 } else if (MemSize < NarrowSize) {
1799 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1800 MMO);
1801 }
1802
1803 StoreMI.eraseFromParent();
1804 return Legalized;
1805 }
1806 case TargetOpcode::G_SELECT:
1807 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1808 case TargetOpcode::G_AND:
1809 case TargetOpcode::G_OR:
1810 case TargetOpcode::G_XOR: {
1811 // Legalize bitwise operation:
1812 // A = BinOp<Ty> B, C
1813 // into:
1814 // B1, ..., BN = G_UNMERGE_VALUES B
1815 // C1, ..., CN = G_UNMERGE_VALUES C
1816 // A1 = BinOp<Ty/N> B1, C2
1817 // ...
1818 // AN = BinOp<Ty/N> BN, CN
1819 // A = G_MERGE_VALUES A1, ..., AN
1820 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1821 }
1822 case TargetOpcode::G_SHL:
1823 case TargetOpcode::G_LSHR:
1824 case TargetOpcode::G_ASHR:
1825 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1826 case TargetOpcode::G_CTLZ:
1827 case TargetOpcode::G_CTLZ_ZERO_POISON:
1828 case TargetOpcode::G_CTTZ:
1829 case TargetOpcode::G_CTTZ_ZERO_POISON:
1830 case TargetOpcode::G_CTLS:
1831 case TargetOpcode::G_CTPOP:
1832 if (TypeIdx == 1)
1833 switch (MI.getOpcode()) {
1834 case TargetOpcode::G_CTLZ:
1835 case TargetOpcode::G_CTLZ_ZERO_POISON:
1836 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1837 case TargetOpcode::G_CTTZ:
1838 case TargetOpcode::G_CTTZ_ZERO_POISON:
1839 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1840 case TargetOpcode::G_CTPOP:
1841 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1842 case TargetOpcode::G_CTLS:
1843 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1844 default:
1845 return UnableToLegalize;
1846 }
1847
1848 Observer.changingInstr(MI);
1849 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1850 Observer.changedInstr(MI);
1851 return Legalized;
1852 case TargetOpcode::G_INTTOPTR:
1853 if (TypeIdx != 1)
1854 return UnableToLegalize;
1855
1856 Observer.changingInstr(MI);
1857 narrowScalarSrc(MI, NarrowTy, 1);
1858 Observer.changedInstr(MI);
1859 return Legalized;
1860 case TargetOpcode::G_PTRTOINT:
1861 if (TypeIdx != 0)
1862 return UnableToLegalize;
1863
1864 Observer.changingInstr(MI);
1865 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1866 Observer.changedInstr(MI);
1867 return Legalized;
1868 case TargetOpcode::G_PHI: {
1869 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1870 // NarrowSize.
1871 if (SizeOp0 % NarrowSize != 0)
1872 return UnableToLegalize;
1873
1874 unsigned NumParts = SizeOp0 / NarrowSize;
1876 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1877 Observer.changingInstr(MI);
1878 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1879 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1880 MIRBuilder.setInsertPt(OpMBB, getPHIIncomingInsertPoint(
1881 OpMBB, MI.getOperand(i).getReg(), MRI));
1882 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1883 SrcRegs[i / 2], MIRBuilder, MRI);
1884 }
1885 MachineBasicBlock &MBB = *MI.getParent();
1886 MIRBuilder.setInsertPt(MBB, MI);
1887 for (unsigned i = 0; i < NumParts; ++i) {
1888 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1890 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1891 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1892 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1893 }
1894 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1895 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1896 Observer.changedInstr(MI);
1897 MI.eraseFromParent();
1898 return Legalized;
1899 }
1900 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1901 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1902 if (TypeIdx != 2)
1903 return UnableToLegalize;
1904
1905 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1906 Observer.changingInstr(MI);
1907 narrowScalarSrc(MI, NarrowTy, OpIdx);
1908 Observer.changedInstr(MI);
1909 return Legalized;
1910 }
1911 case TargetOpcode::G_ICMP: {
1912 Register LHS = MI.getOperand(2).getReg();
1913 LLT SrcTy = MRI.getType(LHS);
1914 CmpInst::Predicate Pred =
1915 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1916
1917 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1918 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1919 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1920 LHSLeftoverRegs, MIRBuilder, MRI))
1921 return UnableToLegalize;
1922
1923 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1924 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1925 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1926 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1927 return UnableToLegalize;
1928
1929 // We now have the LHS and RHS of the compare split into narrow-type
1930 // registers, plus potentially some leftover type.
1931 Register Dst = MI.getOperand(0).getReg();
1932 LLT ResTy = MRI.getType(Dst);
1933 if (ICmpInst::isEquality(Pred)) {
1934 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1935 // them together. For each equal part, the result should be all 0s. For
1936 // each non-equal part, we'll get at least one 1.
1937 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1939 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1940 auto LHS = std::get<0>(LHSAndRHS);
1941 auto RHS = std::get<1>(LHSAndRHS);
1942 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1943 Xors.push_back(Xor);
1944 }
1945
1946 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1947 // to the desired narrow type so that we can OR them together later.
1948 SmallVector<Register, 4> WidenedXors;
1949 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1950 auto LHS = std::get<0>(LHSAndRHS);
1951 auto RHS = std::get<1>(LHSAndRHS);
1952 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1953 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1954 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1955 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1956 llvm::append_range(Xors, WidenedXors);
1957 }
1958
1959 // Now, for each part we broke up, we know if they are equal/not equal
1960 // based off the G_XOR. We can OR these all together and compare against
1961 // 0 to get the result.
1962 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1963 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1964 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1965 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1966 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1967 } else {
1968 Register CmpIn;
1969 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1970 Register CmpOut;
1971 CmpInst::Predicate PartPred;
1972
1973 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1974 PartPred = Pred;
1975 CmpOut = Dst;
1976 } else {
1977 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1978 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1979 }
1980
1981 if (!CmpIn) {
1982 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1983 RHSPartRegs[I]);
1984 } else {
1985 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1986 RHSPartRegs[I]);
1987 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1988 LHSPartRegs[I], RHSPartRegs[I]);
1989 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1990 }
1991
1992 CmpIn = CmpOut;
1993 }
1994
1995 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1996 Register CmpOut;
1997 CmpInst::Predicate PartPred;
1998
1999 if (I == E - 1) {
2000 PartPred = Pred;
2001 CmpOut = Dst;
2002 } else {
2003 PartPred = ICmpInst::getUnsignedPredicate(Pred);
2004 CmpOut = MRI.createGenericVirtualRegister(ResTy);
2005 }
2006
2007 if (!CmpIn) {
2008 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
2009 RHSLeftoverRegs[I]);
2010 } else {
2011 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
2012 RHSLeftoverRegs[I]);
2013 auto CmpEq =
2014 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
2015 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
2016 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
2017 }
2018
2019 CmpIn = CmpOut;
2020 }
2021 }
2022 MI.eraseFromParent();
2023 return Legalized;
2024 }
2025 case TargetOpcode::G_FCMP:
2026 if (TypeIdx != 0)
2027 return UnableToLegalize;
2028
2029 Observer.changingInstr(MI);
2030 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
2031 Observer.changedInstr(MI);
2032 return Legalized;
2033
2034 case TargetOpcode::G_SEXT_INREG: {
2035 if (TypeIdx != 0)
2036 return UnableToLegalize;
2037
2038 int64_t SizeInBits = MI.getOperand(2).getImm();
2039
2040 // So long as the new type has more bits than the bits we're extending we
2041 // don't need to break it apart.
2042 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2043 Observer.changingInstr(MI);
2044 // We don't lose any non-extension bits by truncating the src and
2045 // sign-extending the dst.
2046 MachineOperand &MO1 = MI.getOperand(1);
2047 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2048 MO1.setReg(TruncMIB.getReg(0));
2049
2050 MachineOperand &MO2 = MI.getOperand(0);
2051 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2052 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2053 MIRBuilder.buildSExt(MO2, DstExt);
2054 MO2.setReg(DstExt);
2055 Observer.changedInstr(MI);
2056 return Legalized;
2057 }
2058
2059 // Break it apart. Components below the extension point are unmodified. The
2060 // component containing the extension point becomes a narrower SEXT_INREG.
2061 // Components above it are ashr'd from the component containing the
2062 // extension point.
2063 if (SizeOp0 % NarrowSize != 0)
2064 return UnableToLegalize;
2065 int NumParts = SizeOp0 / NarrowSize;
2066
2067 // List the registers where the destination will be scattered.
2069 // List the registers where the source will be split.
2071
2072 // Create all the temporary registers.
2073 for (int i = 0; i < NumParts; ++i) {
2074 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2075
2076 SrcRegs.push_back(SrcReg);
2077 }
2078
2079 // Explode the big arguments into smaller chunks.
2080 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2081
2082 Register AshrCstReg =
2083 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2084 .getReg(0);
2085 Register FullExtensionReg;
2086 Register PartialExtensionReg;
2087
2088 // Do the operation on each small part.
2089 for (int i = 0; i < NumParts; ++i) {
2090 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2091 DstRegs.push_back(SrcRegs[i]);
2092 PartialExtensionReg = DstRegs.back();
2093 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2094 assert(PartialExtensionReg &&
2095 "Expected to visit partial extension before full");
2096 if (FullExtensionReg) {
2097 DstRegs.push_back(FullExtensionReg);
2098 continue;
2099 }
2100 DstRegs.push_back(
2101 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2102 .getReg(0));
2103 FullExtensionReg = DstRegs.back();
2104 } else {
2105 DstRegs.push_back(
2107 .buildInstr(
2108 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2109 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2110 .getReg(0));
2111 PartialExtensionReg = DstRegs.back();
2112 }
2113 }
2114
2115 // Gather the destination registers into the final destination.
2116 Register DstReg = MI.getOperand(0).getReg();
2117 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2118 MI.eraseFromParent();
2119 return Legalized;
2120 }
2121 case TargetOpcode::G_BSWAP:
2122 case TargetOpcode::G_BITREVERSE: {
2123 if (SizeOp0 % NarrowSize != 0)
2124 return UnableToLegalize;
2125
2126 Observer.changingInstr(MI);
2127 SmallVector<Register, 2> SrcRegs, DstRegs;
2128 unsigned NumParts = SizeOp0 / NarrowSize;
2129 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2130 MIRBuilder, MRI);
2131
2132 for (unsigned i = 0; i < NumParts; ++i) {
2133 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2134 {SrcRegs[NumParts - 1 - i]});
2135 DstRegs.push_back(DstPart.getReg(0));
2136 }
2137
2138 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2139
2140 Observer.changedInstr(MI);
2141 MI.eraseFromParent();
2142 return Legalized;
2143 }
2144 case TargetOpcode::G_PTR_ADD:
2145 case TargetOpcode::G_PTRMASK: {
2146 if (TypeIdx != 1)
2147 return UnableToLegalize;
2148 Observer.changingInstr(MI);
2149 narrowScalarSrc(MI, NarrowTy, 2);
2150 Observer.changedInstr(MI);
2151 return Legalized;
2152 }
2153 case TargetOpcode::G_FPTOUI:
2154 case TargetOpcode::G_FPTOSI:
2155 case TargetOpcode::G_FPTOUI_SAT:
2156 case TargetOpcode::G_FPTOSI_SAT:
2157 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2158 case TargetOpcode::G_FPEXT:
2159 if (TypeIdx != 0)
2160 return UnableToLegalize;
2161 Observer.changingInstr(MI);
2162 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2163 Observer.changedInstr(MI);
2164 return Legalized;
2165 case TargetOpcode::G_FLDEXP:
2166 case TargetOpcode::G_STRICT_FLDEXP:
2167 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2168 case TargetOpcode::G_VSCALE: {
2169 Register Dst = MI.getOperand(0).getReg();
2170 LLT Ty = MRI.getType(Dst);
2171
2172 // Assume VSCALE(1) fits into a legal integer
2173 const APInt One(NarrowTy.getSizeInBits(), 1);
2174 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2175 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2176 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2177 MIRBuilder.buildMul(Dst, ZExt, C);
2178
2179 MI.eraseFromParent();
2180 return Legalized;
2181 }
2182 }
2183}
2184
2186 LLT Ty = MRI.getType(Val);
2187 if (Ty.isScalar() && !Ty.isFloat())
2188 return Val;
2189
2190 const DataLayout &DL = MIRBuilder.getDataLayout();
2191 LLT NewTy = LLT::integer(Ty.getSizeInBits());
2192
2193 if (Ty.isFloat())
2194 return MIRBuilder.buildBitcast(NewTy, Val).getReg(0);
2195
2196 if (Ty.isPointer()) {
2197 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2198 return Register();
2199 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2200 }
2201
2202 Register NewVal = Val;
2203
2204 assert(Ty.isVector());
2205 if (Ty.isPointerVector())
2206 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2207 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2208}
2209
2211 unsigned OpIdx, unsigned ExtOpcode) {
2212 MachineOperand &MO = MI.getOperand(OpIdx);
2213 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2214 MO.setReg(ExtB.getReg(0));
2215}
2216
2218 unsigned OpIdx) {
2219 MachineOperand &MO = MI.getOperand(OpIdx);
2220 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2221 MI.getFlags());
2222 MO.setReg(ExtB.getReg(0));
2223}
2224
2226 unsigned OpIdx) {
2227 MachineOperand &MO = MI.getOperand(OpIdx);
2228 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2229 MO.setReg(ExtB.getReg(0));
2230}
2231
2233 unsigned OpIdx, unsigned TruncOpcode) {
2234 MachineOperand &MO = MI.getOperand(OpIdx);
2235 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2236 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2237 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2238 MO.setReg(DstExt);
2239}
2240
2242 unsigned OpIdx) {
2243 MachineOperand &MO = MI.getOperand(OpIdx);
2244 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2245 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2246 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2247 MO.setReg(DstExt);
2248}
2249
2251 unsigned OpIdx, unsigned ExtOpcode) {
2252 MachineOperand &MO = MI.getOperand(OpIdx);
2253 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2254 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2255 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2256 MO.setReg(DstTrunc);
2257}
2258
2260 unsigned OpIdx) {
2261 MachineOperand &MO = MI.getOperand(OpIdx);
2262 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2263 Register Dst = MO.getReg();
2264 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2265 MO.setReg(DstExt);
2266 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2267}
2268
2270 unsigned OpIdx) {
2271 MachineOperand &MO = MI.getOperand(OpIdx);
2272 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2273}
2274
2275void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2276 MachineOperand &Op = MI.getOperand(OpIdx);
2277 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2278}
2279
2280void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2281 MachineOperand &MO = MI.getOperand(OpIdx);
2282 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2283 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2284 MIRBuilder.buildBitcast(MO, CastDst);
2285 MO.setReg(CastDst);
2286}
2287
2289LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2290 LLT WideTy) {
2291 if (TypeIdx != 1)
2292 return UnableToLegalize;
2293
2294 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2295 if (DstTy.isVector())
2296 return UnableToLegalize;
2297
2298 LLT SrcTy = MRI.getType(Src1Reg);
2299 const int DstSize = DstTy.getSizeInBits();
2300 const int SrcSize = SrcTy.getSizeInBits();
2301 const int WideSize = WideTy.getSizeInBits();
2302 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2303
2304 unsigned NumOps = MI.getNumOperands();
2305 unsigned NumSrc = MI.getNumOperands() - 1;
2306 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2307
2308 if (WideSize >= DstSize) {
2309 // Directly pack the bits in the target type.
2310 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2311
2312 for (unsigned I = 2; I != NumOps; ++I) {
2313 const unsigned Offset = (I - 1) * PartSize;
2314
2315 Register SrcReg = MI.getOperand(I).getReg();
2316 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2317
2318 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2319
2320 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2321 MRI.createGenericVirtualRegister(WideTy);
2322
2323 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2324 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2325 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2326 ResultReg = NextResult;
2327 }
2328
2329 if (WideSize > DstSize)
2330 MIRBuilder.buildTrunc(DstReg, ResultReg);
2331 else if (DstTy.isPointer())
2332 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2333 else if (DstTy != WideTy)
2334 MIRBuilder.buildBitcast(DstReg, ResultReg);
2335
2336 MI.eraseFromParent();
2337 return Legalized;
2338 }
2339
2340 // Unmerge the original values to the GCD type, and recombine to the next
2341 // multiple greater than the original type.
2342 //
2343 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2344 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2345 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2346 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2347 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2348 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2349 // %12:_(s12) = G_MERGE_VALUES %10, %11
2350 //
2351 // Padding with undef if necessary:
2352 //
2353 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2354 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2355 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2356 // %7:_(s2) = G_IMPLICIT_DEF
2357 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2358 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2359 // %10:_(s12) = G_MERGE_VALUES %8, %9
2360
2361 const int GCD = std::gcd(SrcSize, WideSize);
2362 LLT GCDTy = WideTy.changeElementSize(GCD);
2363
2364 SmallVector<Register, 8> NewMergeRegs;
2365 SmallVector<Register, 8> Unmerges;
2366 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2367
2368 // Decompose the original operands if they don't evenly divide.
2369 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2370 Register SrcReg = MO.getReg();
2371 if (GCD == SrcSize) {
2372 Unmerges.push_back(SrcReg);
2373 } else {
2374 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2375 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2376 Unmerges.push_back(Unmerge.getReg(J));
2377 }
2378 }
2379
2380 // Pad with undef to the next size that is a multiple of the requested size.
2381 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2382 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2383 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2384 Unmerges.push_back(UndefReg);
2385 }
2386
2387 const int PartsPerGCD = WideSize / GCD;
2388
2389 // Build merges of each piece.
2390 ArrayRef<Register> Slicer(Unmerges);
2391 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2392 auto Merge =
2393 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2394 NewMergeRegs.push_back(Merge.getReg(0));
2395 }
2396
2397 // A truncate may be necessary if the requested type doesn't evenly divide the
2398 // original result type.
2399 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2400 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2401 } else {
2402 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2403 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2404 }
2405
2406 MI.eraseFromParent();
2407 return Legalized;
2408}
2409
2411LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2412 LLT WideTy) {
2413 if (TypeIdx != 0)
2414 return UnableToLegalize;
2415
2416 int NumDst = MI.getNumOperands() - 1;
2417 Register SrcReg = MI.getOperand(NumDst).getReg();
2418 LLT SrcTy = MRI.getType(SrcReg);
2419 if (SrcTy.isVector())
2420 return UnableToLegalize;
2421
2422 Register Dst0Reg = MI.getOperand(0).getReg();
2423 LLT DstTy = MRI.getType(Dst0Reg);
2424 if (!DstTy.isScalar())
2425 return UnableToLegalize;
2426
2427 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2428 if (SrcTy.isPointer()) {
2429 const DataLayout &DL = MIRBuilder.getDataLayout();
2430 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2431 LLVM_DEBUG(
2432 dbgs() << "Not casting non-integral address space integer\n");
2433 return UnableToLegalize;
2434 }
2435
2436 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2437 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2438 }
2439
2440 // Widen SrcTy to WideTy. This does not affect the result, but since the
2441 // user requested this size, it is probably better handled than SrcTy and
2442 // should reduce the total number of legalization artifacts.
2443 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2444 SrcTy = WideTy;
2445 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2446 }
2447
2448 // Theres no unmerge type to target. Directly extract the bits from the
2449 // source type
2450 unsigned DstSize = DstTy.getSizeInBits();
2451
2452 if (SrcTy.isFloat()) {
2453 SrcReg = coerceToInteger(SrcReg);
2454 SrcTy = MRI.getType(SrcReg);
2455 }
2456
2457 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2458 for (int I = 1; I != NumDst; ++I) {
2459 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2460 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2461 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2462 }
2463
2464 MI.eraseFromParent();
2465 return Legalized;
2466 }
2467
2468 // Extend the source to a wider type.
2469 LLT LCMTy = getLCMType(SrcTy, WideTy);
2470
2471 Register WideSrc = SrcReg;
2472 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2473 // TODO: If this is an integral address space, cast to integer and anyext.
2474 if (SrcTy.isPointer()) {
2475 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2476 return UnableToLegalize;
2477 }
2478
2479 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2480 }
2481
2482 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2483
2484 // Create a sequence of unmerges and merges to the original results. Since we
2485 // may have widened the source, we will need to pad the results with dead defs
2486 // to cover the source register.
2487 // e.g. widen s48 to s64:
2488 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2489 //
2490 // =>
2491 // %4:_(s192) = G_ANYEXT %0:_(s96)
2492 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2493 // ; unpack to GCD type, with extra dead defs
2494 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2495 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2496 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2497 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2498 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2499 const LLT GCDTy = getGCDType(WideTy, DstTy);
2500 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2501 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2502
2503 // Directly unmerge to the destination without going through a GCD type
2504 // if possible
2505 if (PartsPerRemerge == 1) {
2506 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2507
2508 for (int I = 0; I != NumUnmerge; ++I) {
2509 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2510
2511 for (int J = 0; J != PartsPerUnmerge; ++J) {
2512 int Idx = I * PartsPerUnmerge + J;
2513 if (Idx < NumDst)
2514 MIB.addDef(MI.getOperand(Idx).getReg());
2515 else {
2516 // Create dead def for excess components.
2517 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2518 }
2519 }
2520
2521 MIB.addUse(Unmerge.getReg(I));
2522 }
2523 } else {
2524 SmallVector<Register, 16> Parts;
2525 for (int J = 0; J != NumUnmerge; ++J)
2526 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2527
2528 SmallVector<Register, 8> RemergeParts;
2529 for (int I = 0; I != NumDst; ++I) {
2530 for (int J = 0; J < PartsPerRemerge; ++J) {
2531 const int Idx = I * PartsPerRemerge + J;
2532 RemergeParts.emplace_back(Parts[Idx]);
2533 }
2534
2535 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2536 RemergeParts.clear();
2537 }
2538 }
2539
2540 MI.eraseFromParent();
2541 return Legalized;
2542}
2543
2545LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2546 LLT WideTy) {
2547 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2548 unsigned Offset = MI.getOperand(2).getImm();
2549
2550 if (TypeIdx == 0) {
2551 if (SrcTy.isVector() || DstTy.isVector())
2552 return UnableToLegalize;
2553
2554 SrcOp Src(SrcReg);
2555 if (SrcTy.isPointer()) {
2556 // Extracts from pointers can be handled only if they are really just
2557 // simple integers.
2558 const DataLayout &DL = MIRBuilder.getDataLayout();
2559 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2560 return UnableToLegalize;
2561
2562 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2563 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2564 SrcTy = SrcAsIntTy;
2565 }
2566
2567 if (DstTy.isPointer())
2568 return UnableToLegalize;
2569
2570 if (Offset == 0) {
2571 // Avoid a shift in the degenerate case.
2572 MIRBuilder.buildTrunc(DstReg,
2573 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2574 MI.eraseFromParent();
2575 return Legalized;
2576 }
2577
2578 // Do a shift in the source type.
2579 LLT ShiftTy = SrcTy;
2580 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2581 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2582 ShiftTy = WideTy;
2583 }
2584
2585 auto LShr = MIRBuilder.buildLShr(
2586 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2587 MIRBuilder.buildTrunc(DstReg, LShr);
2588 MI.eraseFromParent();
2589 return Legalized;
2590 }
2591
2592 if (SrcTy.isScalar()) {
2593 Observer.changingInstr(MI);
2594 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2595 Observer.changedInstr(MI);
2596 return Legalized;
2597 }
2598
2599 if (!SrcTy.isVector())
2600 return UnableToLegalize;
2601
2602 if (DstTy != SrcTy.getElementType())
2603 return UnableToLegalize;
2604
2605 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2606 return UnableToLegalize;
2607
2608 Observer.changingInstr(MI);
2609 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2610
2611 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2612 Offset);
2613 widenScalarDst(MI, WideTy.getScalarType(), 0);
2614 Observer.changedInstr(MI);
2615 return Legalized;
2616}
2617
2619LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2620 LLT WideTy) {
2621 if (TypeIdx != 0 || WideTy.isVector())
2622 return UnableToLegalize;
2623 Observer.changingInstr(MI);
2624 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2625 widenScalarDst(MI, WideTy);
2626 Observer.changedInstr(MI);
2627 return Legalized;
2628}
2629
2631LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2632 LLT WideTy) {
2633 unsigned Opcode;
2634 unsigned ExtOpcode;
2635 std::optional<Register> CarryIn;
2636 switch (MI.getOpcode()) {
2637 default:
2638 llvm_unreachable("Unexpected opcode!");
2639 case TargetOpcode::G_SADDO:
2640 Opcode = TargetOpcode::G_ADD;
2641 ExtOpcode = TargetOpcode::G_SEXT;
2642 break;
2643 case TargetOpcode::G_SSUBO:
2644 Opcode = TargetOpcode::G_SUB;
2645 ExtOpcode = TargetOpcode::G_SEXT;
2646 break;
2647 case TargetOpcode::G_UADDO:
2648 Opcode = TargetOpcode::G_ADD;
2649 ExtOpcode = TargetOpcode::G_ZEXT;
2650 break;
2651 case TargetOpcode::G_USUBO:
2652 Opcode = TargetOpcode::G_SUB;
2653 ExtOpcode = TargetOpcode::G_ZEXT;
2654 break;
2655 case TargetOpcode::G_SADDE:
2656 Opcode = TargetOpcode::G_UADDE;
2657 ExtOpcode = TargetOpcode::G_SEXT;
2658 CarryIn = MI.getOperand(4).getReg();
2659 break;
2660 case TargetOpcode::G_SSUBE:
2661 Opcode = TargetOpcode::G_USUBE;
2662 ExtOpcode = TargetOpcode::G_SEXT;
2663 CarryIn = MI.getOperand(4).getReg();
2664 break;
2665 case TargetOpcode::G_UADDE:
2666 Opcode = TargetOpcode::G_UADDE;
2667 ExtOpcode = TargetOpcode::G_ZEXT;
2668 CarryIn = MI.getOperand(4).getReg();
2669 break;
2670 case TargetOpcode::G_USUBE:
2671 Opcode = TargetOpcode::G_USUBE;
2672 ExtOpcode = TargetOpcode::G_ZEXT;
2673 CarryIn = MI.getOperand(4).getReg();
2674 break;
2675 }
2676
2677 if (TypeIdx == 1) {
2678 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2679
2680 Observer.changingInstr(MI);
2681 if (CarryIn)
2682 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2683 widenScalarDst(MI, WideTy, 1);
2684
2685 Observer.changedInstr(MI);
2686 return Legalized;
2687 }
2688
2689 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2690 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2691 // Do the arithmetic in the larger type.
2692 Register NewOp;
2693 if (CarryIn) {
2694 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2695 NewOp = MIRBuilder
2696 .buildInstr(Opcode, {WideTy, CarryOutTy},
2697 {LHSExt, RHSExt, *CarryIn})
2698 .getReg(0);
2699 } else {
2700 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2701 }
2702 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2703 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2704 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2705 // There is no overflow if the ExtOp is the same as NewOp.
2706 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2707 // Now trunc the NewOp to the original result.
2708 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2709 MI.eraseFromParent();
2710 return Legalized;
2711}
2712
2714LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2715 LLT WideTy) {
2716 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2717 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2718 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2719 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2720 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2721 // We can convert this to:
2722 // 1. Any extend iN to iM
2723 // 2. SHL by M-N
2724 // 3. [US][ADD|SUB|SHL]SAT
2725 // 4. L/ASHR by M-N
2726 //
2727 // It may be more efficient to lower this to a min and a max operation in
2728 // the higher precision arithmetic if the promoted operation isn't legal,
2729 // but this decision is up to the target's lowering request.
2730 Register DstReg = MI.getOperand(0).getReg();
2731
2732 unsigned NewBits = WideTy.getScalarSizeInBits();
2733 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2734
2735 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2736 // must not left shift the RHS to preserve the shift amount.
2737 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2738 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2739 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2740 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2741 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2742 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2743
2744 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2745 {ShiftL, ShiftR}, MI.getFlags());
2746
2747 // Use a shift that will preserve the number of sign bits when the trunc is
2748 // folded away.
2749 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2750 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2751
2752 MIRBuilder.buildTrunc(DstReg, Result);
2753 MI.eraseFromParent();
2754 return Legalized;
2755}
2756
2758LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2759 LLT WideTy) {
2760 if (TypeIdx == 1) {
2761 Observer.changingInstr(MI);
2762 widenScalarDst(MI, WideTy, 1);
2763 Observer.changedInstr(MI);
2764 return Legalized;
2765 }
2766
2767 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2768 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2769 LLT SrcTy = MRI.getType(LHS);
2770 LLT OverflowTy = MRI.getType(OriginalOverflow);
2771 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2772
2773 // To determine if the result overflowed in the larger type, we extend the
2774 // input to the larger type, do the multiply (checking if it overflows),
2775 // then also check the high bits of the result to see if overflow happened
2776 // there.
2777 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2778 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2779 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2780
2781 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2782 // so we don't need to check the overflow result of larger type Mulo.
2783 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2784
2785 unsigned MulOpc =
2786 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2787
2788 MachineInstrBuilder Mulo;
2789 if (WideMulCanOverflow)
2790 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2791 {LeftOperand, RightOperand});
2792 else
2793 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2794
2795 auto Mul = Mulo->getOperand(0);
2796 MIRBuilder.buildTrunc(Result, Mul);
2797
2798 MachineInstrBuilder ExtResult;
2799 // Overflow occurred if it occurred in the larger type, or if the high part
2800 // of the result does not zero/sign-extend the low part. Check this second
2801 // possibility first.
2802 if (IsSigned) {
2803 // For signed, overflow occurred when the high part does not sign-extend
2804 // the low part.
2805 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2806 } else {
2807 // Unsigned overflow occurred when the high part does not zero-extend the
2808 // low part.
2809 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2810 }
2811
2812 if (WideMulCanOverflow) {
2813 auto Overflow =
2814 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2815 // Finally check if the multiplication in the larger type itself overflowed.
2816 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2817 } else {
2818 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2819 }
2820 MI.eraseFromParent();
2821 return Legalized;
2822}
2823
2826 unsigned Opcode = MI.getOpcode();
2827 switch (Opcode) {
2828 default:
2829 return UnableToLegalize;
2830 case TargetOpcode::G_ATOMICRMW_XCHG:
2831 case TargetOpcode::G_ATOMICRMW_ADD:
2832 case TargetOpcode::G_ATOMICRMW_SUB:
2833 case TargetOpcode::G_ATOMICRMW_AND:
2834 case TargetOpcode::G_ATOMICRMW_OR:
2835 case TargetOpcode::G_ATOMICRMW_XOR:
2836 case TargetOpcode::G_ATOMICRMW_MIN:
2837 case TargetOpcode::G_ATOMICRMW_MAX:
2838 case TargetOpcode::G_ATOMICRMW_UMIN:
2839 case TargetOpcode::G_ATOMICRMW_UMAX:
2840 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2841 Observer.changingInstr(MI);
2842 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2843 widenScalarDst(MI, WideTy, 0);
2844 Observer.changedInstr(MI);
2845 return Legalized;
2846 case TargetOpcode::G_ATOMIC_CMPXCHG:
2847 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2848 Observer.changingInstr(MI);
2849 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2850 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2851 widenScalarDst(MI, WideTy, 0);
2852 Observer.changedInstr(MI);
2853 return Legalized;
2854 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2855 if (TypeIdx == 0) {
2856 Observer.changingInstr(MI);
2857 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2858 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2859 widenScalarDst(MI, WideTy, 0);
2860 Observer.changedInstr(MI);
2861 return Legalized;
2862 }
2863 assert(TypeIdx == 1 &&
2864 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2865 Observer.changingInstr(MI);
2866 widenScalarDst(MI, WideTy, 1);
2867 Observer.changedInstr(MI);
2868 return Legalized;
2869 case TargetOpcode::G_EXTRACT:
2870 return widenScalarExtract(MI, TypeIdx, WideTy);
2871 case TargetOpcode::G_INSERT:
2872 return widenScalarInsert(MI, TypeIdx, WideTy);
2873 case TargetOpcode::G_MERGE_VALUES:
2874 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2875 case TargetOpcode::G_UNMERGE_VALUES:
2876 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2877 case TargetOpcode::G_SADDO:
2878 case TargetOpcode::G_SSUBO:
2879 case TargetOpcode::G_UADDO:
2880 case TargetOpcode::G_USUBO:
2881 case TargetOpcode::G_SADDE:
2882 case TargetOpcode::G_SSUBE:
2883 case TargetOpcode::G_UADDE:
2884 case TargetOpcode::G_USUBE:
2885 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2886 case TargetOpcode::G_UMULO:
2887 case TargetOpcode::G_SMULO:
2888 return widenScalarMulo(MI, TypeIdx, WideTy);
2889 case TargetOpcode::G_SADDSAT:
2890 case TargetOpcode::G_SSUBSAT:
2891 case TargetOpcode::G_SSHLSAT:
2892 case TargetOpcode::G_UADDSAT:
2893 case TargetOpcode::G_USUBSAT:
2894 case TargetOpcode::G_USHLSAT:
2895 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2896 case TargetOpcode::G_CTTZ:
2897 case TargetOpcode::G_CTTZ_ZERO_POISON:
2898 case TargetOpcode::G_CTLZ:
2899 case TargetOpcode::G_CTLZ_ZERO_POISON:
2900 case TargetOpcode::G_CTLS:
2901 case TargetOpcode::G_CTPOP: {
2902 if (TypeIdx == 0) {
2903 Observer.changingInstr(MI);
2904 widenScalarDst(MI, WideTy, 0);
2905 Observer.changedInstr(MI);
2906 return Legalized;
2907 }
2908
2909 Register SrcReg = MI.getOperand(1).getReg();
2910
2911 // First extend the input.
2912 unsigned ExtOpc;
2913 switch (Opcode) {
2914 case TargetOpcode::G_CTTZ:
2915 case TargetOpcode::G_CTTZ_ZERO_POISON:
2916 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2917 ExtOpc = TargetOpcode::G_ANYEXT;
2918 break;
2919 case TargetOpcode::G_CTLS:
2920 ExtOpc = TargetOpcode::G_SEXT;
2921 break;
2922 default:
2923 ExtOpc = TargetOpcode::G_ZEXT;
2924 }
2925
2926 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2927 LLT CurTy = MRI.getType(SrcReg);
2928 unsigned NewOpc = Opcode;
2929 if (NewOpc == TargetOpcode::G_CTTZ) {
2930 // The count is the same in the larger type except if the original
2931 // value was zero. This can be handled by setting the bit just off
2932 // the top of the original type.
2933 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2934 CurTy.getScalarSizeInBits());
2935 MIBSrc = MIRBuilder.buildOr(
2936 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2937 // Now we know the operand is non-zero, use the more relaxed opcode.
2938 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2939 }
2940
2941 unsigned SizeDiff =
2942 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2943
2944 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2945 // An optimization where the result is the CTLZ after the left shift by
2946 // (Difference in widety and current ty), that is,
2947 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2948 // Result = ctlz MIBSrc
2949 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2950 MIRBuilder.buildConstant(WideTy, SizeDiff));
2951 }
2952
2953 // Perform the operation at the larger size.
2954 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2955 // This is already the correct result for CTPOP and CTTZs
2956 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2957 // The correct result is NewOp - (Difference in widety and current ty).
2958 // At this stage SUB is guaranteed to be positive no-wrap,
2959 // that to be used in further KnownBits optimizations for CTLZ.
2960 MIBNewOp = MIRBuilder.buildSub(
2961 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2962 Opcode == TargetOpcode::G_CTLZ
2963 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2964 : std::nullopt);
2965 }
2966
2967 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2968 MI.eraseFromParent();
2969 return Legalized;
2970 }
2971 case TargetOpcode::G_BSWAP: {
2972 Observer.changingInstr(MI);
2973 Register DstReg = MI.getOperand(0).getReg();
2974
2975 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2976 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2977 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2978 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2979
2980 MI.getOperand(0).setReg(DstExt);
2981
2982 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2983
2984 LLT Ty = MRI.getType(DstReg);
2985 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2986 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2987 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2988
2989 MIRBuilder.buildTrunc(DstReg, ShrReg);
2990 Observer.changedInstr(MI);
2991 return Legalized;
2992 }
2993 case TargetOpcode::G_BITREVERSE: {
2994 Observer.changingInstr(MI);
2995
2996 Register DstReg = MI.getOperand(0).getReg();
2997 LLT Ty = MRI.getType(DstReg);
2998 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2999
3000 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
3001 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3002 MI.getOperand(0).setReg(DstExt);
3003 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3004
3005 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
3006 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
3007 MIRBuilder.buildTrunc(DstReg, Shift);
3008 Observer.changedInstr(MI);
3009 return Legalized;
3010 }
3011 case TargetOpcode::G_FREEZE:
3012 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
3013 Observer.changingInstr(MI);
3014 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3015 widenScalarDst(MI, WideTy);
3016 Observer.changedInstr(MI);
3017 return Legalized;
3018
3019 case TargetOpcode::G_ABS:
3020 Observer.changingInstr(MI);
3021 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3022 widenScalarDst(MI, WideTy);
3023 Observer.changedInstr(MI);
3024 return Legalized;
3025
3026 case TargetOpcode::G_ADD:
3027 case TargetOpcode::G_AND:
3028 case TargetOpcode::G_MUL:
3029 case TargetOpcode::G_OR:
3030 case TargetOpcode::G_XOR:
3031 case TargetOpcode::G_SUB:
3032 case TargetOpcode::G_SHUFFLE_VECTOR:
3033 // Perform operation at larger width (any extension is fines here, high bits
3034 // don't affect the result) and then truncate the result back to the
3035 // original type.
3036 Observer.changingInstr(MI);
3037 // The G_ANYEXTs below leave the new high bits unconstrained, so no-wrap and
3038 // disjoint claims proved at the narrow width no longer hold. Paths that
3039 // widen with value-preserving G_ZEXT/G_SEXT keep their flags.
3042 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3043 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3044 widenScalarDst(MI, WideTy);
3045 Observer.changedInstr(MI);
3046 return Legalized;
3047
3048 case TargetOpcode::G_SBFX:
3049 case TargetOpcode::G_UBFX:
3050 Observer.changingInstr(MI);
3051
3052 if (TypeIdx == 0) {
3053 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3054 widenScalarDst(MI, WideTy);
3055 } else {
3056 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3057 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3058 }
3059
3060 Observer.changedInstr(MI);
3061 return Legalized;
3062
3063 case TargetOpcode::G_SHL:
3064 Observer.changingInstr(MI);
3065
3066 if (TypeIdx == 0) {
3067 // Widening the result with G_ANYEXT invalidates the no-wrap flags, as in
3068 // the G_ADD/G_SUB/G_MUL case above. TypeIdx 1 widens only the shift
3069 // amount, which is value-preserving, so it keeps them.
3071 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3072 widenScalarDst(MI, WideTy);
3073 } else {
3074 assert(TypeIdx == 1);
3075 // The "number of bits to shift" operand must preserve its value as an
3076 // unsigned integer:
3077 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3078 }
3079
3080 Observer.changedInstr(MI);
3081 return Legalized;
3082
3083 case TargetOpcode::G_ROTR:
3084 case TargetOpcode::G_ROTL:
3085 if (TypeIdx != 1)
3086 return UnableToLegalize;
3087
3088 Observer.changingInstr(MI);
3089 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3090 Observer.changedInstr(MI);
3091 return Legalized;
3092
3093 case TargetOpcode::G_SDIV:
3094 case TargetOpcode::G_SREM:
3095 case TargetOpcode::G_SMIN:
3096 case TargetOpcode::G_SMAX:
3097 case TargetOpcode::G_ABDS:
3098 Observer.changingInstr(MI);
3099 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3100 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3101 widenScalarDst(MI, WideTy);
3102 Observer.changedInstr(MI);
3103 return Legalized;
3104
3105 case TargetOpcode::G_SDIVREM:
3106 Observer.changingInstr(MI);
3107 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3108 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3109 widenScalarDst(MI, WideTy);
3110 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3111 widenScalarDst(MI, WideTy, 1);
3112 Observer.changedInstr(MI);
3113 return Legalized;
3114
3115 case TargetOpcode::G_ASHR:
3116 case TargetOpcode::G_LSHR:
3117 Observer.changingInstr(MI);
3118
3119 if (TypeIdx == 0) {
3120 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3121 : TargetOpcode::G_ZEXT;
3122
3123 widenScalarSrc(MI, WideTy, 1, CvtOp);
3124 widenScalarDst(MI, WideTy);
3125 } else {
3126 assert(TypeIdx == 1);
3127 // The "number of bits to shift" operand must preserve its value as an
3128 // unsigned integer:
3129 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3130 }
3131
3132 Observer.changedInstr(MI);
3133 return Legalized;
3134 case TargetOpcode::G_UDIV:
3135 case TargetOpcode::G_UREM:
3136 case TargetOpcode::G_ABDU:
3137 Observer.changingInstr(MI);
3138 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3139 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3140 widenScalarDst(MI, WideTy);
3141 Observer.changedInstr(MI);
3142 return Legalized;
3143 case TargetOpcode::G_UDIVREM:
3144 Observer.changingInstr(MI);
3145 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3146 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3147 widenScalarDst(MI, WideTy);
3148 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3149 widenScalarDst(MI, WideTy, 1);
3150 Observer.changedInstr(MI);
3151 return Legalized;
3152 case TargetOpcode::G_UMIN:
3153 case TargetOpcode::G_UMAX: {
3154 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3155
3156 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3157 unsigned ExtOpc =
3158 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3159 getApproximateEVTForLLT(WideTy, Ctx))
3160 ? TargetOpcode::G_SEXT
3161 : TargetOpcode::G_ZEXT;
3162
3163 Observer.changingInstr(MI);
3164 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3165 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3166 widenScalarDst(MI, WideTy);
3167 Observer.changedInstr(MI);
3168 return Legalized;
3169 }
3170
3171 case TargetOpcode::G_SELECT:
3172 Observer.changingInstr(MI);
3173 if (TypeIdx == 0) {
3174 // Perform operation at larger width (any extension is fine here, high
3175 // bits don't affect the result) and then truncate the result back to the
3176 // original type.
3177 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3178 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3179 widenScalarDst(MI, WideTy);
3180 } else {
3181 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3182 // Explicit extension is required here since high bits affect the result.
3183 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3184 }
3185 Observer.changedInstr(MI);
3186 return Legalized;
3187
3188 case TargetOpcode::G_FPEXT:
3189 if (TypeIdx != 1)
3190 return UnableToLegalize;
3191
3192 Observer.changingInstr(MI);
3193 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3194 Observer.changedInstr(MI);
3195 return Legalized;
3196 case TargetOpcode::G_FPTOSI:
3197 case TargetOpcode::G_FPTOUI:
3198 case TargetOpcode::G_INTRINSIC_LRINT:
3199 case TargetOpcode::G_INTRINSIC_LLRINT:
3200 case TargetOpcode::G_IS_FPCLASS:
3201 Observer.changingInstr(MI);
3202
3203 if (TypeIdx == 0)
3204 widenScalarDst(MI, WideTy);
3205 else
3206 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3207
3208 Observer.changedInstr(MI);
3209 return Legalized;
3210 case TargetOpcode::G_SITOFP:
3211 Observer.changingInstr(MI);
3212
3213 if (TypeIdx == 0)
3214 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3215 else
3216 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3217
3218 Observer.changedInstr(MI);
3219 return Legalized;
3220 case TargetOpcode::G_UITOFP:
3221 Observer.changingInstr(MI);
3222
3223 if (TypeIdx == 0)
3224 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3225 else
3226 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3227
3228 Observer.changedInstr(MI);
3229 return Legalized;
3230 case TargetOpcode::G_FPTOSI_SAT:
3231 case TargetOpcode::G_FPTOUI_SAT:
3232 Observer.changingInstr(MI);
3233
3234 if (TypeIdx == 0) {
3235 Register OldDst = MI.getOperand(0).getReg();
3236 LLT Ty = MRI.getType(OldDst);
3237 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3238 Register NewDst;
3239 MI.getOperand(0).setReg(ExtReg);
3240 uint64_t ShortBits = Ty.getScalarSizeInBits();
3241 uint64_t WideBits = WideTy.getScalarSizeInBits();
3242 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3243 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3244 // z = i16 fptosi_sat(a)
3245 // ->
3246 // x = i32 fptosi_sat(a)
3247 // y = smin(x, 32767)
3248 // z = smax(y, -32768)
3249 auto MaxVal = MIRBuilder.buildConstant(
3250 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3251 auto MinVal = MIRBuilder.buildConstant(
3252 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3253 Register MidReg =
3254 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3255 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3256 } else {
3257 // z = i16 fptoui_sat(a)
3258 // ->
3259 // x = i32 fptoui_sat(a)
3260 // y = smin(x, 65535)
3261 auto MaxVal = MIRBuilder.buildConstant(
3262 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3263 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3264 }
3265 MIRBuilder.buildTrunc(OldDst, NewDst);
3266 } else
3267 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3268
3269 Observer.changedInstr(MI);
3270 return Legalized;
3271 case TargetOpcode::G_LOAD:
3272 case TargetOpcode::G_SEXTLOAD:
3273 case TargetOpcode::G_ZEXTLOAD:
3274 case TargetOpcode::G_FPEXTLOAD:
3275 Observer.changingInstr(MI);
3276 widenScalarDst(MI, WideTy);
3277 Observer.changedInstr(MI);
3278 return Legalized;
3279
3280 case TargetOpcode::G_STORE: {
3281 if (TypeIdx != 0)
3282 return UnableToLegalize;
3283
3284 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3285 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3286 if (!Ty.isScalar()) {
3287 // We need to widen the vector element type.
3288 Observer.changingInstr(MI);
3289 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3290 // We also need to adjust the MMO to turn this into a truncating store.
3291 MachineMemOperand &MMO = **MI.memoperands_begin();
3292 MachineFunction &MF = MIRBuilder.getMF();
3293 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3294 MI.setMemRefs(MF, {NewMMO});
3295 Observer.changedInstr(MI);
3296 return Legalized;
3297 }
3298
3299 Observer.changingInstr(MI);
3300
3301 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3302 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3303 widenScalarSrc(MI, WideTy, 0, ExtType);
3304
3305 Observer.changedInstr(MI);
3306 return Legalized;
3307 }
3308 case TargetOpcode::G_FPTRUNCSTORE:
3309 if (TypeIdx != 0)
3310 return UnableToLegalize;
3311 Observer.changingInstr(MI);
3312 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3313 Observer.changedInstr(MI);
3314 return Legalized;
3315 case TargetOpcode::G_CONSTANT: {
3316 MachineOperand &SrcMO = MI.getOperand(1);
3317 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3318 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3319 MRI.getType(MI.getOperand(0).getReg()));
3320 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3321 ExtOpc == TargetOpcode::G_ANYEXT) &&
3322 "Illegal Extend");
3323 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3324 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3325 ? SrcVal.sext(WideTy.getSizeInBits())
3326 : SrcVal.zext(WideTy.getSizeInBits());
3327 Observer.changingInstr(MI);
3328 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3329
3330 widenScalarDst(MI, WideTy);
3331 Observer.changedInstr(MI);
3332 return Legalized;
3333 }
3334 case TargetOpcode::G_FCONSTANT: {
3335 // To avoid changing the bits of the constant due to extension to a larger
3336 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3337 MachineOperand &SrcMO = MI.getOperand(1);
3338 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3339 MIRBuilder.setInstrAndDebugLoc(MI);
3340 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3341 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3342 MI.eraseFromParent();
3343 return Legalized;
3344 }
3345 case TargetOpcode::G_IMPLICIT_DEF: {
3346 Observer.changingInstr(MI);
3347 widenScalarDst(MI, WideTy);
3348 Observer.changedInstr(MI);
3349 return Legalized;
3350 }
3351 case TargetOpcode::G_BRCOND:
3352 Observer.changingInstr(MI);
3353 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3354 Observer.changedInstr(MI);
3355 return Legalized;
3356
3357 case TargetOpcode::G_FCMP:
3358 Observer.changingInstr(MI);
3359 if (TypeIdx == 0)
3360 widenScalarDst(MI, WideTy);
3361 else {
3362 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3363 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3364 }
3365 Observer.changedInstr(MI);
3366 return Legalized;
3367
3368 case TargetOpcode::G_ICMP:
3369 Observer.changingInstr(MI);
3370 if (TypeIdx == 0)
3371 widenScalarDst(MI, WideTy);
3372 else {
3373 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3374 CmpInst::Predicate Pred =
3375 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3376
3377 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3378 unsigned ExtOpcode =
3379 (CmpInst::isSigned(Pred) ||
3380 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3381 getApproximateEVTForLLT(WideTy, Ctx)))
3382 ? TargetOpcode::G_SEXT
3383 : TargetOpcode::G_ZEXT;
3384 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3385 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3386 }
3387 Observer.changedInstr(MI);
3388 return Legalized;
3389
3390 case TargetOpcode::G_PTR_ADD:
3391 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3392 Observer.changingInstr(MI);
3393 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3394 Observer.changedInstr(MI);
3395 return Legalized;
3396
3397 case TargetOpcode::G_PHI: {
3398 assert(TypeIdx == 0 && "Expecting only Idx 0");
3399
3400 Observer.changingInstr(MI);
3401 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3402 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3403 MIRBuilder.setInsertPt(OpMBB, getPHIIncomingInsertPoint(
3404 OpMBB, MI.getOperand(I).getReg(), MRI));
3405 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3406 }
3407
3408 MachineBasicBlock &MBB = *MI.getParent();
3409 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3410 widenScalarDst(MI, WideTy);
3411 Observer.changedInstr(MI);
3412 return Legalized;
3413 }
3414 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3415 if (TypeIdx == 0) {
3416 Register VecReg = MI.getOperand(1).getReg();
3417 LLT VecTy = MRI.getType(VecReg);
3418 Observer.changingInstr(MI);
3419
3420 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3421 TargetOpcode::G_ANYEXT);
3422
3423 widenScalarDst(MI, WideTy, 0);
3424 Observer.changedInstr(MI);
3425 return Legalized;
3426 }
3427
3428 if (TypeIdx != 2)
3429 return UnableToLegalize;
3430 Observer.changingInstr(MI);
3431 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3432 Observer.changedInstr(MI);
3433 return Legalized;
3434 }
3435 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3436 if (TypeIdx == 0) {
3437 Observer.changingInstr(MI);
3438 const LLT WideEltTy = WideTy.getElementType();
3439
3440 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3441 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3442 widenScalarDst(MI, WideTy, 0);
3443 Observer.changedInstr(MI);
3444 return Legalized;
3445 }
3446
3447 if (TypeIdx == 1) {
3448 Observer.changingInstr(MI);
3449
3450 Register VecReg = MI.getOperand(1).getReg();
3451 LLT VecTy = MRI.getType(VecReg);
3452 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3453
3454 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3455 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3456 widenScalarDst(MI, WideVecTy, 0);
3457 Observer.changedInstr(MI);
3458 return Legalized;
3459 }
3460
3461 if (TypeIdx == 2) {
3462 Observer.changingInstr(MI);
3463 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3464 Observer.changedInstr(MI);
3465 return Legalized;
3466 }
3467
3468 return UnableToLegalize;
3469 }
3470 case TargetOpcode::G_FADD:
3471 case TargetOpcode::G_FMUL:
3472 case TargetOpcode::G_FSUB:
3473 case TargetOpcode::G_FMA:
3474 case TargetOpcode::G_FMAD:
3475 case TargetOpcode::G_FNEG:
3476 case TargetOpcode::G_FABS:
3477 case TargetOpcode::G_FCANONICALIZE:
3478 case TargetOpcode::G_FMINNUM:
3479 case TargetOpcode::G_FMAXNUM:
3480 case TargetOpcode::G_FMINNUM_IEEE:
3481 case TargetOpcode::G_FMAXNUM_IEEE:
3482 case TargetOpcode::G_FMINIMUM:
3483 case TargetOpcode::G_FMAXIMUM:
3484 case TargetOpcode::G_FMINIMUMNUM:
3485 case TargetOpcode::G_FMAXIMUMNUM:
3486 case TargetOpcode::G_FDIV:
3487 case TargetOpcode::G_FREM:
3488 case TargetOpcode::G_FCEIL:
3489 case TargetOpcode::G_FFLOOR:
3490 case TargetOpcode::G_FCOS:
3491 case TargetOpcode::G_FSIN:
3492 case TargetOpcode::G_FTAN:
3493 case TargetOpcode::G_FACOS:
3494 case TargetOpcode::G_FASIN:
3495 case TargetOpcode::G_FATAN:
3496 case TargetOpcode::G_FATAN2:
3497 case TargetOpcode::G_FCOSH:
3498 case TargetOpcode::G_FSINH:
3499 case TargetOpcode::G_FTANH:
3500 case TargetOpcode::G_FLOG10:
3501 case TargetOpcode::G_FLOG:
3502 case TargetOpcode::G_FLOG2:
3503 case TargetOpcode::G_FRINT:
3504 case TargetOpcode::G_FNEARBYINT:
3505 case TargetOpcode::G_FSQRT:
3506 case TargetOpcode::G_FEXP:
3507 case TargetOpcode::G_FEXP2:
3508 case TargetOpcode::G_FEXP10:
3509 case TargetOpcode::G_FPOW:
3510 case TargetOpcode::G_INTRINSIC_TRUNC:
3511 case TargetOpcode::G_INTRINSIC_ROUND:
3512 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3513 assert(TypeIdx == 0);
3514 Observer.changingInstr(MI);
3515
3516 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3517 widenScalarSrcUsingFPExt(MI, WideTy, I);
3518
3519 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3520 Observer.changedInstr(MI);
3521 return Legalized;
3522 case TargetOpcode::G_FMODF: {
3523 Observer.changingInstr(MI);
3524 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3525
3526 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3527 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3528 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3529 Observer.changedInstr(MI);
3530 return Legalized;
3531 }
3532 case TargetOpcode::G_FPOWI:
3533 case TargetOpcode::G_FLDEXP:
3534 case TargetOpcode::G_STRICT_FLDEXP: {
3535 if (TypeIdx == 0) {
3536 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3537 return UnableToLegalize;
3538
3539 Observer.changingInstr(MI);
3540 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3541 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3542 Observer.changedInstr(MI);
3543 return Legalized;
3544 }
3545
3546 if (TypeIdx == 1) {
3547 // For some reason SelectionDAG tries to promote to a libcall without
3548 // actually changing the integer type for promotion.
3549 Observer.changingInstr(MI);
3550 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3551 Observer.changedInstr(MI);
3552 return Legalized;
3553 }
3554
3555 return UnableToLegalize;
3556 }
3557 case TargetOpcode::G_FFREXP: {
3558 Observer.changingInstr(MI);
3559
3560 if (TypeIdx == 0) {
3561 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3562 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3563 } else {
3564 widenScalarDst(MI, WideTy, 1);
3565 }
3566
3567 Observer.changedInstr(MI);
3568 return Legalized;
3569 }
3570 case TargetOpcode::G_LROUND:
3571 case TargetOpcode::G_LLROUND:
3572 Observer.changingInstr(MI);
3573
3574 if (TypeIdx == 0)
3575 widenScalarDst(MI, WideTy);
3576 else
3577 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3578
3579 Observer.changedInstr(MI);
3580 return Legalized;
3581
3582 case TargetOpcode::G_INTTOPTR:
3583 if (TypeIdx != 1)
3584 return UnableToLegalize;
3585
3586 Observer.changingInstr(MI);
3587 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3588 Observer.changedInstr(MI);
3589 return Legalized;
3590 case TargetOpcode::G_PTRTOINT:
3591 if (TypeIdx != 0)
3592 return UnableToLegalize;
3593
3594 Observer.changingInstr(MI);
3595 widenScalarDst(MI, WideTy, 0);
3596 Observer.changedInstr(MI);
3597 return Legalized;
3598 case TargetOpcode::G_BUILD_VECTOR: {
3599 Observer.changingInstr(MI);
3600
3601 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3602 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3603 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3604
3605 // Avoid changing the result vector type if the source element type was
3606 // requested.
3607 if (TypeIdx == 1) {
3608 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3609 } else {
3610 widenScalarDst(MI, WideTy, 0);
3611 }
3612
3613 Observer.changedInstr(MI);
3614 return Legalized;
3615 }
3616 case TargetOpcode::G_SEXT_INREG:
3617 if (TypeIdx != 0)
3618 return UnableToLegalize;
3619
3620 Observer.changingInstr(MI);
3621 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3622 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3623 Observer.changedInstr(MI);
3624 return Legalized;
3625 case TargetOpcode::G_PTRMASK: {
3626 if (TypeIdx != 1)
3627 return UnableToLegalize;
3628 Observer.changingInstr(MI);
3629 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3630 Observer.changedInstr(MI);
3631 return Legalized;
3632 }
3633 case TargetOpcode::G_VECREDUCE_ADD: {
3634 if (TypeIdx != 1)
3635 return UnableToLegalize;
3636 Observer.changingInstr(MI);
3637 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3638 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3639 Observer.changedInstr(MI);
3640 return Legalized;
3641 }
3642 case TargetOpcode::G_VECREDUCE_FADD:
3643 case TargetOpcode::G_VECREDUCE_FMUL:
3644 case TargetOpcode::G_VECREDUCE_FMIN:
3645 case TargetOpcode::G_VECREDUCE_FMAX:
3646 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3647 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3648 if (TypeIdx != 0)
3649 return UnableToLegalize;
3650 Observer.changingInstr(MI);
3651 Register VecReg = MI.getOperand(1).getReg();
3652 LLT VecTy = MRI.getType(VecReg);
3653 LLT WideVecTy = VecTy.changeElementType(WideTy);
3654 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3655 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3656 Observer.changedInstr(MI);
3657 return Legalized;
3658 }
3659 case TargetOpcode::G_VSCALE: {
3660 MachineOperand &SrcMO = MI.getOperand(1);
3661 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3662 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3663 // The CImm is always a signed value
3664 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3665 Observer.changingInstr(MI);
3666 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3667 widenScalarDst(MI, WideTy);
3668 Observer.changedInstr(MI);
3669 return Legalized;
3670 }
3671 case TargetOpcode::G_SPLAT_VECTOR: {
3672 if (TypeIdx != 1)
3673 return UnableToLegalize;
3674
3675 Observer.changingInstr(MI);
3676 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3677 Observer.changedInstr(MI);
3678 return Legalized;
3679 }
3680 case TargetOpcode::G_INSERT_SUBVECTOR: {
3681 if (TypeIdx != 0)
3682 return UnableToLegalize;
3683
3685 Register BigVec = IS.getBigVec();
3686 Register SubVec = IS.getSubVec();
3687
3688 LLT SubVecTy = MRI.getType(SubVec);
3689 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3690
3691 // Widen the G_INSERT_SUBVECTOR
3692 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3693 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3694 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3695 IS.getIndexImm());
3696
3697 // Truncate back down
3698 auto SplatZero = MIRBuilder.buildSplatVector(
3699 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3700 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3701 SplatZero);
3702
3703 MI.eraseFromParent();
3704
3705 return Legalized;
3706 }
3707 case TargetOpcode::G_BITCAST:
3708 if (WideTy.isVector())
3709 return UnableToLegalize;
3710 Observer.changingInstr(MI);
3711 if (TypeIdx == 0)
3712 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3713 else
3714 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3715 Observer.changedInstr(MI);
3716
3717 Register Dst = MI.getOperand(0).getReg();
3718 Register Src = MI.getOperand(1).getReg();
3719 if (MRI.getType(Dst) == MRI.getType(Src)) {
3720 Observer.changingAllUsesOfReg(MRI, Dst);
3721 MRI.replaceRegWith(Dst, Src);
3722 Observer.finishedChangingAllUsesOfReg();
3723 MI.eraseFromParent();
3724 }
3725
3726 return Legalized;
3727 }
3728}
3729
3731 MachineIRBuilder &B, Register Src, LLT Ty) {
3732 auto Unmerge = B.buildUnmerge(Ty, Src);
3733 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3734 Pieces.push_back(Unmerge.getReg(I));
3735}
3736
3737static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3738 MachineIRBuilder &MIRBuilder) {
3739 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3740 MachineFunction &MF = MIRBuilder.getMF();
3741 const DataLayout &DL = MIRBuilder.getDataLayout();
3742 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3743 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3744 LLT DstLLT = MRI.getType(DstReg);
3745
3746 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3747
3748 auto Addr = MIRBuilder.buildConstantPool(
3749 AddrPtrTy,
3750 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3751
3752 MachineMemOperand *MMO =
3754 MachineMemOperand::MOLoad, DstLLT, Alignment);
3755
3756 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3757}
3758
3761 const MachineOperand &ConstOperand = MI.getOperand(1);
3762 const Constant *ConstantVal = ConstOperand.getCImm();
3763
3764 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3765 MI.eraseFromParent();
3766
3767 return Legalized;
3768}
3769
3772 Register Dst = MI.getOperand(0).getReg();
3773 const ConstantFP *ConstantVal = MI.getOperand(1).getFPImm();
3774 const APFloat &Imm = ConstantVal->getValueAPF();
3775
3776 bool ForCodeSize = MIRBuilder.getMF().getFunction().hasOptSize();
3777 if (TLI.getFPImmAction(Imm, MRI.getType(Dst), ForCodeSize) ==
3779 MIRBuilder.buildConstant(Dst, Imm.bitcastToAPInt());
3780 else
3781 emitLoadFromConstantPool(Dst, ConstantVal, MIRBuilder);
3782
3783 MI.eraseFromParent();
3784 return Legalized;
3785}
3786
3789 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3790 if (SrcTy.isVector()) {
3791 LLT SrcEltTy = SrcTy.getElementType();
3793
3794 if (DstTy.isVector()) {
3795 LLT DstEltTy = DstTy.getElementType();
3796 ElementCount DstEC = DstTy.getElementCount();
3797 ElementCount SrcEC = SrcTy.getElementCount();
3798
3799 if (!SrcEC.isKnownMultipleOf(DstEC) && !DstEC.isKnownMultipleOf(SrcEC)) {
3800 // Split non-integer element ratio bitcast
3801 //
3802 // %1:_(<3 x s16>) = G_BITCAST %0:_(<2 x s24>)
3803 //
3804 // =>
3805 //
3806 // %2:_(<6 x s8>) = G_BITCAST %0:_(<2 x s24>)
3807 // %1:_(<3 x s16>) = G_BITCAST %2:_(<6 x s8>)
3808 unsigned SrcEltSize = SrcEltTy.getScalarSizeInBits();
3809 unsigned PieceSize =
3810 std::gcd(SrcEltSize, DstEltTy.getScalarSizeInBits());
3811 LLT PieceTy = LLT::integer(PieceSize);
3812
3813 if (!PieceTy.isByteSized()) {
3814 // Split bitcast whose pieces are not whole bytes through a scalar
3815 //
3816 // %1:_(<3 x s8>) = G_BITCAST %0:_(<2 x s12>)
3817 //
3818 // =>
3819 //
3820 // %2:_(s24) = G_BITCAST %0:_(<2 x s12>)
3821 // %1:_(<3 x s8>) = G_BITCAST %2:_(s24)
3822 LLT ScalarTy = LLT::integer(SrcTy.getSizeInBits());
3823 Register ScalarReg = MIRBuilder.buildBitcast(ScalarTy, Src).getReg(0);
3824 MIRBuilder.buildBitcast(Dst, ScalarReg);
3825 MI.eraseFromParent();
3826 return Legalized;
3827 }
3828
3829 LLT PiecesVecTy =
3830 LLT::vector(SrcEC * (SrcEltSize / PieceSize), PieceTy);
3831 Register PiecesReg =
3832 MIRBuilder.buildBitcast(PiecesVecTy, Src).getReg(0);
3833 MIRBuilder.buildBitcast(Dst, PiecesReg);
3834 MI.eraseFromParent();
3835 return Legalized;
3836 }
3837
3838 unsigned NumDstElt = DstEC.getKnownMinValue();
3839 unsigned NumSrcElt = SrcEC.getKnownMinValue();
3840
3841 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3842 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3843
3844 // If there's an element size mismatch, insert intermediate casts to match
3845 // the result element type.
3846 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3847 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3848 //
3849 // =>
3850 //
3851 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3852 // %3:_(<2 x s8>) = G_BITCAST %2
3853 // %4:_(<2 x s8>) = G_BITCAST %3
3854 // %1:_(<4 x s8>) = G_CONCAT_VECTORS %3, %4
3855 DstCastTy = DstTy.changeVectorElementCount(
3856 ElementCount::getFixed(NumDstElt / NumSrcElt));
3857 SrcPartTy = SrcEltTy;
3858 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3859 //
3860 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3861 //
3862 // =>
3863 //
3864 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3865 // %3:_(s16) = G_BITCAST %2
3866 // %4:_(s16) = G_BITCAST %3
3867 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3868 SrcPartTy = SrcTy.changeVectorElementCount(
3869 ElementCount::getFixed(NumSrcElt / NumDstElt));
3870 DstCastTy = DstEltTy;
3871 }
3872
3873 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3874 for (Register &SrcReg : SrcRegs)
3875 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3876 } else
3877 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3878
3879 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3880 MI.eraseFromParent();
3881 return Legalized;
3882 }
3883
3884 if (DstTy.isVector()) {
3886 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3887 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3888 MI.eraseFromParent();
3889 return Legalized;
3890 }
3891
3892 return UnableToLegalize;
3893}
3894
3895/// Figure out the bit offset into a register when coercing a vector index for
3896/// the wide element type. This is only for the case when promoting vector to
3897/// one with larger elements.
3898//
3899///
3900/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3901/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3903 Register Idx,
3904 unsigned NewEltSize,
3905 unsigned OldEltSize) {
3906 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3907 LLT IdxTy = B.getMRI()->getType(Idx);
3908
3909 // Now figure out the amount we need to shift to get the target bits.
3910 auto OffsetMask = B.buildConstant(
3911 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3912 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3913 return B.buildShl(IdxTy, OffsetIdx,
3914 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3915}
3916
3917/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3918/// is casting to a vector with a smaller element size, perform multiple element
3919/// extracts and merge the results. If this is coercing to a vector with larger
3920/// elements, index the bitcasted vector and extract the target element with bit
3921/// operations. This is intended to force the indexing in the native register
3922/// size for architectures that can dynamically index the register file.
3925 LLT CastTy) {
3926 if (TypeIdx != 1)
3927 return UnableToLegalize;
3928
3929 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3930
3931 LLT SrcEltTy = SrcVecTy.getElementType();
3932 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3933 unsigned OldNumElts = SrcVecTy.getNumElements();
3934
3935 LLT NewEltTy = CastTy.getScalarType();
3936 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3937
3938 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3939 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3940 if (NewNumElts > OldNumElts) {
3941 // Decreasing the vector element size
3942 //
3943 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3944 // =>
3945 // v4i32:castx = bitcast x:v2i64
3946 //
3947 // i64 = bitcast
3948 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3949 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3950 //
3951 if (NewNumElts % OldNumElts != 0)
3952 return UnableToLegalize;
3953
3954 // Type of the intermediate result vector.
3955 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3956 LLT MidTy =
3957 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3958
3959 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3960
3961 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3962 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3963
3964 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3965 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3966 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3967 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3968 NewOps[I] = Elt.getReg(0);
3969 }
3970
3971 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3972 MIRBuilder.buildBitcast(Dst, NewVec);
3973 MI.eraseFromParent();
3974 return Legalized;
3975 }
3976
3977 if (NewNumElts < OldNumElts) {
3978 if (NewEltSize % OldEltSize != 0)
3979 return UnableToLegalize;
3980
3981 // This only depends on powers of 2 because we use bit tricks to figure out
3982 // the bit offset we need to shift to get the target element. A general
3983 // expansion could emit division/multiply.
3984 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3985 return UnableToLegalize;
3986
3987 // Increasing the vector element size.
3988 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3989 //
3990 // =>
3991 //
3992 // %cast = G_BITCAST %vec
3993 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3994 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3995 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3996 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3997 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3998 // %elt = G_TRUNC %elt_bits
3999
4000 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4001 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4002
4003 // Divide to get the index in the wider element type.
4004 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4005
4006 Register WideElt = CastVec;
4007 if (CastTy.isVector()) {
4008 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4009 ScaledIdx).getReg(0);
4010 }
4011
4012 // Compute the bit offset into the register of the target element.
4014 MIRBuilder, Idx, NewEltSize, OldEltSize);
4015
4016 // Shift the wide element to get the target element.
4017 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
4018 MIRBuilder.buildTrunc(Dst, ExtractedBits);
4019 MI.eraseFromParent();
4020 return Legalized;
4021 }
4022
4023 return UnableToLegalize;
4024}
4025
4026/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
4027/// TargetReg, while preserving other bits in \p TargetReg.
4028///
4029/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
4031 Register TargetReg, Register InsertReg,
4032 Register OffsetBits) {
4033 LLT TargetTy = B.getMRI()->getType(TargetReg);
4034 LLT InsertTy = B.getMRI()->getType(InsertReg);
4035 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
4036 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
4037
4038 // Produce a bitmask of the value to insert
4039 auto EltMask = B.buildConstant(
4040 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
4041 InsertTy.getSizeInBits()));
4042 // Shift it into position
4043 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
4044 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
4045
4046 // Clear out the bits in the wide element
4047 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
4048
4049 // The value to insert has all zeros already, so stick it into the masked
4050 // wide element.
4051 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
4052}
4053
4054/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
4055/// is increasing the element size, perform the indexing in the target element
4056/// type, and use bit operations to insert at the element position. This is
4057/// intended for architectures that can dynamically index the register file and
4058/// want to force indexing in the native register size.
4061 LLT CastTy) {
4062 if (TypeIdx != 0)
4063 return UnableToLegalize;
4064
4065 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
4066 MI.getFirst4RegLLTs();
4067 LLT VecTy = DstTy;
4068
4069 LLT VecEltTy = VecTy.getElementType();
4070 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
4071 const unsigned NewEltSize = NewEltTy.getSizeInBits();
4072 const unsigned OldEltSize = VecEltTy.getSizeInBits();
4073
4074 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
4075 unsigned OldNumElts = VecTy.getNumElements();
4076
4077 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
4078 if (NewNumElts < OldNumElts) {
4079 if (NewEltSize % OldEltSize != 0)
4080 return UnableToLegalize;
4081
4082 // This only depends on powers of 2 because we use bit tricks to figure out
4083 // the bit offset we need to shift to get the target element. A general
4084 // expansion could emit division/multiply.
4085 if (!isPowerOf2_32(NewEltSize / OldEltSize))
4086 return UnableToLegalize;
4087
4088 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4089 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4090
4091 // Divide to get the index in the wider element type.
4092 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4093
4094 Register ExtractedElt = CastVec;
4095 if (CastTy.isVector()) {
4096 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4097 ScaledIdx).getReg(0);
4098 }
4099
4100 // Compute the bit offset into the register of the target element.
4102 MIRBuilder, Idx, NewEltSize, OldEltSize);
4103
4104 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
4105 Val, OffsetBits);
4106 if (CastTy.isVector()) {
4107 InsertedElt = MIRBuilder.buildInsertVectorElement(
4108 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
4109 }
4110
4111 MIRBuilder.buildBitcast(Dst, InsertedElt);
4112 MI.eraseFromParent();
4113 return Legalized;
4114 }
4115
4116 return UnableToLegalize;
4117}
4118
4119// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4120// those that have smaller than legal operands.
4121//
4122// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4123//
4124// ===>
4125//
4126// s32 = G_BITCAST <4 x s8>
4127// s32 = G_BITCAST <4 x s8>
4128// s32 = G_BITCAST <4 x s8>
4129// s32 = G_BITCAST <4 x s8>
4130// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4131// <16 x s8> = G_BITCAST <4 x s32>
4134 LLT CastTy) {
4135 // Convert it to CONCAT instruction
4136 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4137 if (!ConcatMI) {
4138 return UnableToLegalize;
4139 }
4140
4141 // Check if bitcast is Legal
4142 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4143 LLT SrcScalTy = CastTy.getScalarType();
4144
4145 // Check if the build vector is Legal
4146 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4147 return UnableToLegalize;
4148 }
4149
4150 // Bitcast the sources
4151 SmallVector<Register> BitcastRegs;
4152 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4153 BitcastRegs.push_back(
4154 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4155 .getReg(0));
4156 }
4157
4158 // Build the scalar values into a vector
4159 Register BuildReg =
4160 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4161 MIRBuilder.buildBitcast(DstReg, BuildReg);
4162
4163 MI.eraseFromParent();
4164 return Legalized;
4165}
4166
4167// This bitcasts a shuffle vector to a different type currently of the same
4168// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4169// will be used instead.
4170//
4171// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4172// ===>
4173// <4 x s64> = G_PTRTOINT <4 x p0>
4174// <4 x s64> = G_PTRTOINT <4 x p0>
4175// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4176// <16 x p0> = G_INTTOPTR <16 x s64>
4179 LLT CastTy) {
4180 auto ShuffleMI = cast<GShuffleVector>(&MI);
4181 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4182 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4183
4184 // We currently only handle vectors of the same size.
4185 if (TypeIdx != 0 ||
4186 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4187 CastTy.getElementCount() != DstTy.getElementCount())
4188 return UnableToLegalize;
4189
4190 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4191
4192 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4193 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4194 auto Shuf =
4195 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4196 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4197
4198 MI.eraseFromParent();
4199 return Legalized;
4200}
4201
4202/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4203///
4204/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4205///
4206/// ===>
4207///
4208/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4209/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4210/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4213 LLT CastTy) {
4214 auto ES = cast<GExtractSubvector>(&MI);
4215
4216 if (!CastTy.isVector())
4217 return UnableToLegalize;
4218
4219 if (TypeIdx != 0)
4220 return UnableToLegalize;
4221
4222 Register Dst = ES->getReg(0);
4223 Register Src = ES->getSrcVec();
4224 uint64_t Idx = ES->getIndexImm();
4225
4226 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4227
4228 LLT DstTy = MRI.getType(Dst);
4229 LLT SrcTy = MRI.getType(Src);
4230 ElementCount DstTyEC = DstTy.getElementCount();
4231 ElementCount SrcTyEC = SrcTy.getElementCount();
4232 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4233 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4234
4235 if (DstTy == CastTy)
4236 return Legalized;
4237
4238 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4239 return UnableToLegalize;
4240
4241 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4242 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4243 if (CastEltSize < DstEltSize)
4244 return UnableToLegalize;
4245
4246 auto AdjustAmt = CastEltSize / DstEltSize;
4247 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4248 SrcTyMinElts % AdjustAmt != 0)
4249 return UnableToLegalize;
4250
4251 Idx /= AdjustAmt;
4252 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4253 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4254 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4255 MIRBuilder.buildBitcast(Dst, PromotedES);
4256
4257 ES->eraseFromParent();
4258 return Legalized;
4259}
4260
4261/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4262///
4263/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4264/// <vscale x 8 x i1>,
4265/// N
4266///
4267/// ===>
4268///
4269/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4270/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4271/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4272/// <vscale x 1 x i8>, N / 8
4273/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4276 LLT CastTy) {
4277 auto ES = cast<GInsertSubvector>(&MI);
4278
4279 if (!CastTy.isVector())
4280 return UnableToLegalize;
4281
4282 if (TypeIdx != 0)
4283 return UnableToLegalize;
4284
4285 Register Dst = ES->getReg(0);
4286 Register BigVec = ES->getBigVec();
4287 Register SubVec = ES->getSubVec();
4288 uint64_t Idx = ES->getIndexImm();
4289
4290 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4291
4292 LLT DstTy = MRI.getType(Dst);
4293 LLT BigVecTy = MRI.getType(BigVec);
4294 LLT SubVecTy = MRI.getType(SubVec);
4295
4296 if (DstTy == CastTy)
4297 return Legalized;
4298
4299 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4300 return UnableToLegalize;
4301
4302 ElementCount DstTyEC = DstTy.getElementCount();
4303 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4304 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4305 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4306 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4307 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4308
4309 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4310 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4311 if (CastEltSize < DstEltSize)
4312 return UnableToLegalize;
4313
4314 auto AdjustAmt = CastEltSize / DstEltSize;
4315 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4316 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4317 return UnableToLegalize;
4318
4319 Idx /= AdjustAmt;
4320 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4321 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4322 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4323 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4324 auto PromotedIS =
4325 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4326 MIRBuilder.buildBitcast(Dst, PromotedIS);
4327
4328 ES->eraseFromParent();
4329 return Legalized;
4330}
4331
4333 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4334 Register DstReg = LoadMI.getDstReg();
4335 Register PtrReg = LoadMI.getPointerReg();
4336 LLT DstTy = MRI.getType(DstReg);
4337 MachineMemOperand &MMO = LoadMI.getMMO();
4338 LLT MemTy = MMO.getMemoryType();
4339 MachineFunction &MF = MIRBuilder.getMF();
4340
4341 LLT EltTy = MemTy.getScalarType();
4342
4343 unsigned MemSizeInBits = MemTy.getSizeInBits();
4344 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4345
4346 if (MemSizeInBits != MemStoreSizeInBits) {
4347 if (MemTy.isVector())
4348 return UnableToLegalize;
4349
4350 // Promote to a byte-sized load if not loading an integral number of
4351 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4352 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4353 MachineMemOperand *NewMMO =
4354 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4355
4356 Register LoadReg = DstReg;
4357 LLT LoadTy = DstTy;
4358
4359 // If this wasn't already an extending load, we need to widen the result
4360 // register to avoid creating a load with a narrower result than the source.
4361 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4362 LoadTy = WideMemTy;
4363 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4364 }
4365
4366 if (isa<GSExtLoad>(LoadMI)) {
4367 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4368 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4369 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4370 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4371 // The extra bits are guaranteed to be zero, since we stored them that
4372 // way. A zext load from Wide thus automatically gives zext from MemVT.
4373 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4374 } else {
4375 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4376 }
4377
4378 if (DstTy != LoadTy)
4379 MIRBuilder.buildTrunc(DstReg, LoadReg);
4380
4381 LoadMI.eraseFromParent();
4382 return Legalized;
4383 }
4384
4385 // Big endian lowering not implemented.
4386 if (MIRBuilder.getDataLayout().isBigEndian())
4387 return UnableToLegalize;
4388
4389 // This load needs splitting into power of 2 sized loads.
4390 //
4391 // Our strategy here is to generate anyextending loads for the smaller
4392 // types up to next power-2 result type, and then combine the two larger
4393 // result values together, before truncating back down to the non-pow-2
4394 // type.
4395 // E.g. v1 = i24 load =>
4396 // v2 = i32 zextload (2 byte)
4397 // v3 = i32 load (1 byte)
4398 // v4 = i32 shl v3, 16
4399 // v5 = i32 or v4, v2
4400 // v1 = i24 trunc v5
4401 // By doing this we generate the correct truncate which should get
4402 // combined away as an artifact with a matching extend.
4403
4404 uint64_t LargeSplitSize, SmallSplitSize;
4405
4406 if (!isPowerOf2_32(MemSizeInBits)) {
4407 // This load needs splitting into power of 2 sized loads.
4408 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4409 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4410 } else {
4411 // This is already a power of 2, but we still need to split this in half.
4412 //
4413 // Assume we're being asked to decompose an unaligned load.
4414 // TODO: If this requires multiple splits, handle them all at once.
4415 auto &Ctx = MF.getFunction().getContext();
4416 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4417 return UnableToLegalize;
4418
4419 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4420 }
4421
4422 if (MemTy.isVector()) {
4423 // TODO: Handle vector extloads
4424 if (MemTy != DstTy)
4425 return UnableToLegalize;
4426
4427 Align Alignment = LoadMI.getAlign();
4428 // Given an alignment larger than the size of the memory, we can increase
4429 // the size of the load without needing to scalarize it.
4430 if (Alignment.value() * 8 > MemSizeInBits &&
4432 LLT MoreTy = DstTy.changeVectorElementCount(
4434 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4435 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4436 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4437 NewLoad.getReg(0));
4438 LoadMI.eraseFromParent();
4439 return Legalized;
4440 }
4441
4442 // TODO: We can do better than scalarizing the vector and at least split it
4443 // in half.
4444 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4445 }
4446
4447 MachineMemOperand *LargeMMO =
4448 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4449 MachineMemOperand *SmallMMO =
4450 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4451
4452 LLT PtrTy = MRI.getType(PtrReg);
4453 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4454
4455 LLT AnyExtTy = LLT::integer(AnyExtSize);
4456 LLT OffsetCstRes = LLT::integer(PtrTy.getSizeInBits());
4457
4458 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4459 PtrReg, *LargeMMO);
4460
4461 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4462 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4463 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4464 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4465 SmallPtr, *SmallMMO);
4466
4467 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4468 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4469
4470 if (AnyExtTy == DstTy)
4471 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4472 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4473 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4474 LLT IntDstTy = DstTy.changeToInteger();
4475 if (IntDstTy == DstTy) {
4476 MIRBuilder.buildTrunc(DstReg, {Or});
4477 } else {
4478 auto Trunc = MIRBuilder.buildTrunc(IntDstTy, Or);
4479 MIRBuilder.buildBitcast(DstReg, Trunc);
4480 }
4481 } else if (DstTy.isPointer()) {
4482 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4483
4484 // FIXME: We currently consider this to be illegal for non-integral address
4485 // spaces, but we need still need a way to reinterpret the bits.
4486 MIRBuilder.buildIntToPtr(DstReg, Or);
4487 } else {
4488 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4489 MIRBuilder.buildBitcast(DstReg, Or);
4490 }
4491
4492 LoadMI.eraseFromParent();
4493 return Legalized;
4494}
4495
4497 // Lower a non-power of 2 store into multiple pow-2 stores.
4498 // E.g. split an i24 store into an i16 store + i8 store.
4499 // We do this by first extending the stored value to the next largest power
4500 // of 2 type, and then using truncating stores to store the components.
4501 // By doing this, likewise with G_LOAD, generate an extend that can be
4502 // artifact-combined away instead of leaving behind extracts.
4503 Register SrcReg = StoreMI.getValueReg();
4504 Register PtrReg = StoreMI.getPointerReg();
4505 LLT SrcTy = MRI.getType(SrcReg);
4506 MachineFunction &MF = MIRBuilder.getMF();
4507 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4508 LLT MemTy = MMO.getMemoryType();
4509
4510 unsigned StoreWidth = MemTy.getSizeInBits();
4511 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4512
4513 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4514 // Promote to a byte-sized store with upper bits zero if not
4515 // storing an integral number of bytes. For example, promote
4516 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4517 LLT WideTy = LLT::integer(StoreSizeInBits);
4518
4519 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4520 // Avoid creating a store with a narrower source than result.
4521 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4522 SrcTy = WideTy;
4523 }
4524
4525 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4526
4527 MachineMemOperand *NewMMO =
4528 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4529 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4530 StoreMI.eraseFromParent();
4531 return Legalized;
4532 }
4533
4534 if (MemTy.isVector()) {
4535 if (MemTy != SrcTy)
4536 return scalarizeVectorBooleanStore(StoreMI);
4537
4538 // TODO: We can do better than scalarizing the vector and at least split it
4539 // in half.
4540 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4541 }
4542
4543 unsigned MemSizeInBits = MemTy.getSizeInBits();
4544 uint64_t LargeSplitSize, SmallSplitSize;
4545
4546 if (!isPowerOf2_32(MemSizeInBits)) {
4547 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4548 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4549 } else {
4550 auto &Ctx = MF.getFunction().getContext();
4551 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4552 return UnableToLegalize; // Don't know what we're being asked to do.
4553
4554 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4555 }
4556
4557 // Extend to the next pow-2. If this store was itself the result of lowering,
4558 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4559 // that's wider than the stored size.
4560 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4561 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4562
4563 if (SrcTy.isPointer()) {
4564 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4565 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4566 }
4567
4568 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4569
4570 // Obtain the smaller value by shifting away the larger value.
4571 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4572 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4573
4574 // Generate the PtrAdd and truncating stores.
4575 LLT PtrTy = MRI.getType(PtrReg);
4576 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4577 LargeSplitSize / 8);
4578 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4579
4580 MachineMemOperand *LargeMMO =
4581 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4582 MachineMemOperand *SmallMMO =
4583 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4584 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4585 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4586 StoreMI.eraseFromParent();
4587 return Legalized;
4588}
4589
4592 Register SrcReg = StoreMI.getValueReg();
4593 Register PtrReg = StoreMI.getPointerReg();
4594 LLT SrcTy = MRI.getType(SrcReg);
4595 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4596 LLT MemTy = MMO.getMemoryType();
4597 LLT MemScalarTy = MemTy.getElementType();
4598 MachineFunction &MF = MIRBuilder.getMF();
4599
4600 assert(SrcTy.isVector() && "Expect a vector store type");
4601
4602 if (!MemScalarTy.isByteSized()) {
4603 // We need to build an integer scalar of the vector bit pattern.
4604 // It's not legal for us to add padding when storing a vector.
4605 unsigned NumBits = MemTy.getSizeInBits();
4606 LLT IntTy = LLT::integer(NumBits);
4607 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4608 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4609
4610 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4611 auto Elt = MIRBuilder.buildExtractVectorElement(
4612 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4613 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4614 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4615 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4616 ? (MemTy.getNumElements() - 1) - I
4617 : I;
4618 auto ShiftAmt = MIRBuilder.buildConstant(
4619 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4620 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4621 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4622 }
4623 auto PtrInfo = MMO.getPointerInfo();
4624 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4625 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4626 StoreMI.eraseFromParent();
4627 return Legalized;
4628 }
4629
4630 // TODO: implement simple scalarization.
4631 return UnableToLegalize;
4632}
4633
4635LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4636 switch (MI.getOpcode()) {
4637 case TargetOpcode::G_LOAD: {
4638 if (TypeIdx != 0)
4639 return UnableToLegalize;
4640 MachineMemOperand &MMO = **MI.memoperands_begin();
4641
4642 // Not sure how to interpret a bitcast of an extending load.
4643 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4644 return UnableToLegalize;
4645
4646 Observer.changingInstr(MI);
4647 bitcastDst(MI, CastTy, 0);
4648 MMO.setType(CastTy);
4649 // The range metadata is no longer valid when reinterpreted as a different
4650 // type.
4651 MMO.clearRanges();
4652 Observer.changedInstr(MI);
4653 return Legalized;
4654 }
4655 case TargetOpcode::G_STORE: {
4656 if (TypeIdx != 0)
4657 return UnableToLegalize;
4658
4659 MachineMemOperand &MMO = **MI.memoperands_begin();
4660
4661 // Not sure how to interpret a bitcast of a truncating store.
4662 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4663 return UnableToLegalize;
4664
4665 Observer.changingInstr(MI);
4666 bitcastSrc(MI, CastTy, 0);
4667 MMO.setType(CastTy);
4668 Observer.changedInstr(MI);
4669 return Legalized;
4670 }
4671 case TargetOpcode::G_SELECT: {
4672 if (TypeIdx != 0)
4673 return UnableToLegalize;
4674
4675 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4676 LLVM_DEBUG(
4677 dbgs() << "bitcast action not implemented for vector select\n");
4678 return UnableToLegalize;
4679 }
4680
4681 Observer.changingInstr(MI);
4682 bitcastSrc(MI, CastTy, 2);
4683 bitcastSrc(MI, CastTy, 3);
4684 bitcastDst(MI, CastTy, 0);
4685 Observer.changedInstr(MI);
4686 return Legalized;
4687 }
4688 case TargetOpcode::G_AND:
4689 case TargetOpcode::G_OR:
4690 case TargetOpcode::G_XOR: {
4691 Observer.changingInstr(MI);
4692 bitcastSrc(MI, CastTy, 1);
4693 bitcastSrc(MI, CastTy, 2);
4694 bitcastDst(MI, CastTy, 0);
4695 Observer.changedInstr(MI);
4696 return Legalized;
4697 }
4698 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4699 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4700 case TargetOpcode::G_INSERT_VECTOR_ELT:
4701 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4702 case TargetOpcode::G_CONCAT_VECTORS:
4703 return bitcastConcatVector(MI, TypeIdx, CastTy);
4704 case TargetOpcode::G_SHUFFLE_VECTOR:
4705 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4706 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4707 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4708 case TargetOpcode::G_INSERT_SUBVECTOR:
4709 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4710 default:
4711 return UnableToLegalize;
4712 }
4713}
4714
4715// Legalize an instruction by changing the opcode in place.
4716void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4718 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4720}
4721
4723LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4724 using namespace TargetOpcode;
4725 switch(MI.getOpcode()) {
4726 default:
4727 return UnableToLegalize;
4728 case TargetOpcode::G_FCONSTANT:
4729 return lowerFConstant(MI);
4730 case TargetOpcode::G_BITCAST:
4731 return lowerBitcast(MI);
4732 case TargetOpcode::G_SREM:
4733 case TargetOpcode::G_UREM: {
4734 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4735 auto Quot =
4736 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4737 {MI.getOperand(1), MI.getOperand(2)});
4738
4739 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4740 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4741 MI.eraseFromParent();
4742 return Legalized;
4743 }
4744 case TargetOpcode::G_SADDO:
4745 case TargetOpcode::G_SSUBO:
4746 return lowerSADDO_SSUBO(MI);
4747 case TargetOpcode::G_SADDE:
4748 return lowerSADDE(MI);
4749 case TargetOpcode::G_SSUBE:
4750 return lowerSSUBE(MI);
4751 case TargetOpcode::G_UMULH:
4752 case TargetOpcode::G_SMULH:
4753 return lowerSMULH_UMULH(MI);
4754 case TargetOpcode::G_SMULO:
4755 case TargetOpcode::G_UMULO: {
4756 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4757 // result.
4758 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4759 LLT Ty = MRI.getType(Res);
4760
4761 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4762 ? TargetOpcode::G_SMULH
4763 : TargetOpcode::G_UMULH;
4764
4765 Observer.changingInstr(MI);
4766 const auto &TII = MIRBuilder.getTII();
4767 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4768 MI.removeOperand(1);
4769 Observer.changedInstr(MI);
4770
4771 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4772 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4773
4774 // Move insert point forward so we can use the Res register if needed.
4775 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4776
4777 // For *signed* multiply, overflow is detected by checking:
4778 // (hi != (lo >> bitwidth-1))
4779 if (Opcode == TargetOpcode::G_SMULH) {
4780 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4781 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4782 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4783 } else {
4784 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4785 }
4786 return Legalized;
4787 }
4788 case TargetOpcode::G_FNEG: {
4789 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4790 LLT TyInt =
4791 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4792 Register CastedSubByReg = SubByReg;
4793
4794 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4795 !SubByRegTy.getScalarType().isInteger()) {
4796 auto BitcastDst = SubByRegTy.changeElementType(
4797 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4798 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4799 }
4800
4801 auto SignMask = MIRBuilder.buildConstant(
4802 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4803
4804 if (ResTy != TyInt) {
4805 Register NewDst =
4806 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4807 MIRBuilder.buildBitcast(Res, NewDst);
4808 } else
4809 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4810
4811 MI.eraseFromParent();
4812 return Legalized;
4813 }
4814 case TargetOpcode::G_FSUB:
4815 case TargetOpcode::G_STRICT_FSUB: {
4816 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4817 LLT Ty = MRI.getType(Res);
4818
4819 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4820 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4821
4822 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4823 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4824 else
4825 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4826
4827 MI.eraseFromParent();
4828 return Legalized;
4829 }
4830 case TargetOpcode::G_FMAD:
4831 return lowerFMad(MI);
4832 case TargetOpcode::G_FFLOOR:
4833 return lowerFFloor(MI);
4834 case TargetOpcode::G_LROUND:
4835 case TargetOpcode::G_LLROUND: {
4836 Register DstReg = MI.getOperand(0).getReg();
4837 Register SrcReg = MI.getOperand(1).getReg();
4838 LLT SrcTy = MRI.getType(SrcReg);
4839 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4840 {SrcReg});
4841 MIRBuilder.buildFPTOSI(DstReg, Round);
4842 MI.eraseFromParent();
4843 return Legalized;
4844 }
4845 case TargetOpcode::G_INTRINSIC_ROUND:
4846 return lowerIntrinsicRound(MI);
4847 case TargetOpcode::G_FRINT: {
4848 // Since round even is the assumed rounding mode for unconstrained FP
4849 // operations, rint and roundeven are the same operation.
4850 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4851 return Legalized;
4852 }
4853 case TargetOpcode::G_INTRINSIC_LRINT:
4854 case TargetOpcode::G_INTRINSIC_LLRINT: {
4855 Register DstReg = MI.getOperand(0).getReg();
4856 Register SrcReg = MI.getOperand(1).getReg();
4857 LLT SrcTy = MRI.getType(SrcReg);
4858 auto Round =
4859 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4860 MIRBuilder.buildFPTOSI(DstReg, Round);
4861 MI.eraseFromParent();
4862 return Legalized;
4863 }
4864 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4865 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4866 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4867 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4868 **MI.memoperands_begin());
4869 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4870 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4871 MI.eraseFromParent();
4872 return Legalized;
4873 }
4874 case TargetOpcode::G_LOAD:
4875 case TargetOpcode::G_SEXTLOAD:
4876 case TargetOpcode::G_ZEXTLOAD:
4877 return lowerLoad(cast<GAnyLoad>(MI));
4878 case TargetOpcode::G_STORE:
4879 return lowerStore(cast<GStore>(MI));
4880 case TargetOpcode::G_CTLZ_ZERO_POISON:
4881 case TargetOpcode::G_CTTZ_ZERO_POISON:
4882 case TargetOpcode::G_CTLZ:
4883 case TargetOpcode::G_CTTZ:
4884 case TargetOpcode::G_CTPOP:
4885 case TargetOpcode::G_CTLS:
4886 return lowerBitCount(MI);
4887 case G_UADDO: {
4888 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4889
4890 Register NewRes = MRI.cloneVirtualRegister(Res);
4891
4892 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4893 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4894
4895 MIRBuilder.buildCopy(Res, NewRes);
4896
4897 MI.eraseFromParent();
4898 return Legalized;
4899 }
4900 case G_UADDE: {
4901 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4902 const LLT CondTy = MRI.getType(CarryOut);
4903 const LLT Ty = MRI.getType(Res);
4904
4905 Register NewRes = MRI.cloneVirtualRegister(Res);
4906
4907 // Initial add of the two operands.
4908 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4909
4910 // Initial check for carry.
4911 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4912
4913 // Add the sum and the carry.
4914 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4915 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4916
4917 // Second check for carry. We can only carry if the initial sum is all 1s
4918 // and the carry is set, resulting in a new sum of 0.
4919 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4920 auto ResEqZero =
4921 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4922 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4923 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4924
4925 MIRBuilder.buildCopy(Res, NewRes);
4926
4927 MI.eraseFromParent();
4928 return Legalized;
4929 }
4930 case G_USUBO: {
4931 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4932
4933 MIRBuilder.buildSub(Res, LHS, RHS);
4934 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4935
4936 MI.eraseFromParent();
4937 return Legalized;
4938 }
4939 case G_USUBE: {
4940 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4941 const LLT CondTy = MRI.getType(BorrowOut);
4942 const LLT Ty = MRI.getType(Res);
4943
4944 // Initial subtract of the two operands.
4945 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4946
4947 // Initial check for borrow.
4948 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4949
4950 // Subtract the borrow from the first subtract.
4951 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4952 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4953
4954 // Second check for borrow. We can only borrow if the initial difference is
4955 // 0 and the borrow is set, resulting in a new difference of all 1s.
4956 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4957 auto TmpResEqZero =
4958 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4959 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4960 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4961
4962 MI.eraseFromParent();
4963 return Legalized;
4964 }
4965 case G_UITOFP:
4966 return lowerUITOFP(MI);
4967 case G_SITOFP:
4968 return lowerSITOFP(MI);
4969 case G_FPTOUI:
4970 return lowerFPTOUI(MI);
4971 case G_FPTOSI:
4972 return lowerFPTOSI(MI);
4973 case G_FPTOUI_SAT:
4974 case G_FPTOSI_SAT:
4975 return lowerFPTOINT_SAT(MI);
4976 case G_FPEXT:
4977 return lowerFPEXT(MI);
4978 case G_FPTRUNC:
4979 return lowerFPTRUNC(MI);
4980 case G_FPOWI:
4981 return lowerFPOWI(MI);
4982 case G_FMODF:
4983 return lowerFMODF(MI);
4984 case G_SMIN:
4985 case G_SMAX:
4986 case G_UMIN:
4987 case G_UMAX:
4988 return lowerMinMax(MI);
4989 case G_SCMP:
4990 case G_UCMP:
4991 return lowerThreewayCompare(MI);
4992 case G_FCOPYSIGN:
4993 return lowerFCopySign(MI);
4994 case G_FMINNUM:
4995 case G_FMAXNUM:
4996 case G_FMINIMUMNUM:
4997 case G_FMAXIMUMNUM:
4998 return lowerFMinNumMaxNum(MI);
4999 case G_FMINIMUM:
5000 case G_FMAXIMUM:
5001 return lowerFMinimumMaximum(MI);
5002 case G_MERGE_VALUES:
5003 return lowerMergeValues(MI);
5004 case G_UNMERGE_VALUES:
5005 return lowerUnmergeValues(MI);
5006 case TargetOpcode::G_SEXT_INREG: {
5007 assert(MI.getOperand(2).isImm() && "Expected immediate");
5008 int64_t SizeInBits = MI.getOperand(2).getImm();
5009
5010 auto [DstReg, SrcReg] = MI.getFirst2Regs();
5011 LLT DstTy = MRI.getType(DstReg);
5012 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
5013
5014 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
5015 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
5016 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
5017 MI.eraseFromParent();
5018 return Legalized;
5019 }
5020 case G_EXTRACT_VECTOR_ELT:
5021 case G_INSERT_VECTOR_ELT:
5023 case G_SHUFFLE_VECTOR:
5024 return lowerShuffleVector(MI);
5025 case G_VECTOR_COMPRESS:
5026 return lowerVECTOR_COMPRESS(MI);
5027 case G_DYN_STACKALLOC:
5028 return lowerDynStackAlloc(MI);
5029 case G_INSERT_SUBVECTOR: {
5030 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
5031 MRI.getType(MI.getOperand(2).getReg()).isScalable())
5032 return UnableToLegalize;
5033
5034 // Check that subvector is half size of main vector
5035 Register Vector = MI.getOperand(1).getReg();
5036 Register Subvector = MI.getOperand(2).getReg();
5037 auto InsertionPointImm = MI.getOperand(3).getImm();
5038
5039 LLT VectorTy = MRI.getType(Vector);
5040 LLT DstTy = MRI.getType(Subvector);
5041 // If so, -> concat(subvector, extract(half of vector))
5042 // (Operands can be either way round depending on insertion point
5043 if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
5044 bool InsertInLowHalf = InsertionPointImm == 0;
5045 auto Extract = MIRBuilder.buildExtractSubvector(
5046 DstTy, Vector,
5047 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
5048
5049 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
5050 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
5051
5052 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
5053 {LowHalf, HighHalf});
5054 MI.eraseFromParent();
5055 return Legalized;
5056 }
5057 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
5058 else {
5059 // Extend subvector to same size as vector
5060 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
5061 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
5062
5063 // Calculate mask required for this shuffle
5064 SmallVector<int> Mask;
5065 for (int i = 0; i < VectorTy.getNumElements(); i++) {
5066 // If this index is within bounds, put subvector's index into mask
5067 if (i >= InsertionPointImm &&
5068 i < InsertionPointImm + DstTy.getNumElements())
5069 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
5070 else
5071 Mask.push_back(i);
5072 }
5073
5074 // Build shuffle
5075 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
5076 Mask);
5077 MI.eraseFromParent();
5078 return Legalized;
5079 }
5080 }
5081 case G_EXTRACT_SUBVECTOR: {
5082 Register DstReg = MI.getOperand(0).getReg();
5083 Register SrcReg = MI.getOperand(1).getReg();
5084 uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
5085
5086 LLT SrcTy = MRI.getType(SrcReg);
5087 LLT DstTy = MRI.getType(DstReg);
5088
5089 if (SrcTy.isScalable())
5090 return UnableToLegalize;
5091
5092 if (SrcTy.getScalarType() != DstTy.getScalarType())
5093 return UnableToLegalize;
5094
5095 // extract_subvector = build_vector(extract_element, extract_element, ...)
5096 SmallVector<Register> ExtractedElements;
5097 for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
5098 ExtractedElements.push_back(
5100 .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
5101 ExtractionPointImm + i)
5102 .getReg(0));
5103 }
5104
5105 MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
5106 MI.eraseFromParent();
5107 return Legalized;
5108 }
5109 case G_STACKSAVE:
5110 return lowerStackSave(MI);
5111 case G_STACKRESTORE:
5112 return lowerStackRestore(MI);
5113 case G_EXTRACT:
5114 return lowerExtract(MI);
5115 case G_INSERT:
5116 return lowerInsert(MI);
5117 case G_BSWAP:
5118 return lowerBswap(MI);
5119 case G_BITREVERSE:
5120 return lowerBitreverse(MI);
5121 case G_READ_REGISTER:
5122 case G_WRITE_REGISTER:
5123 return lowerReadWriteRegister(MI);
5124 case G_UADDSAT:
5125 case G_USUBSAT: {
5126 // Try to make a reasonable guess about which lowering strategy to use. The
5127 // target can override this with custom lowering and calling the
5128 // implementation functions.
5129 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5130 if (LI.isLegalOrCustom({G_UMIN, Ty}))
5131 return lowerAddSubSatToMinMax(MI);
5133 }
5134 case G_SADDSAT:
5135 case G_SSUBSAT: {
5136 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5137
5138 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5139 // since it's a shorter expansion. However, we would need to figure out the
5140 // preferred boolean type for the carry out for the query.
5141 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5142 return lowerAddSubSatToMinMax(MI);
5144 }
5145 case G_SSHLSAT:
5146 case G_USHLSAT:
5147 return lowerShlSat(MI);
5148 case G_TRUNC_SSAT_S:
5149 case G_TRUNC_USAT_U:
5150 case G_TRUNC_SSAT_U:
5151 return lowerTruncSat(MI);
5152 case G_ABS:
5153 return lowerAbsToAddXor(MI);
5154 case G_ABDS:
5155 case G_ABDU: {
5156 bool IsSigned = MI.getOpcode() == G_ABDS;
5157 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5158 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5159 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5160 return lowerAbsDiffToMinMax(MI);
5161 }
5162 return lowerAbsDiffToSelect(MI);
5163 }
5164 case G_FABS:
5165 return lowerFAbs(MI);
5166 case G_SELECT:
5167 return lowerSelect(MI);
5168 case G_IS_FPCLASS:
5169 return lowerISFPCLASS(MI);
5170 case G_SDIVREM:
5171 case G_UDIVREM:
5172 return lowerDIVREM(MI);
5173 case G_FSHL:
5174 case G_FSHR:
5175 return lowerFunnelShift(MI);
5176 case G_ROTL:
5177 case G_ROTR:
5178 return lowerRotate(MI);
5179 case G_MEMSET:
5180 case G_MEMCPY:
5181 case G_MEMMOVE:
5182 case G_MEMCPY_INLINE:
5183 case G_MEMSET_INLINE:
5184 return lowerMemCpyFamily(MI);
5185 case G_ZEXT:
5186 case G_SEXT:
5187 case G_ANYEXT:
5188 return lowerEXT(MI);
5189 case G_TRUNC:
5190 return lowerTRUNC(MI);
5192 return lowerVectorReduction(MI);
5193 case G_VAARG:
5194 return lowerVAArg(MI);
5195 case G_ATOMICRMW_SUB: {
5196 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5197 const LLT ValTy = MRI.getType(Val);
5198 MachineMemOperand *MMO = *MI.memoperands_begin();
5199
5200 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5201 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5202 MI.eraseFromParent();
5203 return Legalized;
5204 }
5205 case G_SMULFIX:
5206 case G_UMULFIX:
5207 case G_SMULFIXSAT:
5208 case G_UMULFIXSAT:
5209 return lowerMulfix(MI);
5210 }
5211}
5212
5214 Align MinAlign) const {
5215 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5216 // datalayout for the preferred alignment. Also there should be a target hook
5217 // for this to allow targets to reduce the alignment and ignore the
5218 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5219 // the type.
5220 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5221}
5222
5225 MachinePointerInfo &PtrInfo) {
5226 MachineFunction &MF = MIRBuilder.getMF();
5227 const DataLayout &DL = MIRBuilder.getDataLayout();
5228 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5229
5230 unsigned AddrSpace = DL.getAllocaAddrSpace();
5231 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5232
5233 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5234 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5235}
5236
5238 const SrcOp &Val) {
5239 LLT SrcTy = Val.getLLTTy(MRI);
5240 Align StackTypeAlign =
5241 std::max(getStackTemporaryAlignment(SrcTy),
5243 MachinePointerInfo PtrInfo;
5244 auto StackTemp =
5245 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5246
5247 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5248 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5249}
5250
5252 LLT VecTy) {
5253 LLT IdxTy = B.getMRI()->getType(IdxReg);
5254 unsigned NElts = VecTy.getNumElements();
5255
5256 int64_t IdxVal;
5257 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5258 if (IdxVal < VecTy.getNumElements())
5259 return IdxReg;
5260 // If a constant index would be out of bounds, clamp it as well.
5261 }
5262
5263 if (isPowerOf2_32(NElts)) {
5265 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5266 }
5267
5268 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5269 .getReg(0);
5270}
5271
5273 Register Index) {
5274 LLT EltTy = VecTy.getElementType();
5275
5276 // Calculate the element offset and add it to the pointer.
5277 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5278 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5279 "Converting bits to bytes lost precision");
5280
5281 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5282
5283 // Convert index to the correct size for the address space.
5284 const DataLayout &DL = MIRBuilder.getDataLayout();
5285 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5286 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5287 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5288 if (IdxTy != MRI.getType(Index))
5289 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5290
5291 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5292 MIRBuilder.buildConstant(IdxTy, EltSize));
5293
5294 LLT PtrTy = MRI.getType(VecPtr);
5295 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5296}
5297
5298#ifndef NDEBUG
5299/// Check that all vector operands have same number of elements. Other operands
5300/// should be listed in NonVecOp.
5303 std::initializer_list<unsigned> NonVecOpIndices) {
5304 if (MI.getNumMemOperands() != 0)
5305 return false;
5306
5307 LLT VecTy = MRI.getType(MI.getReg(0));
5308 if (!VecTy.isVector())
5309 return false;
5310 unsigned NumElts = VecTy.getNumElements();
5311
5312 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5313 MachineOperand &Op = MI.getOperand(OpIdx);
5314 if (!Op.isReg()) {
5315 if (!is_contained(NonVecOpIndices, OpIdx))
5316 return false;
5317 continue;
5318 }
5319
5320 LLT Ty = MRI.getType(Op.getReg());
5321 if (!Ty.isVector()) {
5322 if (!is_contained(NonVecOpIndices, OpIdx))
5323 return false;
5324 continue;
5325 }
5326
5327 if (Ty.getNumElements() != NumElts)
5328 return false;
5329 }
5330
5331 return true;
5332}
5333#endif
5334
5335/// Fill \p DstOps with DstOps that have same number of elements combined as
5336/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5337/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5338/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5339static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5340 unsigned NumElts) {
5341 LLT LeftoverTy;
5342 assert(Ty.isVector() && "Expected vector type");
5343 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5344 int NumParts, NumLeftover;
5345 std::tie(NumParts, NumLeftover) =
5346 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5347
5348 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5349 for (int i = 0; i < NumParts; ++i) {
5350 DstOps.push_back(NarrowTy);
5351 }
5352
5353 if (LeftoverTy.isValid()) {
5354 assert(NumLeftover == 1 && "expected exactly one leftover");
5355 DstOps.push_back(LeftoverTy);
5356 }
5357}
5358
5359/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5360/// made from \p Op depending on operand type.
5362 MachineOperand &Op) {
5363 for (unsigned i = 0; i < N; ++i) {
5364 if (Op.isReg())
5365 Ops.push_back(Op.getReg());
5366 else if (Op.isImm())
5367 Ops.push_back(Op.getImm());
5368 else if (Op.isPredicate())
5369 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5370 else
5371 llvm_unreachable("Unsupported type");
5372 }
5373}
5374
5375// Handle splitting vector operations which need to have the same number of
5376// elements in each type index, but each type index may have a different element
5377// type.
5378//
5379// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5380// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5381// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5382//
5383// Also handles some irregular breakdown cases, e.g.
5384// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5385// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5386// s64 = G_SHL s64, s32
5389 GenericMachineInstr &MI, unsigned NumElts,
5390 std::initializer_list<unsigned> NonVecOpIndices) {
5391 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5392 "Non-compatible opcode or not specified non-vector operands");
5393 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5394
5395 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5396 unsigned NumDefs = MI.getNumDefs();
5397
5398 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5399 // Build instructions with DstOps to use instruction found by CSE directly.
5400 // CSE copies found instruction into given vreg when building with vreg dest.
5401 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5402 // Output registers will be taken from created instructions.
5403 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5404 for (unsigned i = 0; i < NumDefs; ++i) {
5405 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5406 }
5407
5408 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5409 // Operands listed in NonVecOpIndices will be used as is without splitting;
5410 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5411 // scalar condition (op 1), immediate in sext_inreg (op 2).
5412 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5413 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5414 ++UseIdx, ++UseNo) {
5415 if (is_contained(NonVecOpIndices, UseIdx)) {
5416 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5417 MI.getOperand(UseIdx));
5418 } else {
5419 SmallVector<Register, 8> SplitPieces;
5420 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5421 MRI);
5422 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5423 }
5424 }
5425
5426 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5427
5428 // Take i-th piece of each input operand split and build sub-vector/scalar
5429 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5430 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5432 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5433 Defs.push_back(OutputOpsPieces[DstNo][i]);
5434
5436 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5437 Uses.push_back(InputOpsPieces[InputNo][i]);
5438
5439 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5440 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5441 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5442 }
5443
5444 // Merge small outputs into MI's output for each def operand.
5445 if (NumLeftovers) {
5446 for (unsigned i = 0; i < NumDefs; ++i)
5447 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5448 } else {
5449 for (unsigned i = 0; i < NumDefs; ++i)
5450 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5451 }
5452
5453 MI.eraseFromParent();
5454 return Legalized;
5455}
5456
5459 unsigned NumElts) {
5460 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5461
5462 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5463 unsigned NumDefs = MI.getNumDefs();
5464
5465 SmallVector<DstOp, 8> OutputOpsPieces;
5466 SmallVector<Register, 8> OutputRegs;
5467 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5468
5469 // Instructions that perform register split will be inserted in basic block
5470 // where register is defined (basic block is in the next operand).
5471 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5472 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5473 UseIdx += 2, ++UseNo) {
5474 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5475 MIRBuilder.setInsertPt(
5476 OpMBB, getPHIIncomingInsertPoint(OpMBB, MI.getReg(UseIdx), MRI));
5477 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5478 MIRBuilder, MRI);
5479 }
5480
5481 // Build PHIs with fewer elements.
5482 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5483 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5484 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5485 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5486 Phi.addDef(
5487 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5488 OutputRegs.push_back(Phi.getReg(0));
5489
5490 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5491 Phi.addUse(InputOpsPieces[j][i]);
5492 Phi.add(MI.getOperand(1 + j * 2 + 1));
5493 }
5494 }
5495
5496 // Set the insert point after the existing PHIs
5497 MachineBasicBlock &MBB = *MI.getParent();
5498 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5499
5500 // Merge small outputs into MI's def.
5501 if (NumLeftovers) {
5502 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5503 } else {
5504 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5505 }
5506
5507 MI.eraseFromParent();
5508 return Legalized;
5509}
5510
5513 unsigned TypeIdx,
5514 LLT NarrowTy) {
5515 const int NumDst = MI.getNumOperands() - 1;
5516 const Register SrcReg = MI.getOperand(NumDst).getReg();
5517 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5518 LLT SrcTy = MRI.getType(SrcReg);
5519
5520 if (TypeIdx != 1 || NarrowTy == DstTy)
5521 return UnableToLegalize;
5522
5523 // Requires compatible types. Otherwise SrcReg should have been defined by
5524 // merge-like instruction that would get artifact combined. Most likely
5525 // instruction that defines SrcReg has to perform more/fewer elements
5526 // legalization compatible with NarrowTy.
5527 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5528 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5529
5530 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5531 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5532 return UnableToLegalize;
5533
5534 // This is most likely DstTy (smaller then register size) packed in SrcTy
5535 // (larger then register size) and since unmerge was not combined it will be
5536 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5537 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5538
5539 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5540 //
5541 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5542 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5543 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5544 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5545 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5546 const int PartsPerUnmerge = NumDst / NumUnmerge;
5547
5548 for (int I = 0; I != NumUnmerge; ++I) {
5549 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5550
5551 for (int J = 0; J != PartsPerUnmerge; ++J)
5552 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5553 MIB.addUse(Unmerge.getReg(I));
5554 }
5555
5556 MI.eraseFromParent();
5557 return Legalized;
5558}
5559
5562 LLT NarrowTy) {
5563 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5564 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5565 // that should have been artifact combined. Most likely instruction that uses
5566 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5567 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5568 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5569 if (NarrowTy == SrcTy)
5570 return UnableToLegalize;
5571
5572 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5573 // is for old mir tests. Since the changes to more/fewer elements it should no
5574 // longer be possible to generate MIR like this when starting from llvm-ir
5575 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5576 if (TypeIdx == 1) {
5577 assert(SrcTy.isVector() && "Expected vector types");
5578 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5579 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5580 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5581 return UnableToLegalize;
5582 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5583 //
5584 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5585 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5586 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5587 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5588 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5589 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5590
5592 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5593 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5594 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5595 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5596 Elts.push_back(Unmerge.getReg(j));
5597 }
5598
5599 SmallVector<Register, 8> NarrowTyElts;
5600 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5601 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5602 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5603 ++i, Offset += NumNarrowTyElts) {
5604 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5605 NarrowTyElts.push_back(
5606 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5607 }
5608
5609 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5610 MI.eraseFromParent();
5611 return Legalized;
5612 }
5613
5614 assert(TypeIdx == 0 && "Bad type index");
5615 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5616 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5617 return UnableToLegalize;
5618
5619 // This is most likely SrcTy (smaller then register size) packed in DstTy
5620 // (larger then register size) and since merge was not combined it will be
5621 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5622 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5623
5624 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5625 //
5626 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5627 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5628 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5629 SmallVector<Register, 8> NarrowTyElts;
5630 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5631 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5632 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5633 for (unsigned i = 0; i < NumParts; ++i) {
5635 for (unsigned j = 0; j < NumElts; ++j)
5636 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5637 NarrowTyElts.push_back(
5638 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5639 }
5640
5641 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5642 MI.eraseFromParent();
5643 return Legalized;
5644}
5645
5648 unsigned TypeIdx,
5649 LLT NarrowVecTy) {
5650 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5651 Register InsertVal;
5652 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5653
5654 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5655 if (IsInsert)
5656 InsertVal = MI.getOperand(2).getReg();
5657
5658 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5659 LLT VecTy = MRI.getType(SrcVec);
5660
5661 // If the index is a constant, we can really break this down as you would
5662 // expect, and index into the target size pieces.
5663 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5664 if (MaybeCst) {
5665 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5666 // Avoid out of bounds indexing the pieces.
5667 if (IdxVal >= VecTy.getNumElements()) {
5668 MIRBuilder.buildUndef(DstReg);
5669 MI.eraseFromParent();
5670 return Legalized;
5671 }
5672
5673 if (!NarrowVecTy.isVector()) {
5674 SmallVector<Register, 8> SplitPieces;
5675 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5676 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5677 if (IsInsert) {
5678 SplitPieces[IdxVal] = InsertVal;
5679 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5680 } else {
5681 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5682 }
5683 } else {
5684 SmallVector<Register, 8> VecParts;
5685 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5686
5687 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5688 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5689 TargetOpcode::G_ANYEXT);
5690
5691 unsigned NewNumElts = NarrowVecTy.getNumElements();
5692
5693 LLT IdxTy = MRI.getType(Idx);
5694 int64_t PartIdx = IdxVal / NewNumElts;
5695 auto NewIdx =
5696 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5697
5698 if (IsInsert) {
5699 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5700
5701 // Use the adjusted index to insert into one of the subvectors.
5702 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5703 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5704 VecParts[PartIdx] = InsertPart.getReg(0);
5705
5706 // Recombine the inserted subvector with the others to reform the result
5707 // vector.
5708 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5709 } else {
5710 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5711 }
5712 }
5713
5714 MI.eraseFromParent();
5715 return Legalized;
5716 }
5717
5718 // With a variable index, we can't perform the operation in a smaller type, so
5719 // we're forced to expand this.
5720 //
5721 // TODO: We could emit a chain of compare/select to figure out which piece to
5722 // index.
5724}
5725
5728 LLT NarrowTy) {
5729 // FIXME: Don't know how to handle secondary types yet.
5730 if (TypeIdx != 0)
5731 return UnableToLegalize;
5732
5733 if (!NarrowTy.isByteSized()) {
5734 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5735 return UnableToLegalize;
5736 }
5737
5738 // This implementation doesn't work for atomics. Give up instead of doing
5739 // something invalid.
5740 if (LdStMI.isAtomic())
5741 return UnableToLegalize;
5742
5743 bool IsLoad = isa<GLoad>(LdStMI);
5744 Register ValReg = LdStMI.getReg(0);
5745 Register AddrReg = LdStMI.getPointerReg();
5746 LLT ValTy = MRI.getType(ValReg);
5747
5748 // FIXME: Do we need a distinct NarrowMemory legalize action?
5749 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5750 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5751 return UnableToLegalize;
5752 }
5753
5754 int NumParts = -1;
5755 int NumLeftover = -1;
5756 LLT LeftoverTy;
5757 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5758 if (IsLoad) {
5759 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5760 } else {
5761 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5762 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5763 NumParts = NarrowRegs.size();
5764 NumLeftover = NarrowLeftoverRegs.size();
5765 }
5766 }
5767
5768 if (NumParts == -1)
5769 return UnableToLegalize;
5770
5771 LLT PtrTy = MRI.getType(AddrReg);
5772 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5773
5774 unsigned TotalSize = ValTy.getSizeInBits();
5775
5776 // Split the load/store into PartTy sized pieces starting at Offset. If this
5777 // is a load, return the new registers in ValRegs. For a store, each elements
5778 // of ValRegs should be PartTy. Returns the next offset that needs to be
5779 // handled.
5780 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5781 auto MMO = LdStMI.getMMO();
5782 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5783 unsigned NumParts, unsigned Offset) -> unsigned {
5784 MachineFunction &MF = MIRBuilder.getMF();
5785 unsigned PartSize = PartTy.getSizeInBits();
5786 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5787 ++Idx) {
5788 unsigned ByteOffset = Offset / 8;
5789 Register NewAddrReg;
5790
5791 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5792 ByteOffset);
5793
5794 MachineMemOperand *NewMMO =
5795 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5796
5797 if (IsLoad) {
5798 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5799 ValRegs.push_back(Dst);
5800 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5801 } else {
5802 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5803 }
5804 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5805 }
5806
5807 return Offset;
5808 };
5809
5810 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5811 unsigned HandledOffset =
5812 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5813
5814 // Handle the rest of the register if this isn't an even type breakdown.
5815 if (LeftoverTy.isValid())
5816 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5817
5818 if (IsLoad) {
5819 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5820 LeftoverTy, NarrowLeftoverRegs);
5821 }
5822
5823 LdStMI.eraseFromParent();
5824 return Legalized;
5825}
5826
5829 LLT NarrowTy) {
5830 using namespace TargetOpcode;
5832 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5833
5834 switch (MI.getOpcode()) {
5835 case G_IMPLICIT_DEF:
5836 case G_TRUNC:
5837 case G_AND:
5838 case G_OR:
5839 case G_XOR:
5840 case G_ADD:
5841 case G_SUB:
5842 case G_MUL:
5843 case G_PTR_ADD:
5844 case G_SMULH:
5845 case G_UMULH:
5846 case G_FADD:
5847 case G_FMUL:
5848 case G_FSUB:
5849 case G_FNEG:
5850 case G_FABS:
5851 case G_FCANONICALIZE:
5852 case G_FDIV:
5853 case G_FREM:
5854 case G_FMA:
5855 case G_FMAD:
5856 case G_FPOW:
5857 case G_FEXP:
5858 case G_FEXP2:
5859 case G_FEXP10:
5860 case G_FLOG:
5861 case G_FLOG2:
5862 case G_FLOG10:
5863 case G_FLDEXP:
5864 case G_FNEARBYINT:
5865 case G_FCEIL:
5866 case G_FFLOOR:
5867 case G_FRINT:
5868 case G_INTRINSIC_LRINT:
5869 case G_INTRINSIC_LLRINT:
5870 case G_INTRINSIC_ROUND:
5871 case G_INTRINSIC_ROUNDEVEN:
5872 case G_LROUND:
5873 case G_LLROUND:
5874 case G_INTRINSIC_TRUNC:
5875 case G_FMODF:
5876 case G_FCOS:
5877 case G_FSIN:
5878 case G_FTAN:
5879 case G_FACOS:
5880 case G_FASIN:
5881 case G_FATAN:
5882 case G_FATAN2:
5883 case G_FCOSH:
5884 case G_FSINH:
5885 case G_FTANH:
5886 case G_FSQRT:
5887 case G_BSWAP:
5888 case G_BITREVERSE:
5889 case G_SDIV:
5890 case G_UDIV:
5891 case G_SREM:
5892 case G_UREM:
5893 case G_SDIVREM:
5894 case G_UDIVREM:
5895 case G_SMIN:
5896 case G_SMAX:
5897 case G_UMIN:
5898 case G_UMAX:
5899 case G_ABS:
5900 case G_FMINNUM:
5901 case G_FMAXNUM:
5902 case G_FMINNUM_IEEE:
5903 case G_FMAXNUM_IEEE:
5904 case G_FMINIMUM:
5905 case G_FMAXIMUM:
5906 case G_FMINIMUMNUM:
5907 case G_FMAXIMUMNUM:
5908 case G_FSHL:
5909 case G_FSHR:
5910 case G_ROTL:
5911 case G_ROTR:
5912 case G_FREEZE:
5913 case G_SADDSAT:
5914 case G_SSUBSAT:
5915 case G_UADDSAT:
5916 case G_USUBSAT:
5917 case G_UMULO:
5918 case G_SMULO:
5919 case G_SHL:
5920 case G_LSHR:
5921 case G_ASHR:
5922 case G_SSHLSAT:
5923 case G_USHLSAT:
5924 case G_CTLZ:
5925 case G_CTLZ_ZERO_POISON:
5926 case G_CTTZ:
5927 case G_CTTZ_ZERO_POISON:
5928 case G_CTPOP:
5929 case G_CTLS:
5930 case G_FCOPYSIGN:
5931 case G_ZEXT:
5932 case G_SEXT:
5933 case G_ANYEXT:
5934 case G_FPEXT:
5935 case G_FPTRUNC:
5936 case G_SITOFP:
5937 case G_UITOFP:
5938 case G_FPTOSI:
5939 case G_FPTOUI:
5940 case G_FPTOSI_SAT:
5941 case G_FPTOUI_SAT:
5942 case G_INTTOPTR:
5943 case G_PTRTOINT:
5944 case G_ADDRSPACE_CAST:
5945 case G_UADDO:
5946 case G_USUBO:
5947 case G_UADDE:
5948 case G_USUBE:
5949 case G_SADDO:
5950 case G_SSUBO:
5951 case G_SADDE:
5952 case G_SSUBE:
5953 case G_STRICT_FADD:
5954 case G_STRICT_FSUB:
5955 case G_STRICT_FMUL:
5956 case G_STRICT_FMA:
5957 case G_STRICT_FLDEXP:
5958 case G_FFREXP:
5959 case G_TRUNC_SSAT_S:
5960 case G_TRUNC_SSAT_U:
5961 case G_TRUNC_USAT_U:
5962 return fewerElementsVectorMultiEltType(GMI, NumElts);
5963 case G_ICMP:
5964 case G_FCMP:
5965 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5966 case G_IS_FPCLASS:
5967 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5968 case G_SELECT:
5969 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5970 return fewerElementsVectorMultiEltType(GMI, NumElts);
5971 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5972 case G_PHI:
5973 return fewerElementsVectorPhi(GMI, NumElts);
5974 case G_UNMERGE_VALUES:
5975 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5976 case G_BUILD_VECTOR:
5977 assert(TypeIdx == 0 && "not a vector type index");
5978 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5979 case G_CONCAT_VECTORS:
5980 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5981 return UnableToLegalize;
5982 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5983 case G_EXTRACT_SUBVECTOR: {
5984 Register DstReg = MI.getOperand(0).getReg();
5985 LLT DstTy = MRI.getType(DstReg);
5986 Register SrcReg = MI.getOperand(1).getReg();
5987 uint64_t InsertionPointImm = MI.getOperand(2).getImm();
5988
5989 // If Dst > NarrowTy bits, then cannot legalize
5990 if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
5991 return UnableToLegalize;
5992
5993 // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
5994 if (!DstTy.getElementCount().isKnownMultipleOf(NarrowTy.getElementCount()))
5995 return UnableToLegalize;
5996
5997 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5998 uint64_t RequiredSubvectorIndex =
5999 InsertionPointImm / NarrowTy.getNumElements();
6000 // If Dst and Narrow are both same size, convert to a copy
6001 if (DstTy.getNumElements() == NarrowTy.getNumElements())
6002 MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
6003 else
6004 MIRBuilder.buildExtractSubvector(
6005 DstReg, Unmerge.getReg(RequiredSubvectorIndex),
6006 InsertionPointImm % NarrowTy.getNumElements());
6007
6008 MI.eraseFromParent();
6009 return Legalized;
6010 }
6011 case G_EXTRACT_VECTOR_ELT:
6012 case G_INSERT_VECTOR_ELT:
6013 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
6014 case G_LOAD:
6015 case G_STORE:
6016 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
6017 case G_SEXT_INREG:
6018 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
6020 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
6021 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
6022 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
6023 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
6024 case G_SHUFFLE_VECTOR:
6025 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
6026 case G_FPOWI:
6027 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
6028 case G_BITCAST:
6029 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
6030 case G_INTRINSIC_FPTRUNC_ROUND:
6031 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
6032 default:
6033 return UnableToLegalize;
6034 }
6035}
6036
6039 LLT NarrowTy) {
6040 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
6041 "Not a bitcast operation");
6042
6043 if (TypeIdx != 0)
6044 return UnableToLegalize;
6045
6046 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6047
6048 unsigned NewElemCount =
6049 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
6050 SmallVector<Register> SrcVRegs, BitcastVRegs;
6051 if (NewElemCount == 1) {
6052 LLT SrcNarrowTy = SrcTy.getElementType();
6053
6054 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
6055 getUnmergeResults(SrcVRegs, *Unmerge);
6056 } else {
6057 LLT SrcNarrowTy =
6059
6060 // Split the Src and Dst Reg into smaller registers
6061 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
6062 return UnableToLegalize;
6063 }
6064
6065 // Build new smaller bitcast instructions
6066 // Not supporting Leftover types for now but will have to
6067 for (Register Reg : SrcVRegs)
6068 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
6069
6070 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
6071 MI.eraseFromParent();
6072 return Legalized;
6073}
6074
6076 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6077 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
6078 if (TypeIdx != 0)
6079 return UnableToLegalize;
6080
6081 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
6082 MI.getFirst3RegLLTs();
6083 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6084 // The shuffle should be canonicalized by now.
6085 if (DstTy != Src1Ty)
6086 return UnableToLegalize;
6087 if (DstTy != Src2Ty)
6088 return UnableToLegalize;
6089
6090 if (!isPowerOf2_32(DstTy.getNumElements()))
6091 return UnableToLegalize;
6092
6093 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
6094 // Further legalization attempts will be needed to do split further.
6095 NarrowTy =
6096 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
6097 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
6098
6099 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
6100 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
6101 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
6102 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
6103 SplitSrc2Regs[1]};
6104
6105 Register Hi, Lo;
6106
6107 // If Lo or Hi uses elements from at most two of the four input vectors, then
6108 // express it as a vector shuffle of those two inputs. Otherwise extract the
6109 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
6111 for (unsigned High = 0; High < 2; ++High) {
6112 Register &Output = High ? Hi : Lo;
6113
6114 // Build a shuffle mask for the output, discovering on the fly which
6115 // input vectors to use as shuffle operands (recorded in InputUsed).
6116 // If building a suitable shuffle vector proves too hard, then bail
6117 // out with useBuildVector set.
6118 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
6119 unsigned FirstMaskIdx = High * NewElts;
6120 bool UseBuildVector = false;
6121 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6122 // The mask element. This indexes into the input.
6123 int Idx = Mask[FirstMaskIdx + MaskOffset];
6124
6125 // The input vector this mask element indexes into.
6126 unsigned Input = (unsigned)Idx / NewElts;
6127
6128 if (Input >= std::size(Inputs)) {
6129 // The mask element does not index into any input vector.
6130 Ops.push_back(-1);
6131 continue;
6132 }
6133
6134 // Turn the index into an offset from the start of the input vector.
6135 Idx -= Input * NewElts;
6136
6137 // Find or create a shuffle vector operand to hold this input.
6138 unsigned OpNo;
6139 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
6140 if (InputUsed[OpNo] == Input) {
6141 // This input vector is already an operand.
6142 break;
6143 } else if (InputUsed[OpNo] == -1U) {
6144 // Create a new operand for this input vector.
6145 InputUsed[OpNo] = Input;
6146 break;
6147 }
6148 }
6149
6150 if (OpNo >= std::size(InputUsed)) {
6151 // More than two input vectors used! Give up on trying to create a
6152 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
6153 UseBuildVector = true;
6154 break;
6155 }
6156
6157 // Add the mask index for the new shuffle vector.
6158 Ops.push_back(Idx + OpNo * NewElts);
6159 }
6160
6161 if (UseBuildVector) {
6162 LLT EltTy = NarrowTy.getElementType();
6164
6165 // Extract the input elements by hand.
6166 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6167 // The mask element. This indexes into the input.
6168 int Idx = Mask[FirstMaskIdx + MaskOffset];
6169
6170 // The input vector this mask element indexes into.
6171 unsigned Input = (unsigned)Idx / NewElts;
6172
6173 if (Input >= std::size(Inputs)) {
6174 // The mask element is "undef" or indexes off the end of the input.
6175 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6176 continue;
6177 }
6178
6179 // Turn the index into an offset from the start of the input vector.
6180 Idx -= Input * NewElts;
6181
6182 // Extract the vector element by hand.
6183 SVOps.push_back(MIRBuilder
6184 .buildExtractVectorElement(
6185 EltTy, Inputs[Input],
6186 MIRBuilder.buildConstant(LLT::integer(32), Idx))
6187 .getReg(0));
6188 }
6189
6190 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6191 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6192 } else if (InputUsed[0] == -1U) {
6193 // No input vectors were used! The result is undefined.
6194 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6195 } else if (NewElts == 1) {
6196 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6197 } else {
6198 Register Op0 = Inputs[InputUsed[0]];
6199 // If only one input was used, use an undefined vector for the other.
6200 Register Op1 = InputUsed[1] == -1U
6201 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6202 : Inputs[InputUsed[1]];
6203 // At least one input vector was used. Create a new shuffle vector.
6204 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6205 }
6206
6207 Ops.clear();
6208 }
6209
6210 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6211 MI.eraseFromParent();
6212 return Legalized;
6213}
6214
6216 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6217 auto &RdxMI = cast<GVecReduce>(MI);
6218
6219 if (TypeIdx != 1)
6220 return UnableToLegalize;
6221
6222 // The semantics of the normal non-sequential reductions allow us to freely
6223 // re-associate the operation.
6224 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6225
6226 if (NarrowTy.isVector() &&
6227 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6228 return UnableToLegalize;
6229
6230 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6231 SmallVector<Register> SplitSrcs;
6232 // If NarrowTy is a scalar then we're being asked to scalarize.
6233 const unsigned NumParts =
6234 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6235 : SrcTy.getNumElements();
6236
6237 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6238 if (NarrowTy.isScalar()) {
6239 if (DstTy != NarrowTy)
6240 return UnableToLegalize; // FIXME: handle implicit extensions.
6241
6242 if (isPowerOf2_32(NumParts)) {
6243 // Generate a tree of scalar operations to reduce the critical path.
6244 SmallVector<Register> PartialResults;
6245 unsigned NumPartsLeft = NumParts;
6246 while (NumPartsLeft > 1) {
6247 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6248 PartialResults.emplace_back(
6250 .buildInstr(ScalarOpc, {NarrowTy},
6251 {SplitSrcs[Idx], SplitSrcs[Idx + 1]},
6252 MI.getFlags())
6253 .getReg(0));
6254 }
6255 SplitSrcs = PartialResults;
6256 PartialResults.clear();
6257 NumPartsLeft = SplitSrcs.size();
6258 }
6259 assert(SplitSrcs.size() == 1);
6260 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6261 MI.eraseFromParent();
6262 return Legalized;
6263 }
6264 // If we can't generate a tree, then just do sequential operations.
6265 Register Acc = SplitSrcs[0];
6266 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6267 Acc = MIRBuilder
6268 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]},
6269 MI.getFlags())
6270 .getReg(0);
6271 MIRBuilder.buildCopy(DstReg, Acc);
6272 MI.eraseFromParent();
6273 return Legalized;
6274 }
6275 SmallVector<Register> PartialReductions;
6276 for (unsigned Part = 0; Part < NumParts; ++Part) {
6277 PartialReductions.push_back(MIRBuilder
6278 .buildInstr(RdxMI.getOpcode(), {DstTy},
6279 {SplitSrcs[Part]},
6280 MI.getFlags())
6281 .getReg(0));
6282 }
6283
6284 // If the types involved are powers of 2, we can generate intermediate vector
6285 // ops, before generating a final reduction operation.
6286 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6287 isPowerOf2_32(NarrowTy.getNumElements())) {
6288 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6289 }
6290
6291 Register Acc = PartialReductions[0];
6292 for (unsigned Part = 1; Part < NumParts; ++Part) {
6293 if (Part == NumParts - 1) {
6294 MIRBuilder.buildInstr(ScalarOpc, {DstReg}, {Acc, PartialReductions[Part]},
6295 MI.getFlags());
6296 } else {
6297 Acc = MIRBuilder
6298 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]},
6299 MI.getFlags())
6300 .getReg(0);
6301 }
6302 }
6303 MI.eraseFromParent();
6304 return Legalized;
6305}
6306
6309 unsigned int TypeIdx,
6310 LLT NarrowTy) {
6311 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6312 MI.getFirst3RegLLTs();
6313 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6314 DstTy != NarrowTy)
6315 return UnableToLegalize;
6316
6317 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6318 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6319 "Unexpected vecreduce opcode");
6320 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6321 ? TargetOpcode::G_FADD
6322 : TargetOpcode::G_FMUL;
6323
6324 SmallVector<Register> SplitSrcs;
6325 unsigned NumParts = SrcTy.getNumElements();
6326 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6327 Register Acc = ScalarReg;
6328 for (unsigned i = 0; i < NumParts; i++)
6329 Acc = MIRBuilder
6330 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]},
6331 MI.getFlags())
6332 .getReg(0);
6333
6334 MIRBuilder.buildCopy(DstReg, Acc);
6335 MI.eraseFromParent();
6336 return Legalized;
6337}
6338
6340LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6341 LLT SrcTy, LLT NarrowTy,
6342 unsigned ScalarOpc) {
6343 SmallVector<Register> SplitSrcs;
6344 // Split the sources into NarrowTy size pieces.
6345 extractParts(SrcReg, NarrowTy,
6346 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6347 MIRBuilder, MRI);
6348 // We're going to do a tree reduction using vector operations until we have
6349 // one NarrowTy size value left.
6350 while (SplitSrcs.size() > 1) {
6351 SmallVector<Register> PartialRdxs;
6352 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6353 Register LHS = SplitSrcs[Idx];
6354 Register RHS = SplitSrcs[Idx + 1];
6355 // Create the intermediate vector op.
6356 Register Res =
6358 .buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}, MI.getFlags())
6359 .getReg(0);
6360 PartialRdxs.push_back(Res);
6361 }
6362 SplitSrcs = std::move(PartialRdxs);
6363 }
6364 // Finally generate the requested NarrowTy based reduction.
6365 Observer.changingInstr(MI);
6366 MI.getOperand(1).setReg(SplitSrcs[0]);
6367 Observer.changedInstr(MI);
6368 return Legalized;
6369}
6370
6373 const LLT HalfTy, const LLT AmtTy) {
6374
6375 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6376 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6377 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6378
6379 if (Amt.isZero()) {
6380 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6381 MI.eraseFromParent();
6382 return Legalized;
6383 }
6384
6385 LLT NVT = HalfTy;
6386 unsigned NVTBits = HalfTy.getSizeInBits();
6387 unsigned VTBits = 2 * NVTBits;
6388
6389 SrcOp Lo(Register(0)), Hi(Register(0));
6390 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6391 if (Amt.ugt(VTBits)) {
6392 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6393 } else if (Amt.ugt(NVTBits)) {
6394 Lo = MIRBuilder.buildConstant(NVT, 0);
6395 Hi = MIRBuilder.buildShl(NVT, InL,
6396 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6397 } else if (Amt == NVTBits) {
6398 Lo = MIRBuilder.buildConstant(NVT, 0);
6399 Hi = InL;
6400 } else {
6401 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6402 auto OrLHS =
6403 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6404 auto OrRHS = MIRBuilder.buildLShr(
6405 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6406 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6407 }
6408 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6409 if (Amt.ugt(VTBits)) {
6410 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6411 } else if (Amt.ugt(NVTBits)) {
6412 Lo = MIRBuilder.buildLShr(NVT, InH,
6413 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6414 Hi = MIRBuilder.buildConstant(NVT, 0);
6415 } else if (Amt == NVTBits) {
6416 Lo = InH;
6417 Hi = MIRBuilder.buildConstant(NVT, 0);
6418 } else {
6419 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6420
6421 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6422 auto OrRHS = MIRBuilder.buildShl(
6423 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6424
6425 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6426 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6427 }
6428 } else {
6429 if (Amt.ugt(VTBits)) {
6430 Hi = Lo = MIRBuilder.buildAShr(
6431 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6432 } else if (Amt.ugt(NVTBits)) {
6433 Lo = MIRBuilder.buildAShr(NVT, InH,
6434 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6435 Hi = MIRBuilder.buildAShr(NVT, InH,
6436 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6437 } else if (Amt == NVTBits) {
6438 Lo = InH;
6439 Hi = MIRBuilder.buildAShr(NVT, InH,
6440 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6441 } else {
6442 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6443
6444 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6445 auto OrRHS = MIRBuilder.buildShl(
6446 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6447
6448 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6449 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6450 }
6451 }
6452
6453 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6454 MI.eraseFromParent();
6455
6456 return Legalized;
6457}
6458
6461 LLT RequestedTy) {
6462 if (TypeIdx == 1) {
6463 Observer.changingInstr(MI);
6464 narrowScalarSrc(MI, RequestedTy, 2);
6465 Observer.changedInstr(MI);
6466 return Legalized;
6467 }
6468
6469 Register DstReg = MI.getOperand(0).getReg();
6470 LLT DstTy = MRI.getType(DstReg);
6471 if (DstTy.isVector())
6472 return UnableToLegalize;
6473
6474 Register Amt = MI.getOperand(2).getReg();
6475 LLT ShiftAmtTy = MRI.getType(Amt);
6476 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6477 if (DstEltSize % 2 != 0)
6478 return UnableToLegalize;
6479
6480 // Check if we should use multi-way splitting instead of recursive binary
6481 // splitting.
6482 //
6483 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6484 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6485 // and dependency chains created by usual binary splitting approach
6486 // (128->64->32).
6487 //
6488 // The >= 8 parts threshold ensures we only use this optimization when binary
6489 // splitting would require multiple recursive passes, avoiding overhead for
6490 // simple 2-way splits where binary approach is sufficient.
6491 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6492 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6493 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6494 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6495 // steps).
6496 if (NumParts >= 8)
6497 return narrowScalarShiftMultiway(MI, RequestedTy);
6498 }
6499
6500 // Fall back to binary splitting:
6501 // Ignore the input type. We can only go to exactly half the size of the
6502 // input. If that isn't small enough, the resulting pieces will be further
6503 // legalized.
6504 const unsigned NewBitSize = DstEltSize / 2;
6505 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6506 const LLT CondTy = LLT::integer(1);
6507
6508 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6509 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6510 ShiftAmtTy);
6511 }
6512
6513 // TODO: Expand with known bits.
6514
6515 // Handle the fully general expansion by an unknown amount.
6516 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6517
6518 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6519 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6520 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6521
6522 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6523 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6524
6525 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6526 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6527 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6528
6529 Register ResultRegs[2];
6530 switch (MI.getOpcode()) {
6531 case TargetOpcode::G_SHL: {
6532 // Short: ShAmt < NewBitSize
6533 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6534
6535 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6536 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6537 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6538
6539 // Long: ShAmt >= NewBitSize
6540 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6541 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6542
6543 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6544 auto Hi = MIRBuilder.buildSelect(
6545 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6546
6547 ResultRegs[0] = Lo.getReg(0);
6548 ResultRegs[1] = Hi.getReg(0);
6549 break;
6550 }
6551 case TargetOpcode::G_LSHR:
6552 case TargetOpcode::G_ASHR: {
6553 // Short: ShAmt < NewBitSize
6554 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6555
6556 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6557 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6558 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6559
6560 // Long: ShAmt >= NewBitSize
6562 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6563 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6564 } else {
6565 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6566 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6567 }
6568 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6569 {InH, AmtExcess}); // Lo from Hi part.
6570
6571 auto Lo = MIRBuilder.buildSelect(
6572 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6573
6574 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6575
6576 ResultRegs[0] = Lo.getReg(0);
6577 ResultRegs[1] = Hi.getReg(0);
6578 break;
6579 }
6580 default:
6581 llvm_unreachable("not a shift");
6582 }
6583
6584 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6585 MI.eraseFromParent();
6586 return Legalized;
6587}
6588
6590 unsigned PartIdx,
6591 unsigned NumParts,
6592 ArrayRef<Register> SrcParts,
6593 const ShiftParams &Params,
6594 LLT TargetTy, LLT ShiftAmtTy) {
6595 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6596 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6597 assert(WordShiftConst && BitShiftConst && "Expected constants");
6598
6599 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6600 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6601 const bool NeedsInterWordShift = ShiftBits != 0;
6602
6603 switch (Opcode) {
6604 case TargetOpcode::G_SHL: {
6605 // Data moves from lower indices to higher indices
6606 // If this part would come from a source beyond our range, it's zero
6607 if (PartIdx < ShiftWords)
6608 return Params.Zero;
6609
6610 unsigned SrcIdx = PartIdx - ShiftWords;
6611 if (!NeedsInterWordShift)
6612 return SrcParts[SrcIdx];
6613
6614 // Combine shifted main part with carry from previous part
6615 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6616 if (SrcIdx > 0) {
6617 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6618 Params.InvBitShift);
6619 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6620 }
6621 return Hi.getReg(0);
6622 }
6623
6624 case TargetOpcode::G_LSHR: {
6625 unsigned SrcIdx = PartIdx + ShiftWords;
6626 if (SrcIdx >= NumParts)
6627 return Params.Zero;
6628 if (!NeedsInterWordShift)
6629 return SrcParts[SrcIdx];
6630
6631 // Combine shifted main part with carry from next part
6632 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6633 if (SrcIdx + 1 < NumParts) {
6634 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6635 Params.InvBitShift);
6636 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6637 }
6638 return Lo.getReg(0);
6639 }
6640
6641 case TargetOpcode::G_ASHR: {
6642 // Like LSHR but preserves sign bit
6643 unsigned SrcIdx = PartIdx + ShiftWords;
6644 if (SrcIdx >= NumParts)
6645 return Params.SignBit;
6646 if (!NeedsInterWordShift)
6647 return SrcParts[SrcIdx];
6648
6649 // Only the original MSB part uses arithmetic shift to preserve sign. All
6650 // other parts use logical shift since they're just moving data bits.
6651 auto Lo =
6652 (SrcIdx == NumParts - 1)
6653 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6654 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6655 Register HiSrc =
6656 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6657 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6658 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6659 }
6660
6661 default:
6662 llvm_unreachable("not a shift");
6663 }
6664}
6665
6667 Register MainOperand,
6668 Register ShiftAmt,
6669 LLT TargetTy,
6670 Register CarryOperand) {
6671 // This helper generates a single output part for variable shifts by combining
6672 // the main operand (shifted by BitShift) with carry bits from an adjacent
6673 // part.
6674
6675 // For G_ASHR, individual parts don't have their own sign bit, only the
6676 // complete value does. So we use LSHR for the main operand shift in ASHR
6677 // context.
6678 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6679 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6680 : Opcode;
6681
6682 // Perform the primary shift on the main operand
6683 Register MainShifted =
6684 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6685 .getReg(0);
6686
6687 // No carry operand available
6688 if (!CarryOperand.isValid())
6689 return MainShifted;
6690
6691 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6692 // so carry bits aren't needed.
6693 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6694 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6695 LLT BoolTy = LLT::integer(1);
6696 auto IsZeroBitShift =
6697 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6698
6699 // Extract bits from the adjacent part that will "carry over" into this part.
6700 // The carry direction is opposite to the main shift direction, so we can
6701 // align the two shifted values before combining them with OR.
6702
6703 // Determine the carry shift opcode (opposite direction)
6704 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6705 : TargetOpcode::G_SHL;
6706
6707 // Calculate inverse shift amount: BitWidth - ShiftAmt
6708 auto TargetBitsConst =
6709 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6710 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6711
6712 // Shift the carry operand
6713 Register CarryBits =
6715 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6716 .getReg(0);
6717
6718 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6719 // TargetBits which would be poison for the individual carry shift operation).
6720 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6721 Register SafeCarryBits =
6722 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6723 .getReg(0);
6724
6725 // Combine the main shifted part with the carry bits
6726 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6727}
6728
6731 const APInt &Amt,
6732 LLT TargetTy,
6733 LLT ShiftAmtTy) {
6734 // Any wide shift can be decomposed into WordShift + BitShift components.
6735 // When shift amount is known constant, directly compute the decomposition
6736 // values and generate constant registers.
6737 Register DstReg = MI.getOperand(0).getReg();
6738 Register SrcReg = MI.getOperand(1).getReg();
6739 LLT DstTy = MRI.getType(DstReg);
6740
6741 const unsigned DstBits = DstTy.getScalarSizeInBits();
6742 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6743 const unsigned NumParts = DstBits / TargetBits;
6744
6745 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6746
6747 // When the shift amount is known at compile time, we just calculate which
6748 // source parts contribute to each output part.
6749
6750 SmallVector<Register, 8> SrcParts;
6751 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6752
6753 if (Amt.isZero()) {
6754 // No shift needed, just copy
6755 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6756 MI.eraseFromParent();
6757 return Legalized;
6758 }
6759
6760 ShiftParams Params;
6761 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6762 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6763
6764 // Generate constants and values needed by all shift types
6765 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6766 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6767 Params.InvBitShift =
6768 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6769 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6770
6771 // For ASHR, we need the sign-extended value to fill shifted-out positions
6772 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6773 Params.SignBit =
6775 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6776 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6777 .getReg(0);
6778
6780 for (unsigned I = 0; I < NumParts; ++I)
6781 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6782 Params, TargetTy, ShiftAmtTy);
6783
6784 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6785 MI.eraseFromParent();
6786 return Legalized;
6787}
6788
6791 Register DstReg = MI.getOperand(0).getReg();
6792 Register SrcReg = MI.getOperand(1).getReg();
6793 Register AmtReg = MI.getOperand(2).getReg();
6794 LLT DstTy = MRI.getType(DstReg);
6795 LLT ShiftAmtTy = MRI.getType(AmtReg);
6796
6797 const unsigned DstBits = DstTy.getScalarSizeInBits();
6798 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6799 const unsigned NumParts = DstBits / TargetBits;
6800
6801 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6802 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6803
6804 // If the shift amount is known at compile time, we can use direct indexing
6805 // instead of generating select chains in the general case.
6806 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6807 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6808 ShiftAmtTy);
6809
6810 // For runtime-variable shift amounts, we must generate a more complex
6811 // sequence that handles all possible shift values using select chains.
6812
6813 // Split the input into target-sized pieces
6814 SmallVector<Register, 8> SrcParts;
6815 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6816
6817 // Shifting by zero should be a no-op.
6818 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6819 LLT BoolTy = LLT::integer(1);
6820 auto IsZeroShift =
6821 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6822
6823 // Any wide shift can be decomposed into two components:
6824 // 1. WordShift: number of complete target-sized words to shift
6825 // 2. BitShift: number of bits to shift within each word
6826 //
6827 // Example: 128-bit >> 50 with 32-bit target:
6828 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6829 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6830 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6831 auto TargetBitsLog2Const =
6832 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6833 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6834
6835 Register WordShift =
6836 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6837 Register BitShift =
6838 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6839
6840 // Fill values:
6841 // - SHL/LSHR: fill with zeros
6842 // - ASHR: fill with sign-extended MSB
6843 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6844
6845 Register FillValue;
6846 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6847 auto TargetBitsMinusOneConst =
6848 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6849 FillValue = MIRBuilder
6850 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6851 TargetBitsMinusOneConst)
6852 .getReg(0);
6853 } else {
6854 FillValue = ZeroReg;
6855 }
6856
6858
6859 // For each output part, generate a select chain that chooses the correct
6860 // result based on the runtime WordShift value. This handles all possible
6861 // word shift amounts by pre-calculating what each would produce.
6862 for (unsigned I = 0; I < NumParts; ++I) {
6863 // Initialize with appropriate default value for this shift type
6864 Register InBoundsResult = FillValue;
6865
6866 // clang-format off
6867 // Build a branchless select chain by pre-computing results for all possible
6868 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6869 //
6870 // K=0: select(WordShift==0, result0, FillValue)
6871 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6872 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6873 // clang-format on
6874 for (unsigned K = 0; K < NumParts; ++K) {
6875 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6876 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6877 WordShift, WordShiftKConst);
6878
6879 // Calculate source indices for this word shift
6880 //
6881 // For 4-part 128-bit value with K=1 word shift:
6882 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6883 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6884 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6885 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6886 int MainSrcIdx;
6887 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6888
6889 switch (MI.getOpcode()) {
6890 case TargetOpcode::G_SHL:
6891 MainSrcIdx = (int)I - (int)K;
6892 CarrySrcIdx = MainSrcIdx - 1;
6893 break;
6894 case TargetOpcode::G_LSHR:
6895 case TargetOpcode::G_ASHR:
6896 MainSrcIdx = (int)I + (int)K;
6897 CarrySrcIdx = MainSrcIdx + 1;
6898 break;
6899 default:
6900 llvm_unreachable("Not a shift");
6901 }
6902
6903 // Check bounds and build the result for this word shift
6904 Register ResultForK;
6905 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6906 Register MainOp = SrcParts[MainSrcIdx];
6907 Register CarryOp;
6908
6909 // Determine carry operand with bounds checking
6910 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6911 CarryOp = SrcParts[CarrySrcIdx];
6912 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6913 CarrySrcIdx >= (int)NumParts)
6914 CarryOp = FillValue; // Use sign extension
6915
6916 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6917 TargetTy, CarryOp);
6918 } else {
6919 // Out of bounds - use fill value for this k
6920 ResultForK = FillValue;
6921 }
6922
6923 // Select this result if WordShift equals k
6924 InBoundsResult =
6926 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6927 .getReg(0);
6928 }
6929
6930 // Handle zero-shift special case: if shift is 0, use original input
6931 DstParts[I] =
6933 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6934 .getReg(0);
6935 }
6936
6937 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6938 MI.eraseFromParent();
6939 return Legalized;
6940}
6941
6944 LLT MoreTy) {
6945 assert(TypeIdx == 0 && "Expecting only Idx 0");
6946
6947 Observer.changingInstr(MI);
6948 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6949 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6950 MIRBuilder.setInsertPt(OpMBB, getPHIIncomingInsertPoint(
6951 OpMBB, MI.getOperand(I).getReg(), MRI));
6952 moreElementsVectorSrc(MI, MoreTy, I);
6953 }
6954
6955 MachineBasicBlock &MBB = *MI.getParent();
6956 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6957 moreElementsVectorDst(MI, MoreTy, 0);
6958 Observer.changedInstr(MI);
6959 return Legalized;
6960}
6961
6962MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6963 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6964 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6965
6966 switch (Opcode) {
6967 default:
6969 "getNeutralElementForVecReduce called with invalid opcode!");
6970 case TargetOpcode::G_VECREDUCE_ADD:
6971 case TargetOpcode::G_VECREDUCE_OR:
6972 case TargetOpcode::G_VECREDUCE_XOR:
6973 case TargetOpcode::G_VECREDUCE_UMAX:
6974 return MIRBuilder.buildConstant(Ty, 0);
6975 case TargetOpcode::G_VECREDUCE_MUL:
6976 return MIRBuilder.buildConstant(Ty, 1);
6977 case TargetOpcode::G_VECREDUCE_AND:
6978 case TargetOpcode::G_VECREDUCE_UMIN:
6980 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6981 case TargetOpcode::G_VECREDUCE_SMAX:
6983 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6984 case TargetOpcode::G_VECREDUCE_SMIN:
6986 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6987 case TargetOpcode::G_VECREDUCE_FADD:
6988 return MIRBuilder.buildFConstant(Ty, -0.0);
6989 case TargetOpcode::G_VECREDUCE_FMUL:
6990 return MIRBuilder.buildFConstant(Ty, 1.0);
6991 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6992 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6993 assert(false && "getNeutralElementForVecReduce unimplemented for "
6994 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6995 }
6996 llvm_unreachable("switch expected to return!");
6997}
6998
7001 LLT MoreTy) {
7002 unsigned Opc = MI.getOpcode();
7003 switch (Opc) {
7004 case TargetOpcode::G_IMPLICIT_DEF:
7005 case TargetOpcode::G_LOAD: {
7006 if (TypeIdx != 0)
7007 return UnableToLegalize;
7008 Observer.changingInstr(MI);
7009 moreElementsVectorDst(MI, MoreTy, 0);
7010 Observer.changedInstr(MI);
7011 return Legalized;
7012 }
7013 case TargetOpcode::G_STORE:
7014 if (TypeIdx != 0)
7015 return UnableToLegalize;
7016 Observer.changingInstr(MI);
7017 moreElementsVectorSrc(MI, MoreTy, 0);
7018 Observer.changedInstr(MI);
7019 return Legalized;
7020 case TargetOpcode::G_AND:
7021 case TargetOpcode::G_OR:
7022 case TargetOpcode::G_XOR:
7023 case TargetOpcode::G_ADD:
7024 case TargetOpcode::G_SUB:
7025 case TargetOpcode::G_MUL:
7026 case TargetOpcode::G_FADD:
7027 case TargetOpcode::G_FSUB:
7028 case TargetOpcode::G_FMUL:
7029 case TargetOpcode::G_FDIV:
7030 case TargetOpcode::G_FCOPYSIGN:
7031 case TargetOpcode::G_UADDSAT:
7032 case TargetOpcode::G_USUBSAT:
7033 case TargetOpcode::G_SADDSAT:
7034 case TargetOpcode::G_SSUBSAT:
7035 case TargetOpcode::G_SMIN:
7036 case TargetOpcode::G_SMAX:
7037 case TargetOpcode::G_UMIN:
7038 case TargetOpcode::G_UMAX:
7039 case TargetOpcode::G_FMINNUM:
7040 case TargetOpcode::G_FMAXNUM:
7041 case TargetOpcode::G_FMINNUM_IEEE:
7042 case TargetOpcode::G_FMAXNUM_IEEE:
7043 case TargetOpcode::G_FMINIMUM:
7044 case TargetOpcode::G_FMAXIMUM:
7045 case TargetOpcode::G_FMINIMUMNUM:
7046 case TargetOpcode::G_FMAXIMUMNUM:
7047 case TargetOpcode::G_STRICT_FADD:
7048 case TargetOpcode::G_STRICT_FSUB:
7049 case TargetOpcode::G_STRICT_FMUL: {
7050 Observer.changingInstr(MI);
7051 moreElementsVectorSrc(MI, MoreTy, 1);
7052 moreElementsVectorSrc(MI, MoreTy, 2);
7053 moreElementsVectorDst(MI, MoreTy, 0);
7054 Observer.changedInstr(MI);
7055 return Legalized;
7056 }
7057 case TargetOpcode::G_SHL:
7058 case TargetOpcode::G_ASHR:
7059 case TargetOpcode::G_LSHR: {
7060 Observer.changingInstr(MI);
7061 moreElementsVectorSrc(MI, MoreTy, 1);
7062 // The shift operand may have a different scalar type from the source and
7063 // destination operands.
7064 LLT ShiftMoreTy = MoreTy.changeElementType(
7065 MRI.getType(MI.getOperand(2).getReg()).getElementType());
7066 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
7067 moreElementsVectorDst(MI, MoreTy, 0);
7068 Observer.changedInstr(MI);
7069 return Legalized;
7070 }
7071 case TargetOpcode::G_FMA:
7072 case TargetOpcode::G_STRICT_FMA:
7073 case TargetOpcode::G_FSHR:
7074 case TargetOpcode::G_FSHL: {
7075 Observer.changingInstr(MI);
7076 moreElementsVectorSrc(MI, MoreTy, 1);
7077 moreElementsVectorSrc(MI, MoreTy, 2);
7078 moreElementsVectorSrc(MI, MoreTy, 3);
7079 moreElementsVectorDst(MI, MoreTy, 0);
7080 Observer.changedInstr(MI);
7081 return Legalized;
7082 }
7083 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
7084 case TargetOpcode::G_EXTRACT:
7085 if (TypeIdx != 1)
7086 return UnableToLegalize;
7087 Observer.changingInstr(MI);
7088 moreElementsVectorSrc(MI, MoreTy, 1);
7089 Observer.changedInstr(MI);
7090 return Legalized;
7091 case TargetOpcode::G_INSERT:
7092 case TargetOpcode::G_INSERT_VECTOR_ELT:
7093 case TargetOpcode::G_FREEZE:
7094 case TargetOpcode::G_FNEG:
7095 case TargetOpcode::G_FABS:
7096 case TargetOpcode::G_FSQRT:
7097 case TargetOpcode::G_FCEIL:
7098 case TargetOpcode::G_FFLOOR:
7099 case TargetOpcode::G_FNEARBYINT:
7100 case TargetOpcode::G_FRINT:
7101 case TargetOpcode::G_INTRINSIC_ROUND:
7102 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
7103 case TargetOpcode::G_INTRINSIC_TRUNC:
7104 case TargetOpcode::G_BITREVERSE:
7105 case TargetOpcode::G_BSWAP:
7106 case TargetOpcode::G_FCANONICALIZE:
7107 case TargetOpcode::G_SEXT_INREG:
7108 case TargetOpcode::G_ABS:
7109 case TargetOpcode::G_CTLZ:
7110 case TargetOpcode::G_CTPOP:
7111 if (TypeIdx != 0)
7112 return UnableToLegalize;
7113 Observer.changingInstr(MI);
7114 moreElementsVectorSrc(MI, MoreTy, 1);
7115 moreElementsVectorDst(MI, MoreTy, 0);
7116 Observer.changedInstr(MI);
7117 return Legalized;
7118 case TargetOpcode::G_SELECT: {
7119 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
7120 if (TypeIdx == 1) {
7121 if (!CondTy.isScalar() ||
7122 DstTy.getElementCount() != MoreTy.getElementCount())
7123 return UnableToLegalize;
7124
7125 // This is turning a scalar select of vectors into a vector
7126 // select. Broadcast the select condition.
7127 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
7128 Observer.changingInstr(MI);
7129 MI.getOperand(1).setReg(ShufSplat.getReg(0));
7130 Observer.changedInstr(MI);
7131 return Legalized;
7132 }
7133
7134 if (CondTy.isVector())
7135 return UnableToLegalize;
7136
7137 Observer.changingInstr(MI);
7138 moreElementsVectorSrc(MI, MoreTy, 2);
7139 moreElementsVectorSrc(MI, MoreTy, 3);
7140 moreElementsVectorDst(MI, MoreTy, 0);
7141 Observer.changedInstr(MI);
7142 return Legalized;
7143 }
7144 case TargetOpcode::G_UNMERGE_VALUES:
7145 return UnableToLegalize;
7146 case TargetOpcode::G_PHI:
7147 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
7148 case TargetOpcode::G_SHUFFLE_VECTOR:
7149 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
7150 case TargetOpcode::G_BUILD_VECTOR: {
7152 for (auto Op : MI.uses()) {
7153 Elts.push_back(Op.getReg());
7154 }
7155
7156 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
7157 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
7158 }
7159
7160 MIRBuilder.buildDeleteTrailingVectorElements(
7161 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
7162 MI.eraseFromParent();
7163 return Legalized;
7164 }
7165 case TargetOpcode::G_SEXT:
7166 case TargetOpcode::G_ZEXT:
7167 case TargetOpcode::G_ANYEXT:
7168 case TargetOpcode::G_TRUNC:
7169 case TargetOpcode::G_FPTRUNC:
7170 case TargetOpcode::G_FPEXT:
7171 case TargetOpcode::G_FPTOSI:
7172 case TargetOpcode::G_FPTOUI:
7173 case TargetOpcode::G_FPTOSI_SAT:
7174 case TargetOpcode::G_FPTOUI_SAT:
7175 case TargetOpcode::G_SITOFP:
7176 case TargetOpcode::G_UITOFP:
7177 case TargetOpcode::G_TRUNC_SSAT_S:
7178 case TargetOpcode::G_TRUNC_SSAT_U:
7179 case TargetOpcode::G_TRUNC_USAT_U: {
7180 Observer.changingInstr(MI);
7181 LLT SrcExtTy;
7182 LLT DstExtTy;
7183 if (TypeIdx == 0) {
7184 DstExtTy = MoreTy;
7185 SrcExtTy = MoreTy.changeElementType(
7186 MRI.getType(MI.getOperand(1).getReg()).getElementType());
7187 } else {
7188 DstExtTy = MoreTy.changeElementType(
7189 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7190 SrcExtTy = MoreTy;
7191 }
7192 moreElementsVectorSrc(MI, SrcExtTy, 1);
7193 moreElementsVectorDst(MI, DstExtTy, 0);
7194 Observer.changedInstr(MI);
7195 return Legalized;
7196 }
7197 case TargetOpcode::G_ICMP:
7198 case TargetOpcode::G_FCMP: {
7199 if (TypeIdx != 1)
7200 return UnableToLegalize;
7201
7202 Observer.changingInstr(MI);
7203 moreElementsVectorSrc(MI, MoreTy, 2);
7204 moreElementsVectorSrc(MI, MoreTy, 3);
7205 LLT CondTy = MoreTy.changeVectorElementType(
7206 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7207 moreElementsVectorDst(MI, CondTy, 0);
7208 Observer.changedInstr(MI);
7209 return Legalized;
7210 }
7211 case TargetOpcode::G_BITCAST: {
7212 if (TypeIdx != 0)
7213 return UnableToLegalize;
7214
7215 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7216 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7217
7218 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7219 if (coefficient % DstTy.getNumElements() != 0)
7220 return UnableToLegalize;
7221
7222 coefficient = coefficient / DstTy.getNumElements();
7223
7224 LLT NewTy = SrcTy.changeElementCount(
7225 ElementCount::get(coefficient, MoreTy.isScalable()));
7226 Observer.changingInstr(MI);
7227 moreElementsVectorSrc(MI, NewTy, 1);
7228 moreElementsVectorDst(MI, MoreTy, 0);
7229 Observer.changedInstr(MI);
7230 return Legalized;
7231 }
7232 case TargetOpcode::G_VECREDUCE_FADD:
7233 case TargetOpcode::G_VECREDUCE_FMUL:
7234 case TargetOpcode::G_VECREDUCE_ADD:
7235 case TargetOpcode::G_VECREDUCE_MUL:
7236 case TargetOpcode::G_VECREDUCE_AND:
7237 case TargetOpcode::G_VECREDUCE_OR:
7238 case TargetOpcode::G_VECREDUCE_XOR:
7239 case TargetOpcode::G_VECREDUCE_SMAX:
7240 case TargetOpcode::G_VECREDUCE_SMIN:
7241 case TargetOpcode::G_VECREDUCE_UMAX:
7242 case TargetOpcode::G_VECREDUCE_UMIN: {
7243 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7244 MachineOperand &MO = MI.getOperand(1);
7245 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7246 auto NeutralElement = getNeutralElementForVecReduce(
7247 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7248
7249 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7250 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7251 i != e; i++) {
7252 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7253 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7254 NeutralElement, Idx);
7255 }
7256
7257 Observer.changingInstr(MI);
7258 MO.setReg(NewVec.getReg(0));
7259 Observer.changedInstr(MI);
7260 return Legalized;
7261 }
7262
7263 default:
7264 return UnableToLegalize;
7265 }
7266}
7267
7270 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7271 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7272 unsigned MaskNumElts = Mask.size();
7273 unsigned SrcNumElts = SrcTy.getNumElements();
7274 LLT DestEltTy = DstTy.getElementType();
7275
7276 if (MaskNumElts == SrcNumElts)
7277 return Legalized;
7278
7279 if (MaskNumElts < SrcNumElts) {
7280 // Extend mask to match new destination vector size with
7281 // undef values.
7282 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7283 llvm::copy(Mask, NewMask.begin());
7284
7285 moreElementsVectorDst(MI, SrcTy, 0);
7286 MIRBuilder.setInstrAndDebugLoc(MI);
7287 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7288 MI.getOperand(1).getReg(),
7289 MI.getOperand(2).getReg(), NewMask);
7290 MI.eraseFromParent();
7291
7292 return Legalized;
7293 }
7294
7295 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7296 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7297 LLT PaddedTy =
7298 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7299
7300 // Create new source vectors by concatenating the initial
7301 // source vectors with undefined vectors of the same size.
7302 auto Undef = MIRBuilder.buildUndef(SrcTy);
7303 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7304 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7305 MOps1[0] = MI.getOperand(1).getReg();
7306 MOps2[0] = MI.getOperand(2).getReg();
7307
7308 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7309 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7310
7311 // Readjust mask for new input vector length.
7312 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7313 for (unsigned I = 0; I != MaskNumElts; ++I) {
7314 int Idx = Mask[I];
7315 if (Idx >= static_cast<int>(SrcNumElts))
7316 Idx += PaddedMaskNumElts - SrcNumElts;
7317 MappedOps[I] = Idx;
7318 }
7319
7320 // If we got more elements than required, extract subvector.
7321 if (MaskNumElts != PaddedMaskNumElts) {
7322 auto Shuffle =
7323 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7324
7325 SmallVector<Register, 16> Elts(MaskNumElts);
7326 for (unsigned I = 0; I < MaskNumElts; ++I) {
7327 Elts[I] =
7328 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7329 .getReg(0);
7330 }
7331 MIRBuilder.buildBuildVector(DstReg, Elts);
7332 } else {
7333 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7334 }
7335
7336 MI.eraseFromParent();
7338}
7339
7342 unsigned int TypeIdx, LLT MoreTy) {
7343 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7344 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7345 unsigned NumElts = DstTy.getNumElements();
7346 unsigned WidenNumElts = MoreTy.getNumElements();
7347
7348 if (DstTy.isVector() && Src1Ty.isVector() &&
7349 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7351 }
7352
7353 if (TypeIdx != 0)
7354 return UnableToLegalize;
7355
7356 // Expect a canonicalized shuffle.
7357 if (DstTy != Src1Ty || DstTy != Src2Ty)
7358 return UnableToLegalize;
7359
7360 moreElementsVectorSrc(MI, MoreTy, 1);
7361 moreElementsVectorSrc(MI, MoreTy, 2);
7362
7363 // Adjust mask based on new input vector length.
7364 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7365 for (unsigned I = 0; I != NumElts; ++I) {
7366 int Idx = Mask[I];
7367 if (Idx < static_cast<int>(NumElts))
7368 NewMask[I] = Idx;
7369 else
7370 NewMask[I] = Idx - NumElts + WidenNumElts;
7371 }
7372 moreElementsVectorDst(MI, MoreTy, 0);
7373 MIRBuilder.setInstrAndDebugLoc(MI);
7374 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7375 MI.getOperand(1).getReg(),
7376 MI.getOperand(2).getReg(), NewMask);
7377 MI.eraseFromParent();
7378 return Legalized;
7379}
7380
7381void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7382 ArrayRef<Register> Src1Regs,
7383 ArrayRef<Register> Src2Regs,
7384 LLT NarrowTy) {
7386 unsigned SrcParts = Src1Regs.size();
7387 unsigned DstParts = DstRegs.size();
7388
7389 unsigned DstIdx = 0; // Low bits of the result.
7390 Register FactorSum =
7391 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7392 DstRegs[DstIdx] = FactorSum;
7393
7394 Register CarrySumPrevDstIdx;
7396
7397 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7398 // Collect high parts of muls from previous DstIdx.
7399 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7400 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7401 MachineInstrBuilder Umulh =
7402 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7403 Factors.push_back(Umulh.getReg(0));
7404 }
7405 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7406 // the low Src1 part, so multiply-add selectors can use it as the first
7407 // accumulated cross product.
7408 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7409 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7410 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7411 unsigned i = RevI - 1;
7413 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7414 Factors.push_back(Mul.getReg(0));
7415 }
7416 // Add CarrySum from additions calculated for previous DstIdx.
7417 if (DstIdx != 1) {
7418 Factors.push_back(CarrySumPrevDstIdx);
7419 }
7420
7421 Register CarrySum;
7422 // Add all factors and accumulate all carries into CarrySum.
7423 if (DstIdx != DstParts - 1) {
7424 MachineInstrBuilder Uaddo =
7425 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7426 FactorSum = Uaddo.getReg(0);
7427 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7428 for (unsigned i = 2; i < Factors.size(); ++i) {
7429 MachineInstrBuilder Uaddo =
7430 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7431 FactorSum = Uaddo.getReg(0);
7432 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7433 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7434 }
7435 } else {
7436 // Since value for the next index is not calculated, neither is CarrySum.
7437 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7438 for (unsigned i = 2; i < Factors.size(); ++i)
7439 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7440 }
7441
7442 CarrySumPrevDstIdx = CarrySum;
7443 DstRegs[DstIdx] = FactorSum;
7444 Factors.clear();
7445 }
7446}
7447
7450 LLT NarrowTy) {
7451 if (TypeIdx != 0)
7452 return UnableToLegalize;
7453
7454 Register DstReg = MI.getOperand(0).getReg();
7455 LLT DstType = MRI.getType(DstReg);
7456 // FIXME: add support for vector types
7457 if (DstType.isVector())
7458 return UnableToLegalize;
7459
7460 unsigned Opcode = MI.getOpcode();
7461 unsigned OpO, OpE, OpF;
7462 switch (Opcode) {
7463 case TargetOpcode::G_SADDO:
7464 case TargetOpcode::G_SADDE:
7465 case TargetOpcode::G_UADDO:
7466 case TargetOpcode::G_UADDE:
7467 case TargetOpcode::G_ADD:
7468 OpO = TargetOpcode::G_UADDO;
7469 OpE = TargetOpcode::G_UADDE;
7470 OpF = TargetOpcode::G_UADDE;
7471 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7472 OpF = TargetOpcode::G_SADDE;
7473 break;
7474 case TargetOpcode::G_SSUBO:
7475 case TargetOpcode::G_SSUBE:
7476 case TargetOpcode::G_USUBO:
7477 case TargetOpcode::G_USUBE:
7478 case TargetOpcode::G_SUB:
7479 OpO = TargetOpcode::G_USUBO;
7480 OpE = TargetOpcode::G_USUBE;
7481 OpF = TargetOpcode::G_USUBE;
7482 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7483 OpF = TargetOpcode::G_SSUBE;
7484 break;
7485 default:
7486 llvm_unreachable("Unexpected add/sub opcode!");
7487 }
7488
7489 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7490 unsigned NumDefs = MI.getNumExplicitDefs();
7491 Register Src1 = MI.getOperand(NumDefs).getReg();
7492 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7493 Register CarryDst, CarryIn;
7494 if (NumDefs == 2)
7495 CarryDst = MI.getOperand(1).getReg();
7496 if (MI.getNumOperands() == NumDefs + 3)
7497 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7498
7499 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7500 LLT LeftoverTy, DummyTy;
7501 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7502 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7503 MIRBuilder, MRI);
7504 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7505 MRI);
7506
7507 int NarrowParts = Src1Regs.size();
7508 Src1Regs.append(Src1Left);
7509 Src2Regs.append(Src2Left);
7510 DstRegs.reserve(Src1Regs.size());
7511
7512 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7513 Register DstReg =
7514 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7515 Register CarryOut;
7516 // Forward the final carry-out to the destination register
7517 if (i == e - 1 && CarryDst)
7518 CarryOut = CarryDst;
7519 else
7520 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7521
7522 if (!CarryIn) {
7523 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7524 {Src1Regs[i], Src2Regs[i]});
7525 } else if (i == e - 1) {
7526 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7527 {Src1Regs[i], Src2Regs[i], CarryIn});
7528 } else {
7529 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7530 {Src1Regs[i], Src2Regs[i], CarryIn});
7531 }
7532
7533 DstRegs.push_back(DstReg);
7534 CarryIn = CarryOut;
7535 }
7536 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7537 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7538 ArrayRef(DstRegs).drop_front(NarrowParts));
7539
7540 MI.eraseFromParent();
7541 return Legalized;
7542}
7543
7546 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7547
7548 LLT Ty = MRI.getType(DstReg);
7549 if (Ty.isVector())
7550 return UnableToLegalize;
7551
7552 unsigned Size = Ty.getSizeInBits();
7553 unsigned NarrowSize = NarrowTy.getSizeInBits();
7554 if (Size % NarrowSize != 0)
7555 return UnableToLegalize;
7556
7557 unsigned NumParts = Size / NarrowSize;
7558 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH ||
7559 MI.getOpcode() == TargetOpcode::G_SMULH;
7560 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7561
7562 SmallVector<Register, 2> Src1Parts, Src2Parts;
7563 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7564 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7565 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7566 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7567
7568 // Take only high half of registers if this is high mul.
7569 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7570
7571 if (MI.getOpcode() == TargetOpcode::G_SMULH) {
7572 Register UnsignedHigh = MRI.createGenericVirtualRegister(Ty);
7573 MIRBuilder.buildMergeLikeInstr(UnsignedHigh, DstRegs);
7574
7575 // Extract the sign from the highest narrow part of each operand.
7576 auto ShiftAmt = MIRBuilder.buildConstant(NarrowTy, NarrowSize - 1);
7577
7578 auto SignAPart =
7579 MIRBuilder.buildAShr(NarrowTy, Src1Parts.back(), ShiftAmt.getReg(0));
7580 auto SignBPart =
7581 MIRBuilder.buildAShr(NarrowTy, Src2Parts.back(), ShiftAmt.getReg(0));
7582
7583 // Replicate the sign parts to construct full-width sign masks.
7584 SmallVector<Register, 2> SignAParts(NumParts, SignAPart.getReg(0));
7585 SmallVector<Register, 2> SignBParts(NumParts, SignBPart.getReg(0));
7586
7587 auto SignA = MIRBuilder.buildMergeLikeInstr(Ty, SignAParts);
7588 auto SignB = MIRBuilder.buildMergeLikeInstr(Ty, SignBParts);
7589
7590 // Ca = (Src1 < 0) ? Src2 : 0
7591 // Cb = (Src2 < 0) ? Src1 : 0
7592 auto Ca = MIRBuilder.buildAnd(Ty, SignA, Src2);
7593 auto Cb = MIRBuilder.buildAnd(Ty, SignB, Src1);
7594
7595 // SignedHigh = UnsignedHigh - Ca - Cb
7596 auto Tmp = MIRBuilder.buildSub(Ty, UnsignedHigh, Ca);
7597 MIRBuilder.buildSub(DstReg, Tmp, Cb);
7598 } else {
7599 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7600 }
7601
7602 MI.eraseFromParent();
7603 return Legalized;
7604}
7605
7608 LLT NarrowTy) {
7609 if (TypeIdx != 0)
7610 return UnableToLegalize;
7611
7612 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7613
7614 Register Src = MI.getOperand(1).getReg();
7615 LLT SrcTy = MRI.getType(Src);
7616
7617 // If all finite floats fit into the narrowed integer type, we can just swap
7618 // out the result type. Only IEEE half qualifies: bfloat is also 16 bits wide
7619 // but has float's exponent range. LLT::float16() is equivalent to
7620 // LLT::scalar(16) on targets without extended LLTs.
7621 if (SrcTy.getScalarType() != LLT::float16() ||
7622 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7623 return UnableToLegalize;
7624
7625 Observer.changingInstr(MI);
7626 narrowScalarDst(MI, NarrowTy, 0,
7627 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7628 Observer.changedInstr(MI);
7629 return Legalized;
7630}
7631
7634 LLT NarrowTy) {
7635 if (TypeIdx != 1)
7636 return UnableToLegalize;
7637
7638 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7639
7640 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7641 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7642 // NarrowSize.
7643 if (SizeOp1 % NarrowSize != 0)
7644 return UnableToLegalize;
7645 int NumParts = SizeOp1 / NarrowSize;
7646
7647 SmallVector<Register, 2> SrcRegs, DstRegs;
7648 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7649 MIRBuilder, MRI);
7650
7651 Register OpReg = MI.getOperand(0).getReg();
7652 uint64_t OpStart = MI.getOperand(2).getImm();
7653 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7654 for (int i = 0; i < NumParts; ++i) {
7655 unsigned SrcStart = i * NarrowSize;
7656
7657 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7658 // No part of the extract uses this subregister, ignore it.
7659 continue;
7660 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7661 // The entire subregister is extracted, forward the value.
7662 DstRegs.push_back(SrcRegs[i]);
7663 continue;
7664 }
7665
7666 // OpSegStart is where this destination segment would start in OpReg if it
7667 // extended infinitely in both directions.
7668 int64_t ExtractOffset;
7669 uint64_t SegSize;
7670 if (OpStart < SrcStart) {
7671 ExtractOffset = 0;
7672 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7673 } else {
7674 ExtractOffset = OpStart - SrcStart;
7675 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7676 }
7677
7678 Register SegReg = SrcRegs[i];
7679 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7680 // A genuine extract is needed.
7681 SegReg = MRI.createGenericVirtualRegister(LLT::integer(SegSize));
7682 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7683 }
7684
7685 DstRegs.push_back(SegReg);
7686 }
7687
7688 Register DstReg = MI.getOperand(0).getReg();
7689 if (MRI.getType(DstReg).isVector())
7690 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7691 else if (DstRegs.size() > 1)
7692 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7693 else
7694 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7695 MI.eraseFromParent();
7696 return Legalized;
7697}
7698
7701 LLT NarrowTy) {
7702 // FIXME: Don't know how to handle secondary types yet.
7703 if (TypeIdx != 0)
7704 return UnableToLegalize;
7705
7706 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7707 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7708 LLT LeftoverTy;
7709 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7710 LeftoverRegs, MIRBuilder, MRI);
7711
7712 SrcRegs.append(LeftoverRegs);
7713
7714 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7715 Register OpReg = MI.getOperand(2).getReg();
7716 uint64_t OpStart = MI.getOperand(3).getImm();
7717 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7718 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7719 unsigned DstStart = I * NarrowSize;
7720
7721 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7722 // The entire subregister is defined by this insert, forward the new
7723 // value.
7724 DstRegs.push_back(OpReg);
7725 continue;
7726 }
7727
7728 Register SrcReg = SrcRegs[I];
7729 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7730 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7731 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7732 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7733 }
7734
7735 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7736 // No part of the insert affects this subregister, forward the original.
7737 DstRegs.push_back(SrcReg);
7738 continue;
7739 }
7740
7741 // OpSegStart is where this destination segment would start in OpReg if it
7742 // extended infinitely in both directions.
7743 int64_t ExtractOffset, InsertOffset;
7744 uint64_t SegSize;
7745 if (OpStart < DstStart) {
7746 InsertOffset = 0;
7747 ExtractOffset = DstStart - OpStart;
7748 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7749 } else {
7750 InsertOffset = OpStart - DstStart;
7751 ExtractOffset = 0;
7752 SegSize = std::min(NarrowSize - InsertOffset, OpSize);
7753 }
7754
7755 Register SegReg = OpReg;
7756 if (ExtractOffset != 0 || SegSize != OpSize) {
7757 // A genuine extract is needed.
7758 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7759 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7760 }
7761
7762 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7763 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7764 DstRegs.push_back(DstReg);
7765 }
7766
7767 uint64_t WideSize = DstRegs.size() * NarrowSize;
7768 Register DstReg = MI.getOperand(0).getReg();
7769 if (WideSize > RegTy.getSizeInBits()) {
7770 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7771 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7772 MIRBuilder.buildTrunc(DstReg, MergeReg);
7773 } else
7774 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7775
7776 MI.eraseFromParent();
7777 return Legalized;
7778}
7779
7782 LLT NarrowTy) {
7783 Register DstReg = MI.getOperand(0).getReg();
7784 LLT DstTy = MRI.getType(DstReg);
7785
7786 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7787
7788 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7789 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7790 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7791 LLT LeftoverTy;
7792 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7793 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7794 return UnableToLegalize;
7795
7796 LLT Unused;
7797 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7798 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7799 llvm_unreachable("inconsistent extractParts result");
7800
7801 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7802 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7803 {Src0Regs[I], Src1Regs[I]});
7804 DstRegs.push_back(Inst.getReg(0));
7805 }
7806
7807 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7808 auto Inst = MIRBuilder.buildInstr(
7809 MI.getOpcode(),
7810 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7811 DstLeftoverRegs.push_back(Inst.getReg(0));
7812 }
7813
7814 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7815 LeftoverTy, DstLeftoverRegs);
7816
7817 MI.eraseFromParent();
7818 return Legalized;
7819}
7820
7823 LLT NarrowTy) {
7824 if (TypeIdx != 0)
7825 return UnableToLegalize;
7826
7827 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7828
7829 LLT DstTy = MRI.getType(DstReg);
7830 if (DstTy.isVector())
7831 return UnableToLegalize;
7832
7834 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7835 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7836 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7837
7838 MI.eraseFromParent();
7839 return Legalized;
7840}
7841
7844 LLT NarrowTy) {
7845 if (TypeIdx != 0)
7846 return UnableToLegalize;
7847
7848 Register CondReg = MI.getOperand(1).getReg();
7849 LLT CondTy = MRI.getType(CondReg);
7850 if (CondTy.isVector()) // TODO: Handle vselect
7851 return UnableToLegalize;
7852
7853 Register DstReg = MI.getOperand(0).getReg();
7854 LLT DstTy = MRI.getType(DstReg);
7855
7856 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7857 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7858 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7859 LLT LeftoverTy;
7860 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7861 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7862 return UnableToLegalize;
7863
7864 LLT Unused;
7865 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7866 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7867 llvm_unreachable("inconsistent extractParts result");
7868
7869 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7870 auto Select = MIRBuilder.buildSelect(NarrowTy,
7871 CondReg, Src1Regs[I], Src2Regs[I]);
7872 DstRegs.push_back(Select.getReg(0));
7873 }
7874
7875 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7876 auto Select = MIRBuilder.buildSelect(
7877 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7878 DstLeftoverRegs.push_back(Select.getReg(0));
7879 }
7880
7881 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7882 LeftoverTy, DstLeftoverRegs);
7883
7884 MI.eraseFromParent();
7885 return Legalized;
7886}
7887
7890 LLT NarrowTy) {
7891 if (TypeIdx != 1)
7892 return UnableToLegalize;
7893
7894 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7895 unsigned NarrowSize = NarrowTy.getSizeInBits();
7896
7897 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7898 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7899
7901 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7902 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7903 auto C_0 = B.buildConstant(NarrowTy, 0);
7904 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7905 UnmergeSrc.getReg(1), C_0);
7906 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7907 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7908 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7909 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7910 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7911 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7912
7913 MI.eraseFromParent();
7914 return Legalized;
7915 }
7916
7917 return UnableToLegalize;
7918}
7919
7922 LLT NarrowTy) {
7923 if (TypeIdx != 1)
7924 return UnableToLegalize;
7925
7926 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7927 unsigned NarrowSize = NarrowTy.getSizeInBits();
7928
7929 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7930 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7931
7933 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7934 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7935 auto C_0 = B.buildConstant(NarrowTy, 0);
7936 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7937 UnmergeSrc.getReg(0), C_0);
7938 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7939 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7940 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7941 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7942 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7943 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7944
7945 MI.eraseFromParent();
7946 return Legalized;
7947 }
7948
7949 return UnableToLegalize;
7950}
7951
7954 LLT NarrowTy) {
7955 if (TypeIdx != 1)
7956 return UnableToLegalize;
7957
7958 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7959 unsigned NarrowSize = NarrowTy.getSizeInBits();
7960
7961 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7962 return UnableToLegalize;
7963
7965
7966 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7967 Register Lo = UnmergeSrc.getReg(0);
7968 Register Hi = UnmergeSrc.getReg(1);
7969
7970 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7971 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7972
7973 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7974
7975 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7976 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7977 // Otherwise the leading zeros represent additional sign bits of the original
7978 // value.
7979 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7980 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7981
7982 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7983 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7984 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7985
7986 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7987
7988 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7989
7990 MI.eraseFromParent();
7991 return Legalized;
7992}
7993
7996 LLT NarrowTy) {
7997 if (TypeIdx != 1)
7998 return UnableToLegalize;
7999
8000 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8001 unsigned NarrowSize = NarrowTy.getSizeInBits();
8002
8003 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
8004 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
8005
8006 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
8007 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
8008 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
8009
8010 MI.eraseFromParent();
8011 return Legalized;
8012 }
8013
8014 return UnableToLegalize;
8015}
8016
8019 LLT NarrowTy) {
8020 if (TypeIdx != 1)
8021 return UnableToLegalize;
8022
8024 Register ExpReg = MI.getOperand(2).getReg();
8025 LLT ExpTy = MRI.getType(ExpReg);
8026
8027 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
8028
8029 // Clamp the exponent to the range of the target type.
8030 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
8031 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
8032 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
8033 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
8034
8035 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
8036 Observer.changingInstr(MI);
8037 MI.getOperand(2).setReg(Trunc.getReg(0));
8038 Observer.changedInstr(MI);
8039 return Legalized;
8040}
8041
8044 unsigned Opc = MI.getOpcode();
8045 const auto &TII = MIRBuilder.getTII();
8046 auto isSupported = [this](const LegalityQuery &Q) {
8047 auto QAction = LI.getAction(Q).Action;
8048 return QAction == Legal || QAction == Libcall || QAction == Custom;
8049 };
8050 switch (Opc) {
8051 default:
8052 return UnableToLegalize;
8053 case TargetOpcode::G_CTLZ_ZERO_POISON: {
8054 // This trivially expands to CTLZ.
8055 Observer.changingInstr(MI);
8056 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
8057 Observer.changedInstr(MI);
8058 return Legalized;
8059 }
8060 case TargetOpcode::G_CTLZ: {
8061 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8062 unsigned Len = SrcTy.getScalarSizeInBits();
8063
8064 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
8065 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
8066 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
8067 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
8068 auto ICmp = MIRBuilder.buildICmp(
8069 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
8070 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
8071 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
8072 MI.eraseFromParent();
8073 return Legalized;
8074 }
8075 // for now, we do this:
8076 // NewLen = NextPowerOf2(Len);
8077 // x = x | (x >> 1);
8078 // x = x | (x >> 2);
8079 // ...
8080 // x = x | (x >>16);
8081 // x = x | (x >>32); // for 64-bit input
8082 // Upto NewLen/2
8083 // return Len - popcount(x);
8084 //
8085 // Ref: "Hacker's Delight" by Henry Warren
8086 Register Op = SrcReg;
8087 unsigned NewLen = PowerOf2Ceil(Len);
8088 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
8089 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
8090 auto MIBOp = MIRBuilder.buildOr(
8091 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
8092 Op = MIBOp.getReg(0);
8093 }
8094 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
8095 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
8096 MIBPop);
8097 MI.eraseFromParent();
8098 return Legalized;
8099 }
8100 case TargetOpcode::G_CTTZ_ZERO_POISON: {
8101 // This trivially expands to CTTZ.
8102 Observer.changingInstr(MI);
8103 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
8104 Observer.changedInstr(MI);
8105 return Legalized;
8106 }
8107 case TargetOpcode::G_CTTZ: {
8108 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8109
8110 unsigned Len = SrcTy.getScalarSizeInBits();
8111 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
8112 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
8113 // zero.
8114 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
8115 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
8116 auto ICmp = MIRBuilder.buildICmp(
8117 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
8118 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
8119 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
8120 MI.eraseFromParent();
8121 return Legalized;
8122 }
8123 // for now, we use: { return popcount(~x & (x - 1)); }
8124 // unless the target has ctlz but not ctpop, in which case we use:
8125 // { return 32 - nlz(~x & (x-1)); }
8126 // Ref: "Hacker's Delight" by Henry Warren
8127 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
8128 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
8129 auto MIBTmp = MIRBuilder.buildAnd(
8130 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
8131 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
8132 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
8133 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
8134 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
8135 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
8136 MI.eraseFromParent();
8137 return Legalized;
8138 }
8139 Observer.changingInstr(MI);
8140 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
8141 MI.getOperand(1).setReg(MIBTmp.getReg(0));
8142 Observer.changedInstr(MI);
8143 return Legalized;
8144 }
8145 case TargetOpcode::G_CTPOP: {
8146 Register SrcReg = MI.getOperand(1).getReg();
8147 LLT Ty = MRI.getType(SrcReg);
8148 unsigned Size = Ty.getScalarSizeInBits();
8150
8151 // Bail out on irregular type lengths.
8152 if (Size > 128 || Size % 8 != 0)
8153 return UnableToLegalize;
8154
8155 // Count set bits in blocks of 2 bits. Default approach would be
8156 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
8157 // We use following formula instead:
8158 // B2Count = val - { (val >> 1) & 0x55555555 }
8159 // since it gives same result in blocks of 2 with one instruction less.
8160 auto C_1 = B.buildConstant(Ty, 1);
8161 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
8162 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
8163 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
8164 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
8165 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
8166
8167 // In order to get count in blocks of 4 add values from adjacent block of 2.
8168 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
8169 auto C_2 = B.buildConstant(Ty, 2);
8170 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
8171 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
8172 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
8173 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
8174 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
8175 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
8176
8177 // For count in blocks of 8 bits we don't have to mask high 4 bits before
8178 // addition since count value sits in range {0,...,8} and 4 bits are enough
8179 // to hold such binary values. After addition high 4 bits still hold count
8180 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
8181 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
8182 auto C_4 = B.buildConstant(Ty, 4);
8183 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
8184 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
8185 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
8186 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
8187 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
8188
8189 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
8190
8191 // Avoid the multiply when shift-add is cheaper.
8192 if (Size == 16 && !Ty.isVector()) {
8193 // v = (v + (v >> 8)) & 0xFF;
8194 auto C_8 = B.buildConstant(Ty, 8);
8195 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
8196 auto Res = B.buildAdd(Ty, B8Count, HighSum);
8197 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
8198 MI.eraseFromParent();
8199 return Legalized;
8200 }
8201
8202 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
8203 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
8204 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
8205
8206 // Shift count result from 8 high bits to low bits.
8207 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
8208
8209 auto IsMulSupported = [this](const LLT Ty) {
8210 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
8211 return Action == Legal || Action == WidenScalar || Action == Custom;
8212 };
8213 if (IsMulSupported(Ty)) {
8214 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
8215 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8216 } else {
8217 auto ResTmp = B8Count;
8218 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
8219 auto ShiftC = B.buildConstant(Ty, Shift);
8220 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
8221 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
8222 }
8223 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8224 }
8225 MI.eraseFromParent();
8226 return Legalized;
8227 }
8228 case TargetOpcode::G_CTLS: {
8229 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8230
8231 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
8232 auto SignIdxC =
8233 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
8234 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
8235
8236 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
8237
8238 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
8239 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
8240
8241 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8242 MI.eraseFromParent();
8243 return Legalized;
8244 }
8245 }
8246}
8247
8248// Check that (every element of) Reg is undef or not an exact multiple of BW.
8250 Register Reg, unsigned BW) {
8251 return matchUnaryPredicate(
8252 MRI, Reg,
8253 [=](const Constant *C) {
8254 // Null constant here means an undef.
8256 return !CI || CI->getValue().urem(BW) != 0;
8257 },
8258 /*AllowUndefs*/ true);
8259}
8260
8261// Check that (every element of) Reg is a constant that is not an exact multiple
8262// of BW.
8264 unsigned BW) {
8265 return matchUnaryPredicate(MRI, Reg, [=](const Constant *C) {
8266 return cast<ConstantInt>(C)->getValue().urem(BW) != 0;
8267 });
8268}
8269
8272 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8273 LLT Ty = MRI.getType(Dst);
8274 LLT ShTy = MRI.getType(Z);
8275
8276 unsigned BW = Ty.getScalarSizeInBits();
8277
8278 if (!isPowerOf2_32(BW))
8279 return UnableToLegalize;
8280
8281 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8282 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8283
8284 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8285 // fshl X, Y, Z -> fshr X, Y, -Z
8286 // fshr X, Y, Z -> fshl X, Y, -Z
8287 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8288 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8289 } else {
8290 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8291 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8292 auto One = MIRBuilder.buildConstant(ShTy, 1);
8293 if (IsFSHL) {
8294 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8295 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8296 } else {
8297 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8298 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8299 }
8300
8301 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8302 }
8303
8304 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8305 MI.eraseFromParent();
8306 return Legalized;
8307}
8308
8311 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8312 LLT Ty = MRI.getType(Dst);
8313 LLT ShTy = MRI.getType(Z);
8314
8315 const unsigned BW = Ty.getScalarSizeInBits();
8316 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8317
8318 Register ShX, ShY;
8319 Register ShAmt, InvShAmt;
8320 unsigned OrFlags = MachineInstr::NoFlags;
8321
8322 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8323 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8324 // fshl: X << C | Y >> (BW - C)
8325 // fshr: X << (BW - C) | Y >> C
8326 // where C = Z % BW is not zero
8327 // If Z has undef elements, C may be zero so the or isn't disjoint.
8328 if (isNonZeroModBitWidth(MRI, Z, BW))
8329 OrFlags |= MachineInstr::Disjoint;
8330 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8331 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8332 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8333 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8334 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8335 } else {
8336 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8337 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8338 // The extra shift by 1 guarantees the two sides don't overlap.
8339 OrFlags |= MachineInstr::Disjoint;
8340 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8341 if (isPowerOf2_32(BW)) {
8342 // Z % BW -> Z & (BW - 1)
8343 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8344 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8345 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8346 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8347 } else {
8348 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8349 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8350 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8351 }
8352
8353 auto One = MIRBuilder.buildConstant(ShTy, 1);
8354 if (IsFSHL) {
8355 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8356 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8357 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8358 } else {
8359 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8360 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8361 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8362 }
8363 }
8364
8365 MIRBuilder.buildOr(Dst, ShX, ShY, OrFlags);
8366 MI.eraseFromParent();
8367 return Legalized;
8368}
8369
8372 // These operations approximately do the following (while avoiding undefined
8373 // shifts by BW):
8374 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8375 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8376 Register Dst = MI.getOperand(0).getReg();
8377 LLT Ty = MRI.getType(Dst);
8378 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8379
8380 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8381 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8382
8383 // TODO: Use smarter heuristic that accounts for vector legalization.
8384 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8385 return lowerFunnelShiftAsShifts(MI);
8386
8387 // This only works for powers of 2, fallback to shifts if it fails.
8388 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8389 if (Result == UnableToLegalize)
8390 return lowerFunnelShiftAsShifts(MI);
8391 return Result;
8392}
8393
8395 auto [Dst, Src] = MI.getFirst2Regs();
8396 LLT DstTy = MRI.getType(Dst);
8397 LLT SrcTy = MRI.getType(Src);
8398
8399 uint32_t DstTySize = DstTy.getSizeInBits();
8400 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8401 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8402
8403 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8404 !isPowerOf2_32(SrcTyScalarSize))
8405 return UnableToLegalize;
8406
8407 // The step between extend is too large, split it by creating an intermediate
8408 // extend instruction
8409 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8410 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8411 // If the destination type is illegal, split it into multiple statements
8412 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8413 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8414 // Unmerge the vector
8415 LLT EltTy = MidTy.changeElementCount(
8417 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8418
8419 // ZExt the vectors
8420 LLT ZExtResTy = DstTy.changeElementCount(
8422 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8423 {UnmergeSrc.getReg(0)});
8424 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8425 {UnmergeSrc.getReg(1)});
8426
8427 // Merge the ending vectors
8428 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8429
8430 MI.eraseFromParent();
8431 return Legalized;
8432 }
8433 return UnableToLegalize;
8434}
8435
8437 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8438 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8439 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8440 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8441 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8442 // %lo16(<4 x s16>) = G_TRUNC %inlo
8443 // %hi16(<4 x s16>) = G_TRUNC %inhi
8444 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8445 // %res(<8 x s8>) = G_TRUNC %in16
8446
8447 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8448
8449 Register DstReg = MI.getOperand(0).getReg();
8450 Register SrcReg = MI.getOperand(1).getReg();
8451 LLT DstTy = MRI.getType(DstReg);
8452 LLT SrcTy = MRI.getType(SrcReg);
8453
8454 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8456 isPowerOf2_32(SrcTy.getNumElements()) &&
8457 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8458 // Split input type.
8459 LLT SplitSrcTy = SrcTy.changeElementCount(
8460 SrcTy.getElementCount().divideCoefficientBy(2));
8461
8462 // First, split the source into two smaller vectors.
8463 SmallVector<Register, 2> SplitSrcs;
8464 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8465
8466 // Truncate the splits into intermediate narrower elements.
8467 LLT InterTy;
8468 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8469 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8470 else
8471 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8472 for (Register &Src : SplitSrcs)
8473 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8474
8475 // Combine the new truncates into one vector
8476 auto Merge = MIRBuilder.buildMergeLikeInstr(
8477 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8478
8479 // Truncate the new vector to the final result type
8480 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8481 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8482 else
8483 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8484
8485 MI.eraseFromParent();
8486
8487 return Legalized;
8488 }
8489 return UnableToLegalize;
8490}
8491
8494 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8495 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8496 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8497 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8498 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8499 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8500 MI.eraseFromParent();
8501 return Legalized;
8502}
8503
8505 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8506
8507 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8508 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8509
8510 MIRBuilder.setInstrAndDebugLoc(MI);
8511
8512 // If a rotate in the other direction is supported, use it.
8513 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8514 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8515 isPowerOf2_32(EltSizeInBits))
8516 return lowerRotateWithReverseRotate(MI);
8517
8518 // If a funnel shift is supported, use it.
8519 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8520 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8521 bool IsFShLegal = false;
8522 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8523 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8524 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8525 Register R3) {
8526 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8527 MI.eraseFromParent();
8528 return Legalized;
8529 };
8530 // If a funnel shift in the other direction is supported, use it.
8531 if (IsFShLegal) {
8532 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8533 } else if (isPowerOf2_32(EltSizeInBits)) {
8534 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8535 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8536 }
8537 }
8538
8539 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8540 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8541 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8542 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8543 Register ShVal;
8544 Register RevShiftVal;
8545 unsigned OrFlags = MachineInstr::NoFlags;
8546 if (isPowerOf2_32(EltSizeInBits)) {
8547 // If c may be zero modulo w, both shifts may return x so the or isn't
8548 // disjoint.
8549 if (isNonZeroModBitWidth(MRI, Amt, EltSizeInBits))
8550 OrFlags |= MachineInstr::Disjoint;
8551 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8552 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8553 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8554 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8555 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8556 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8557 RevShiftVal =
8558 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8559 } else {
8560 OrFlags |= MachineInstr::Disjoint;
8561 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8562 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8563 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8564 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8565 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8566 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8567 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8568 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8569 RevShiftVal =
8570 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8571 }
8572 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, OrFlags);
8573 MI.eraseFromParent();
8574 return Legalized;
8575}
8576
8577// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8578// operations and G_SITOFP
8581 auto [Dst, Src] = MI.getFirst2Regs();
8582 const LLT S64 = LLT::scalar(64);
8583 const LLT S32 = LLT::scalar(32);
8584 const LLT S1 = LLT::scalar(1);
8585
8586 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8587
8588 // For i64 < INT_MAX we simply reuse SITOFP.
8589 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8590 // saved before division, convert to float by SITOFP, multiply the result
8591 // by 2.
8592 auto One = MIRBuilder.buildConstant(S64, 1);
8593 auto Zero = MIRBuilder.buildConstant(S64, 0);
8594 // Result if Src < INT_MAX
8595 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8596 // Result if Src >= INT_MAX
8597 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8598 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8599 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8600 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8601 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8602 // Check if the original value is larger than INT_MAX by comparing with
8603 // zero to pick one of the two conversions.
8604 auto IsLarge =
8606 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8607
8608 MI.eraseFromParent();
8609 return Legalized;
8610}
8611
8612// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8613// IEEE double representation.
8616 auto [Dst, Src] = MI.getFirst2Regs();
8617 const LLT S64 = LLT::scalar(64);
8618 const LLT S32 = LLT::scalar(32);
8619
8620 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8621
8622 // We create double value from 32 bit parts with 32 exponent difference.
8623 // Note that + and - are float operations that adjust the implicit leading
8624 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8625 //
8626 // X = 2^52 * 1.0...LowBits
8627 // Y = 2^84 * 1.0...HighBits
8628 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8629 // = - 2^52 * 1.0...HighBits
8630 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8631 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8632 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8633 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8634 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8635 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8636
8637 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8638 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8639 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8640 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8641 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8642 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8643 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8644
8645 MI.eraseFromParent();
8646 return Legalized;
8647}
8648
8649/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8650/// convert fpround f64->f16 without double-rounding, so we manually perform the
8651/// lowering here where we know it is valid.
8654 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8655 auto DstFpTy =
8656 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8657 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8658 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8659 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8660 LLT F32Ty = DstFpTy.changeElementSize(32);
8661 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8662 MIRBuilder.buildFPTrunc(Dst, M2);
8663 MI.eraseFromParent();
8665}
8666
8668 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8669
8670 if (SrcTy == LLT::scalar(1)) {
8671 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8672 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8673 MIRBuilder.buildSelect(Dst, Src, True, False);
8674 MI.eraseFromParent();
8675 return Legalized;
8676 }
8677
8678 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8679 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8680
8681 if (SrcTy != LLT::scalar(64))
8682 return UnableToLegalize;
8683
8684 if (DstTy == LLT::scalar(32))
8685 // TODO: SelectionDAG has several alternative expansions to port which may
8686 // be more reasonable depending on the available instructions. We also need
8687 // a more advanced mechanism to choose an optimal version depending on
8688 // target features such as sitofp or CTLZ availability.
8690
8691 if (DstTy == LLT::scalar(64))
8693
8694 return UnableToLegalize;
8695}
8696
8698 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8699
8700 const LLT I64 = LLT::integer(64);
8701 const LLT I32 = LLT::integer(32);
8702 const LLT I1 = LLT::integer(1);
8703
8704 if (SrcTy == I1) {
8705 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8706 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8707 MIRBuilder.buildSelect(Dst, Src, True, False);
8708 MI.eraseFromParent();
8709 return Legalized;
8710 }
8711
8712 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8713 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8714
8715 if (SrcTy != I64)
8716 return UnableToLegalize;
8717
8718 if (DstTy.getScalarSizeInBits() == 32) {
8719 // signed cl2f(long l) {
8720 // long s = l >> 63;
8721 // float r = cul2f((l + s) ^ s);
8722 // return s ? -r : r;
8723 // }
8724 Register L = Src;
8725 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8726 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8727
8728 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8729 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8730 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8731
8732 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8733 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8734 MIRBuilder.buildConstant(I64, 0));
8735 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8736 MI.eraseFromParent();
8737 return Legalized;
8738 }
8739
8740 return UnableToLegalize;
8741}
8742
8744 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8745 const LLT S64 = LLT::scalar(64);
8746 const LLT S32 = LLT::scalar(32);
8747
8748 if (SrcTy != S64 && SrcTy != S32)
8749 return UnableToLegalize;
8750 if (DstTy != S32 && DstTy != S64)
8751 return UnableToLegalize;
8752
8753 // FPTOSI gives same result as FPTOUI for positive signed integers.
8754 // FPTOUI needs to deal with fp values that convert to unsigned integers
8755 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8756
8757 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8758 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8760 APInt::getZero(SrcTy.getSizeInBits()));
8761 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8762
8763 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8764
8765 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8766 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8767 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8768 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8769 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8770 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8771 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8772
8773 const LLT S1 = LLT::scalar(1);
8774
8775 MachineInstrBuilder FCMP =
8776 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8777 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8778
8779 MI.eraseFromParent();
8780 return Legalized;
8781}
8782
8784 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8785 const LLT S64 = LLT::scalar(64);
8786 const LLT S32 = LLT::scalar(32);
8787
8788 // FIXME: Only f32 to i64 conversions are supported.
8789 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8790 return UnableToLegalize;
8791
8792 // Expand f32 -> i64 conversion
8793 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8794 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8795
8796 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8797
8798 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8799 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8800
8801 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8802 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8803
8804 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8805 APInt::getSignMask(SrcEltBits));
8806 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8807 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8808 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8809 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8810
8811 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8812 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8813 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8814
8815 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8816 R = MIRBuilder.buildZExt(DstTy, R);
8817
8818 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8819 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8820 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8821 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8822
8823 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8824 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8825
8826 const LLT S1 = LLT::scalar(1);
8827 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8828 S1, Exponent, ExponentLoBit);
8829
8830 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8831
8832 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8833 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8834
8835 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8836
8837 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8838 S1, Exponent, ZeroSrcTy);
8839
8840 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8841 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8842
8843 MI.eraseFromParent();
8844 return Legalized;
8845}
8846
8849 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8850
8851 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8852 unsigned SatWidth = DstTy.getScalarSizeInBits();
8853
8854 // Determine minimum and maximum integer values and their corresponding
8855 // floating-point values.
8856 APInt MinInt, MaxInt;
8857 if (IsSigned) {
8858 MinInt = APInt::getSignedMinValue(SatWidth);
8859 MaxInt = APInt::getSignedMaxValue(SatWidth);
8860 } else {
8861 MinInt = APInt::getMinValue(SatWidth);
8862 MaxInt = APInt::getMaxValue(SatWidth);
8863 }
8864
8865 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8866 APFloat MinFloat(Semantics);
8867 APFloat MaxFloat(Semantics);
8868
8869 APFloat::opStatus MinStatus =
8870 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8871 APFloat::opStatus MaxStatus =
8872 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8873 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8874 !(MaxStatus & APFloat::opStatus::opInexact);
8875
8876 // If the integer bounds are exactly representable as floats, emit a
8877 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8878 // and selects.
8879 if (AreExactFloatBounds) {
8880 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8881 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8882 auto MaxP =
8883 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8884 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8885 // Clamp by MaxFloat from above. NaN cannot occur.
8886 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8887 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8889 auto Min =
8890 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8891 // Convert clamped value to integer. In the unsigned case we're done,
8892 // because we mapped NaN to MinFloat, which will cast to zero.
8893 if (!IsSigned) {
8894 MIRBuilder.buildFPTOUI(Dst, Min);
8895 MI.eraseFromParent();
8896 return Legalized;
8897 }
8898
8899 // Otherwise, select 0 if Src is NaN.
8900 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8901 auto IsZero =
8902 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8903 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8904 FpToInt);
8905 MI.eraseFromParent();
8906 return Legalized;
8907 }
8908
8909 // Result of direct conversion. The assumption here is that the operation is
8910 // non-trapping and it's fine to apply it to an out-of-range value if we
8911 // select it away later.
8912 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8913 : MIRBuilder.buildFPTOUI(DstTy, Src);
8914
8915 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8916 // MinInt if Src is NaN.
8917 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8918 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8919 auto Max = MIRBuilder.buildSelect(
8920 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8921 // If Src OGT MaxFloat, select MaxInt.
8922 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8923 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8924
8925 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8926 // is already zero.
8927 if (!IsSigned) {
8928 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8929 Max);
8930 MI.eraseFromParent();
8931 return Legalized;
8932 }
8933
8934 // Otherwise, select 0 if Src is NaN.
8935 auto Min = MIRBuilder.buildSelect(
8936 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8937 auto IsZero =
8938 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8939 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8940 MI.eraseFromParent();
8941 return Legalized;
8942}
8943
8944// Floating-point conversions using truncating and extending loads and stores.
8947 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8948 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8949 "Only G_FPEXT and G_FPTRUNC are expected");
8950
8951 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8952 MachinePointerInfo PtrInfo;
8953 unsigned StoreOpc;
8954 unsigned LoadOpc;
8955 LLT StackTy;
8956 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8957 StackTy = SrcTy;
8958 StoreOpc = TargetOpcode::G_STORE;
8959 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8960 } else {
8961 StackTy = DstTy;
8962 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8963 LoadOpc = TargetOpcode::G_LOAD;
8964 }
8965
8966 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8967 auto StackTemp =
8968 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8969
8970 MachineFunction &MF = MIRBuilder.getMF();
8971 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8972 StackTy, StackTyAlign);
8973 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8974
8975 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8976 StackTy, StackTyAlign);
8977 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8978
8979 MI.eraseFromParent();
8980 return Legalized;
8981}
8982
8983// Expand a bf16 -> f32/f64 fpext with a shift and bitcast. This is based on the
8984// SDAG ISD::BF16_TO_FP lowering.
8987 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8988 assert(SrcTy.getScalarType().isBFloat16() &&
8989 "expected a bf16 source for bf16 fpext lowering");
8990
8991 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8992 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8993 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
8994
8995 auto SrcI =
8996 MIRBuilder.buildAnyExt(I32Ty, MIRBuilder.buildBitcast(I16Ty, SrcReg));
8997 auto Shl =
8998 MIRBuilder.buildShl(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8999
9000 if (DstTy.getScalarType().isFloat32())
9001 MIRBuilder.buildBitcast(DstReg, Shl);
9002 else
9003 MIRBuilder.buildFPExt(DstReg, MIRBuilder.buildBitcast(F32Ty, Shl));
9004
9005 MI.eraseFromParent();
9006 return Legalized;
9007}
9008
9010 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9011 if (SrcTy.getScalarType().isBFloat16() &&
9012 (DstTy.getScalarType().isFloat32() || DstTy.getScalarType().isFloat64()))
9013 return lowerFPEXT_BF16(MI);
9014
9015 return lowerFPExtAndTruncMem(MI);
9016}
9017
9018// f64 -> f16 conversion using round-to-nearest-even rounding mode.
9021 const LLT S1 = LLT::scalar(1);
9022 const LLT I32 = LLT::integer(32);
9023
9024 auto [Dst, Src] = MI.getFirst2Regs();
9025 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
9026 MRI.getType(Src).getScalarType() == LLT::float64());
9027
9028 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
9029 return UnableToLegalize;
9030
9031 if (MI.getFlag(MachineInstr::FmAfn)) {
9032 unsigned Flags = MI.getFlags();
9033 auto Src32 = MIRBuilder.buildFPTrunc(LLT::float32(), Src, Flags);
9034 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
9035 MI.eraseFromParent();
9036 return Legalized;
9037 }
9038
9039 const unsigned ExpMask = 0x7ff;
9040 const unsigned ExpBiasf64 = 1023;
9041 const unsigned ExpBiasf16 = 15;
9042
9043 auto Unmerge = MIRBuilder.buildUnmerge(I32, Src);
9044 Register U = Unmerge.getReg(0);
9045 Register UH = Unmerge.getReg(1);
9046
9047 auto E = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 20));
9048 E = MIRBuilder.buildAnd(I32, E, MIRBuilder.buildConstant(I32, ExpMask));
9049
9050 // Subtract the fp64 exponent bias (1023) to get the real exponent and
9051 // add the f16 bias (15) to get the biased exponent for the f16 format.
9052 E = MIRBuilder.buildAdd(
9053 I32, E, MIRBuilder.buildConstant(I32, -ExpBiasf64 + ExpBiasf16));
9054
9055 auto M = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 8));
9056 M = MIRBuilder.buildAnd(I32, M, MIRBuilder.buildConstant(I32, 0xffe));
9057
9058 auto MaskedSig =
9059 MIRBuilder.buildAnd(I32, UH, MIRBuilder.buildConstant(I32, 0x1ff));
9060 MaskedSig = MIRBuilder.buildOr(I32, MaskedSig, U);
9061
9062 auto Zero = MIRBuilder.buildConstant(I32, 0);
9063 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
9064 auto Lo40Set = MIRBuilder.buildZExt(I32, SigCmpNE0);
9065 M = MIRBuilder.buildOr(I32, M, Lo40Set);
9066
9067 // (M != 0 ? 0x0200 : 0) | 0x7c00;
9068 auto Bits0x200 = MIRBuilder.buildConstant(I32, 0x0200);
9069 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
9070 auto SelectCC = MIRBuilder.buildSelect(I32, CmpM_NE0, Bits0x200, Zero);
9071
9072 auto Bits0x7c00 = MIRBuilder.buildConstant(I32, 0x7c00);
9073 auto I = MIRBuilder.buildOr(I32, SelectCC, Bits0x7c00);
9074
9075 // N = M | (E << 12);
9076 auto EShl12 = MIRBuilder.buildShl(I32, E, MIRBuilder.buildConstant(I32, 12));
9077 auto N = MIRBuilder.buildOr(I32, M, EShl12);
9078
9079 // B = clamp(1-E, 0, 13);
9080 auto One = MIRBuilder.buildConstant(I32, 1);
9081 auto OneSubExp = MIRBuilder.buildSub(I32, One, E);
9082 auto B = MIRBuilder.buildSMax(I32, OneSubExp, Zero);
9083 B = MIRBuilder.buildSMin(I32, B, MIRBuilder.buildConstant(I32, 13));
9084
9085 auto SigSetHigh =
9086 MIRBuilder.buildOr(I32, M, MIRBuilder.buildConstant(I32, 0x1000));
9087
9088 auto D = MIRBuilder.buildLShr(I32, SigSetHigh, B);
9089 auto D0 = MIRBuilder.buildShl(I32, D, B);
9090
9091 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
9092 D0, SigSetHigh);
9093 auto D1 = MIRBuilder.buildZExt(I32, D0_NE_SigSetHigh);
9094 D = MIRBuilder.buildOr(I32, D, D1);
9095
9096 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
9097 auto V = MIRBuilder.buildSelect(I32, CmpELtOne, D, N);
9098
9099 auto VLow3 = MIRBuilder.buildAnd(I32, V, MIRBuilder.buildConstant(I32, 7));
9100 V = MIRBuilder.buildLShr(I32, V, MIRBuilder.buildConstant(I32, 2));
9101
9102 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
9103 MIRBuilder.buildConstant(I32, 3));
9104 auto V0 = MIRBuilder.buildZExt(I32, VLow3Eq3);
9105
9106 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
9107 MIRBuilder.buildConstant(I32, 5));
9108 auto V1 = MIRBuilder.buildZExt(I32, VLow3Gt5);
9109
9110 V1 = MIRBuilder.buildOr(I32, V0, V1);
9111 V = MIRBuilder.buildAdd(I32, V, V1);
9112
9113 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, E,
9114 MIRBuilder.buildConstant(I32, 30));
9115 V = MIRBuilder.buildSelect(I32, CmpEGt30,
9116 MIRBuilder.buildConstant(I32, 0x7c00), V);
9117
9118 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, E,
9119 MIRBuilder.buildConstant(I32, 1039));
9120 V = MIRBuilder.buildSelect(I32, CmpEGt1039, I, V);
9121
9122 // Extract the sign bit.
9123 auto Sign = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 16));
9124 Sign = MIRBuilder.buildAnd(I32, Sign, MIRBuilder.buildConstant(I32, 0x8000));
9125
9126 // Insert the sign bit
9127 V = MIRBuilder.buildOr(I32, Sign, V);
9128
9129 MIRBuilder.buildTrunc(Dst, V);
9130 MI.eraseFromParent();
9131 return Legalized;
9132}
9133
9134// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
9137 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9138 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9139 SrcTy.getScalarType() == LLT::float32());
9140
9141 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
9142 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
9143 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
9144
9145 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
9146
9147 // Conversions should set NaN's quiet bit. This also prevents NaNs from
9148 // turning into infinities.
9149 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
9150 MIRBuilder.buildConstant(I32Ty, 0x400000));
9151
9152 // Factor in the contribution of the low 16 bits.
9153 auto Lsb =
9154 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
9155 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
9156 auto RoundingBias =
9157 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
9158 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
9159
9160 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
9161 // 0x80000000.
9162 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9163 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
9164 MIRBuilder.buildFConstant(SrcTy, 0));
9165 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
9166 }
9167
9168 // Now that we have rounded, shift the bits into position.
9169 auto Srl =
9170 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
9171 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
9172 MIRBuilder.buildBitcast(DstReg, Trunc);
9173 MI.eraseFromParent();
9174 return Legalized;
9175}
9176
9177// Round a wide fp value to ResultTy's element size, forcing inexact
9178// results to the odd value so a subsequent narrowing round is correct. This
9179// avoids double-rounding when narrowing e.g. f64 -> f32 -> bf16. See Boldo &
9180// Melquiond, "When double rounding is odd" (2005).
9182 LLT OperandTy = MRI.getType(Op);
9183 if (OperandTy.getScalarType() == ResultTy.getScalarType())
9184 return Op;
9185
9186 LLT ResultIntTy =
9188 LLT ResultCCTy = ResultTy.changeElementType(LLT::integer(1));
9189 LLT OperandCCTy = OperandTy.changeElementType(LLT::integer(1));
9190
9191 auto Narrow = MIRBuilder.buildFPTrunc(ResultTy, Op);
9192 auto NarrowAsWide = MIRBuilder.buildFPExt(OperandTy, Narrow);
9193
9194 auto NarrowBits = MIRBuilder.buildBitcast(ResultIntTy, Narrow);
9195 auto One = MIRBuilder.buildConstant(ResultIntTy, 1);
9196 auto NegativeOne = MIRBuilder.buildConstant(ResultIntTy, -1);
9197 auto Zero = MIRBuilder.buildConstant(ResultIntTy, 0);
9198 auto And = MIRBuilder.buildAnd(ResultIntTy, NarrowBits, One);
9199 // The result is already odd so we don't need to do anything.
9200 auto AlreadyOdd =
9201 MIRBuilder.buildICmp(CmpInst::ICMP_NE, ResultCCTy, And, Zero);
9202
9203 // We keep results which are exact, odd or NaN.
9204 auto KeepNarrow =
9205 MIRBuilder.buildFCmp(CmpInst::FCMP_UEQ, OperandCCTy, Op, NarrowAsWide);
9206 KeepNarrow = MIRBuilder.buildOr(OperandCCTy, KeepNarrow, AlreadyOdd);
9207 // We morally performed a round-down if AbsNarrow is smaller than AbsWide.
9208 auto AbsWide = MIRBuilder.buildFAbs(OperandTy, Op);
9209 auto AbsNarrowAsWide = MIRBuilder.buildFAbs(OperandTy, NarrowAsWide);
9210 auto NarrowIsRd = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, OperandCCTy,
9211 AbsWide, AbsNarrowAsWide);
9212 // If narrow is the rounded-down value, pick the rounded-up value as it will
9213 // be odd; otherwise adjust down.
9214 auto Adjust =
9215 MIRBuilder.buildSelect(ResultIntTy, NarrowIsRd, One, NegativeOne);
9216 auto Adjusted = MIRBuilder.buildAdd(ResultIntTy, NarrowBits, Adjust);
9217 auto Res =
9218 MIRBuilder.buildSelect(ResultIntTy, KeepNarrow, NarrowBits, Adjusted);
9219 return MIRBuilder.buildBitcast(ResultTy, Res).getReg(0);
9220}
9221
9222// f64 -> bf16 conversion, correcting for double rounding.
9225 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9226 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9227 SrcTy.getScalarType() == LLT::float64());
9228
9229 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
9230 Register OddF32 = lowerRoundInexactToOdd(F32Ty, SrcReg);
9231 MIRBuilder.buildFPTrunc(DstReg, OddF32, MI.getFlags());
9232 MI.eraseFromParent();
9233 return Legalized;
9234}
9235
9238 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9239 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
9241
9242 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
9244
9245 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat64())
9247
9248 return lowerFPExtAndTruncMem(MI);
9249}
9250
9252 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9253 LLT Ty = MRI.getType(Dst);
9254
9255 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
9256 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
9257 MI.eraseFromParent();
9258 return Legalized;
9259}
9260
9262 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
9263 LLT Ty = MRI.getType(Src);
9264 auto Flags = MI.getFlags();
9265 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9266
9267 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
9268 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
9269
9270 Register FracToUse;
9271 if (MI.getFlag(MachineInstr::FmNoInfs)) {
9272 FracToUse = FracPart.getReg(0);
9273 } else {
9274 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
9275 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
9276 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
9277 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
9278 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9279 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
9280 FracToUse = Select.getReg(0);
9281 }
9282
9283 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
9284 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
9285
9286 MI.eraseFromParent();
9287 return Legalized;
9288}
9289
9291 switch (Opc) {
9292 case TargetOpcode::G_SMIN:
9293 return CmpInst::ICMP_SLT;
9294 case TargetOpcode::G_SMAX:
9295 return CmpInst::ICMP_SGT;
9296 case TargetOpcode::G_UMIN:
9297 return CmpInst::ICMP_ULT;
9298 case TargetOpcode::G_UMAX:
9299 return CmpInst::ICMP_UGT;
9300 default:
9301 llvm_unreachable("not in integer min/max");
9302 }
9303}
9304
9306 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9307
9308 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9309 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9310
9311 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9312 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9313
9314 MI.eraseFromParent();
9315 return Legalized;
9316}
9317
9320 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9321
9322 Register Dst = Cmp->getReg(0);
9323 LLT DstTy = MRI.getType(Dst);
9324 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9325 LLT CmpTy = DstTy.changeElementSize(1);
9326
9327 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9330 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9333
9334 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9335 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9336 Cmp->getRHSReg());
9337 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9338 Cmp->getRHSReg());
9339
9340 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9341 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9342 if (TLI.preferSelectsOverBooleanArithmetic(
9343 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9345 auto One = MIRBuilder.buildConstant(DstTy, 1);
9346 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9347
9348 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9349 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9350 } else {
9352 std::swap(IsGT, IsLT);
9353 // Extend boolean results to DstTy, which is at least i2, before subtracting
9354 // them.
9355 unsigned BoolExtOp =
9356 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9357 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9358 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9359 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9360 }
9361
9362 MI.eraseFromParent();
9363 return Legalized;
9364}
9365
9368 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9369 const int Src0Size = Src0Ty.getScalarSizeInBits();
9370 const int Src1Size = Src1Ty.getScalarSizeInBits();
9371
9372 LLT DstIntTy =
9373 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9374 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9375 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9376
9377 Register Src0Int = Src0;
9378 Register Src1Int = Src1;
9379
9380 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9381 Src0Ty.getScalarType().isInteger()))
9382 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9383
9384 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9385 Src1Ty.getScalarType().isInteger()))
9386 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9387
9388 auto SignBitMask =
9389 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9390
9391 auto NotSignBitMask = MIRBuilder.buildConstant(
9392 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9393
9394 Register And0 =
9395 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9396 Register And1;
9397 if (Src0Ty == Src1Ty) {
9398 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9399 } else if (Src0Size > Src1Size) {
9400 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9401 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9402 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9403 And1 = MIRBuilder.buildAnd(Src0IntTy, Shift, SignBitMask).getReg(0);
9404 } else {
9405 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9406 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9407 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9408 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9409 }
9410
9411 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9412 // constants are a nan and -0.0, but the final result should preserve
9413 // everything.
9414 unsigned Flags = MI.getFlags();
9415
9416 // We masked the sign bit and the not-sign bit, so these are disjoint.
9417 Flags |= MachineInstr::Disjoint;
9418
9419 if (DstTy == DstIntTy)
9420 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9421 else {
9422 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9423 MIRBuilder.buildBitcast(Dst, NewDst);
9424 }
9425
9426 MI.eraseFromParent();
9427 return Legalized;
9428}
9429
9432 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9433 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9434 // depend on fminnum/fmaxnum.
9435
9436 unsigned NewOp;
9437 switch (MI.getOpcode()) {
9438 case TargetOpcode::G_FMINNUM:
9439 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9440 break;
9441 case TargetOpcode::G_FMINIMUMNUM:
9442 NewOp = TargetOpcode::G_FMINNUM;
9443 break;
9444 case TargetOpcode::G_FMAXNUM:
9445 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9446 break;
9447 case TargetOpcode::G_FMAXIMUMNUM:
9448 NewOp = TargetOpcode::G_FMAXNUM;
9449 break;
9450 default:
9451 llvm_unreachable("unexpected min/max opcode");
9452 }
9453
9454 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9455 LLT Ty = MRI.getType(Dst);
9456
9457 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9458 // Insert canonicalizes if it's possible we need to quiet to get correct
9459 // sNaN behavior.
9460
9461 // Note this must be done here, and not as an optimization combine in the
9462 // absence of a dedicate quiet-snan instruction as we're using an
9463 // omni-purpose G_FCANONICALIZE.
9464 if (!VT->isKnownNeverSNaN(Src0))
9465 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9466
9467 if (!VT->isKnownNeverSNaN(Src1))
9468 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9469 }
9470
9471 // If there are no nans, it's safe to simply replace this with the non-IEEE
9472 // version.
9473 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9474 MI.eraseFromParent();
9475 return Legalized;
9476}
9477
9480 unsigned Opc = MI.getOpcode();
9481 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9482 LLT Ty = MRI.getType(Dst);
9483 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9484
9485 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9486 unsigned OpcIeee =
9487 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9488 unsigned OpcNonIeee =
9489 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9490 bool MinMaxMustRespectOrderedZero = false;
9491 Register Res;
9492
9493 // IEEE variants don't need canonicalization
9494 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9495 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9496 MinMaxMustRespectOrderedZero = true;
9497 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9498 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9499 } else {
9500 auto Compare = MIRBuilder.buildFCmp(
9501 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9502 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9503 }
9504
9505 // Propagate any NaN of both operands
9506 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9507 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9508 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9509
9510 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9511 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9512 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9513 if (Ty.isVector())
9514 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9515
9516 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9517 }
9518
9519 // fminimum/fmaximum requires -0.0 less than +0.0
9520 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9521 GISelValueTracking VT(MIRBuilder.getMF());
9522 // FIXME: Also demand for subnormal classes depending on the denormal mode.
9523 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9524 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9525
9526 // FIXME: Must use isKnownNeverLogicalZero(Mode)
9527 if (!Src0Info.isKnownNever(fcZero) && !Src1Info.isKnownNever(fcZero)) {
9528 const unsigned Flags = MI.getFlags();
9529 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9530 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9531
9532 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9533
9534 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9535 auto LHSSelect =
9536 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9537
9538 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9539 auto RHSSelect =
9540 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9541
9542 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9543 }
9544 }
9545
9546 MIRBuilder.buildCopy(Dst, Res);
9547 MI.eraseFromParent();
9548 return Legalized;
9549}
9550
9552 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9553 Register DstReg = MI.getOperand(0).getReg();
9554 LLT Ty = MRI.getType(DstReg);
9555 unsigned Flags = MI.getFlags();
9556
9557 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9558 Flags);
9559 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9560 MI.eraseFromParent();
9561 return Legalized;
9562}
9563
9566 auto [DstReg, X] = MI.getFirst2Regs();
9567 const unsigned Flags = MI.getFlags();
9568 const LLT Ty = MRI.getType(DstReg);
9569 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9570
9571 // round(x) =>
9572 // t = trunc(x);
9573 // d = fabs(x - t);
9574 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9575 // return t + o;
9576
9577 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9578
9579 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9580 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9581
9582 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9583 auto Cmp =
9584 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9585
9586 // Could emit G_UITOFP instead
9587 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9588 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9589 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9590 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9591
9592 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9593
9594 MI.eraseFromParent();
9595 return Legalized;
9596}
9597
9599 auto [DstReg, SrcReg] = MI.getFirst2Regs();
9600 unsigned Flags = MI.getFlags();
9601 LLT Ty = MRI.getType(DstReg);
9602 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9603
9604 // result = trunc(src);
9605 // if (src < 0.0 && src != result)
9606 // result += -1.0.
9607
9608 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
9609 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9610
9611 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
9612 SrcReg, Zero, Flags);
9613 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
9614 SrcReg, Trunc, Flags);
9615 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
9616 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
9617
9618 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
9619 MI.eraseFromParent();
9620 return Legalized;
9621}
9622
9625 const unsigned NumOps = MI.getNumOperands();
9626 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
9627 unsigned PartSize = Src0Ty.getSizeInBits();
9628
9629 LLT WideTy = LLT::integer(DstTy.getSizeInBits());
9630 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
9631
9632 for (unsigned I = 2; I != NumOps; ++I) {
9633 const unsigned Offset = (I - 1) * PartSize;
9634
9635 Register SrcReg = MI.getOperand(I).getReg();
9636 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
9637
9638 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
9639 MRI.createGenericVirtualRegister(WideTy);
9640
9641 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
9642 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
9643 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
9644 ResultReg = NextResult;
9645 }
9646
9647 if (DstTy.isPointer()) {
9648 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
9649 DstTy.getAddressSpace())) {
9650 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
9651 return UnableToLegalize;
9652 }
9653
9654 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9655 } else if (WideTy != DstTy) {
9656 MIRBuilder.buildBitcast(DstReg, ResultReg);
9657 }
9658
9659 MI.eraseFromParent();
9660 return Legalized;
9661}
9662
9665 const unsigned NumDst = MI.getNumOperands() - 1;
9666 Register SrcReg = MI.getOperand(NumDst).getReg();
9667 Register Dst0Reg = MI.getOperand(0).getReg();
9668 LLT DstTy = MRI.getType(Dst0Reg);
9669 if (DstTy.isPointer())
9670 return UnableToLegalize; // TODO
9671
9672 SrcReg = coerceToInteger(SrcReg);
9673 if (!SrcReg)
9674 return UnableToLegalize;
9675
9676 // Expand scalarizing unmerge as bitcast to integer and shift.
9677 LLT IntTy = MRI.getType(SrcReg);
9678
9679 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
9680
9681 const unsigned DstSize = DstTy.getSizeInBits();
9682 unsigned Offset = DstSize;
9683 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
9684 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
9685 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
9686 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
9687 }
9688
9689 MI.eraseFromParent();
9690 return Legalized;
9691}
9692
9693/// Lower a vector extract or insert by writing the vector to a stack temporary
9694/// and reloading the element or vector.
9695///
9696/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
9697/// =>
9698/// %stack_temp = G_FRAME_INDEX
9699/// G_STORE %vec, %stack_temp
9700/// %idx = clamp(%idx, %vec.getNumElements())
9701/// %element_ptr = G_PTR_ADD %stack_temp, %idx
9702/// %dst = G_LOAD %element_ptr
9705 Register DstReg = MI.getOperand(0).getReg();
9706 Register SrcVec = MI.getOperand(1).getReg();
9707 Register InsertVal;
9708 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
9709 InsertVal = MI.getOperand(2).getReg();
9710
9711 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
9712
9713 LLT VecTy = MRI.getType(SrcVec);
9714 LLT EltTy = VecTy.getElementType();
9715 unsigned NumElts = VecTy.getNumElements();
9716
9717 int64_t IdxVal;
9718 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
9720 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
9721
9722 if (InsertVal) {
9723 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
9724 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
9725 } else {
9726 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
9727 }
9728
9729 MI.eraseFromParent();
9730 return Legalized;
9731 }
9732
9733 if (!EltTy.isByteSized()) { // Not implemented.
9734 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
9735 return UnableToLegalize;
9736 }
9737
9738 unsigned EltBytes = EltTy.getSizeInBytes();
9739 Align VecAlign = getStackTemporaryAlignment(VecTy);
9740 Align EltAlign;
9741
9742 MachinePointerInfo PtrInfo;
9743 auto StackTemp = createStackTemporary(
9744 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
9745 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
9746
9747 // Get the pointer to the element, and be sure not to hit undefined behavior
9748 // if the index is out of bounds.
9749 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
9750
9751 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
9752 int64_t Offset = IdxVal * EltBytes;
9753 PtrInfo = PtrInfo.getWithOffset(Offset);
9754 EltAlign = commonAlignment(VecAlign, Offset);
9755 } else {
9756 // We lose information with a variable offset.
9757 EltAlign = getStackTemporaryAlignment(EltTy);
9758 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
9759 }
9760
9761 if (InsertVal) {
9762 // Write the inserted element
9763 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
9764
9765 // Reload the whole vector.
9766 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
9767 } else {
9768 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
9769 }
9770
9771 MI.eraseFromParent();
9772 return Legalized;
9773}
9774
9777 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
9778 MI.getFirst3RegLLTs();
9779 LLT IdxTy = LLT::scalar(32);
9780
9781 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
9784 LLT EltTy = DstTy.getScalarType();
9785
9786 DenseMap<unsigned, Register> CachedExtract;
9787
9788 for (int Idx : Mask) {
9789 if (Idx < 0) {
9790 if (!Undef.isValid())
9791 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
9792 BuildVec.push_back(Undef);
9793 continue;
9794 }
9795
9796 assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");
9797
9798 int NumElts = Src0Ty.getNumElements();
9799 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
9800 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
9801 auto [It, Inserted] = CachedExtract.try_emplace(Idx);
9802 if (Inserted) {
9803 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
9804 It->second =
9805 MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);
9806 }
9807 BuildVec.push_back(It->second);
9808 }
9809
9810 assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");
9811 MIRBuilder.buildBuildVector(DstReg, BuildVec);
9812 MI.eraseFromParent();
9813 return Legalized;
9814}
9815
9818 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
9819 MI.getFirst4RegLLTs();
9820
9821 if (VecTy.isScalableVector())
9822 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
9823
9824 Align VecAlign = getStackTemporaryAlignment(VecTy);
9825 MachinePointerInfo PtrInfo;
9826 Register StackPtr =
9827 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
9828 PtrInfo)
9829 .getReg(0);
9830 MachinePointerInfo ValPtrInfo =
9832
9833 LLT IdxTy = LLT::integer(32);
9834 LLT ValTy = VecTy.getElementType();
9835 Align ValAlign = getStackTemporaryAlignment(ValTy);
9836
9837 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
9838
9839 bool HasPassthru = !mi_match(Passthru, MRI, m_GImplicitDef());
9840
9841 if (HasPassthru)
9842 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
9843
9844 Register LastWriteVal;
9845 std::optional<APInt> PassthruSplatVal =
9846 isConstantOrConstantSplatVector(Passthru, MRI);
9847
9848 if (PassthruSplatVal.has_value()) {
9849 LastWriteVal =
9850 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
9851 } else if (HasPassthru) {
9852 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
9853 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
9854 {LLT::integer(32)}, {Popcount});
9855
9856 Register LastElmtPtr =
9857 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
9858 LastWriteVal =
9859 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
9860 .getReg(0);
9861 }
9862
9863 unsigned NumElmts = VecTy.getNumElements();
9864 for (unsigned I = 0; I < NumElmts; ++I) {
9865 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
9866 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
9867 Register ElmtPtr =
9868 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9869 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
9870
9871 LLT MaskITy = MaskTy.getElementType();
9872 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
9873 if (MaskITy.getSizeInBits() > 1)
9874 MaskI = MIRBuilder.buildTrunc(LLT::integer(1), MaskI);
9875
9876 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
9877 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
9878
9879 if (HasPassthru && I == NumElmts - 1) {
9880 auto EndOfVector =
9881 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
9882 auto AllLanesSelected = MIRBuilder.buildICmp(
9883 CmpInst::ICMP_UGT, LLT::integer(1), OutPos, EndOfVector);
9884 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
9885 {OutPos, EndOfVector});
9886 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9887
9888 LastWriteVal =
9889 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
9890 .getReg(0);
9891 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
9892 }
9893 }
9894
9895 // TODO: Use StackPtr's FrameIndex alignment.
9896 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
9897
9898 MI.eraseFromParent();
9899 return Legalized;
9900}
9901
9903 Register AllocSize,
9904 Align Alignment,
9905 LLT PtrTy) {
9907
9908 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
9909 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
9910
9911 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
9912 // have to generate an extra instruction to negate the alloc and then use
9913 // G_PTR_ADD to add the negative offset.
9914 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
9915 if (Alignment > Align(1)) {
9916 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
9917 AlignMask.negate();
9918 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
9919 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
9920 }
9921
9922 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
9923}
9924
9927 const auto &MF = *MI.getMF();
9928 const auto &TFI = *MF.getSubtarget().getFrameLowering();
9929 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
9930 return UnableToLegalize;
9931
9932 Register Dst = MI.getOperand(0).getReg();
9933 Register AllocSize = MI.getOperand(1).getReg();
9934 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
9935
9936 LLT PtrTy = MRI.getType(Dst);
9937 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
9938 Register SPTmp =
9939 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
9940
9941 MIRBuilder.buildCopy(SPReg, SPTmp);
9942 MIRBuilder.buildCopy(Dst, SPTmp);
9943
9944 MI.eraseFromParent();
9945 return Legalized;
9946}
9947
9950 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9951 if (!StackPtr)
9952 return UnableToLegalize;
9953
9954 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
9955 MI.eraseFromParent();
9956 return Legalized;
9957}
9958
9961 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9962 if (!StackPtr)
9963 return UnableToLegalize;
9964
9965 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
9966 MI.eraseFromParent();
9967 return Legalized;
9968}
9969
9972 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9973 unsigned Offset = MI.getOperand(2).getImm();
9974
9975 // Extract sub-vector or one element
9976 if (SrcTy.isVector()) {
9977 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
9978 unsigned DstSize = DstTy.getSizeInBits();
9979
9980 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
9981 (Offset + DstSize <= SrcTy.getSizeInBits())) {
9982 // Unmerge and allow access to each Src element for the artifact combiner.
9983 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
9984
9985 // Take element(s) we need to extract and copy it (merge them).
9986 SmallVector<Register, 8> SubVectorElts;
9987 for (unsigned Idx = Offset / SrcEltSize;
9988 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
9989 SubVectorElts.push_back(Unmerge.getReg(Idx));
9990 }
9991 if (SubVectorElts.size() == 1)
9992 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
9993 else
9994 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
9995
9996 MI.eraseFromParent();
9997 return Legalized;
9998 }
9999 }
10000
10001 const DataLayout &DL = MIRBuilder.getDataLayout();
10002 if ((SrcTy.isPointer() &&
10003 DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) ||
10004 (DstTy.isPointer() &&
10005 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace()))) {
10006 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
10007 return UnableToLegalize;
10008 }
10009
10010 if ((DstTy.isScalar() || DstTy.isPointer()) &&
10011 (SrcTy.isScalar() || SrcTy.isPointer() ||
10012 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
10013 LLT SrcIntTy = SrcTy;
10014 if (!SrcTy.isScalar()) {
10015 SrcIntTy = LLT::integer(SrcTy.getSizeInBits());
10016 SrcReg = MIRBuilder.buildCast(SrcIntTy, SrcReg).getReg(0);
10017 }
10018
10019 Register ResultReg = DstReg;
10020 if (DstTy.isPointer())
10021 ResultReg =
10022 MRI.createGenericVirtualRegister(LLT::integer(DstTy.getSizeInBits()));
10023
10024 if (Offset == 0)
10025 MIRBuilder.buildTrunc(ResultReg, SrcReg);
10026 else {
10027 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
10028 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
10029 MIRBuilder.buildTrunc(ResultReg, Shr);
10030 }
10031
10032 if (DstTy.isPointer())
10033 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
10034
10035 MI.eraseFromParent();
10036 return Legalized;
10037 }
10038
10039 return UnableToLegalize;
10040}
10041
10043 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
10044 uint64_t Offset = MI.getOperand(3).getImm();
10045
10046 LLT DstTy = MRI.getType(Src);
10047 LLT InsertTy = MRI.getType(InsertSrc);
10048
10049 const DataLayout &DL = MIRBuilder.getDataLayout();
10050 bool IsNonIntegralInsert =
10051 InsertTy.isPointerOrPointerVector() &&
10052 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace());
10053 bool IsNonIntegralDst = DstTy.isPointerOrPointerVector() &&
10054 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace());
10055
10056 // Insert sub-vector or one element
10057 if (DstTy.isVector()) {
10058 LLT EltTy = DstTy.getElementType();
10059
10060 if ((IsNonIntegralInsert || IsNonIntegralDst) && InsertTy != EltTy) {
10061 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
10062 return UnableToLegalize;
10063 }
10064
10065 unsigned EltSize = EltTy.getSizeInBits();
10066 unsigned InsertSize = InsertTy.getSizeInBits();
10067
10068 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
10069 (Offset + InsertSize <= DstTy.getSizeInBits())) {
10070 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
10072 unsigned Idx = 0;
10073 // Elements from Src before insert start Offset
10074 for (; Idx < Offset / EltSize; ++Idx) {
10075 DstElts.push_back(UnmergeSrc.getReg(Idx));
10076 }
10077
10078 // Replace elements in Src with elements from InsertSrc
10079 if (InsertTy.getSizeInBits() > EltSize) {
10080 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
10081 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
10082 ++Idx, ++i) {
10083 DstElts.push_back(UnmergeInsertSrc.getReg(i));
10084 }
10085 } else {
10086 if (InsertTy.isPointer() && !EltTy.isPointer())
10087 InsertSrc = MIRBuilder.buildPtrToInt(EltTy, InsertSrc).getReg(0);
10088 else if (!InsertTy.isPointer() && EltTy.isPointer())
10089 InsertSrc = MIRBuilder.buildIntToPtr(EltTy, InsertSrc).getReg(0);
10090 DstElts.push_back(InsertSrc);
10091 ++Idx;
10092 }
10093
10094 // Remaining elements from Src after insert
10095 for (; Idx < DstTy.getNumElements(); ++Idx) {
10096 DstElts.push_back(UnmergeSrc.getReg(Idx));
10097 }
10098
10099 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
10100 MI.eraseFromParent();
10101 return Legalized;
10102 }
10103 }
10104
10105 if (InsertTy.isVector() ||
10106 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
10107 return UnableToLegalize;
10108
10109 if (IsNonIntegralDst || IsNonIntegralInsert) {
10110 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
10111 return UnableToLegalize;
10112 }
10113
10114 LLT IntDstTy = DstTy;
10115
10116 if (!DstTy.isScalar()) {
10117 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
10118 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
10119 }
10120
10121 if (!InsertTy.isScalar()) {
10122 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
10123 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
10124 }
10125
10126 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
10127 if (Offset != 0) {
10128 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
10129 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
10130 }
10131
10133 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
10134
10135 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
10136 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
10137 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
10138
10139 MIRBuilder.buildCast(Dst, Or);
10140 MI.eraseFromParent();
10141 return Legalized;
10142}
10143
10146 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
10147 MI.getFirst4RegLLTs();
10148 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
10149
10150 LLT Ty = Dst0Ty;
10151 LLT BoolTy = Dst1Ty;
10152
10153 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
10154
10155 if (IsAdd)
10156 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
10157 else
10158 MIRBuilder.buildSub(NewDst0, LHS, RHS);
10159
10160 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
10161
10162 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10163
10164 if (IsAdd) {
10165 // For an addition, the result should be less than one of the operands (LHS)
10166 // if and only if the other operand (RHS) is negative, otherwise there will
10167 // be overflow.
10168 auto ResultLowerThanLHS =
10169 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
10170 auto RHSNegative =
10171 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
10172 MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
10173 } else {
10174 // For subtraction, overflow occurs when the signed comparison of operands
10175 // doesn't match the sign of the result.
10176 auto LHSLessThanRHS =
10177 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
10178 auto ResultNegative =
10179 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
10180 MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
10181 }
10182
10183 MIRBuilder.buildCopy(Dst0, NewDst0);
10184 MI.eraseFromParent();
10185
10186 return Legalized;
10187}
10188
10190 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10191 const LLT Ty = MRI.getType(Res);
10192
10193 // sum = LHS + RHS + zext(CarryIn)
10194 auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);
10195 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10196 auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);
10197 MIRBuilder.buildCopy(Res, Sum);
10198
10199 // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 0
10200 auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);
10201 auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);
10202 auto T = MIRBuilder.buildAnd(Ty, AX, BX);
10203
10204 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10205 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10206
10207 MI.eraseFromParent();
10208 return Legalized;
10209}
10210
10212 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10213 const LLT Ty = MRI.getType(Res);
10214
10215 // Diff = LHS - (RHS + zext(CarryIn))
10216 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10217 auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
10218 auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);
10219 MIRBuilder.buildCopy(Res, Diff);
10220
10221 // ov = msb((LHS ^ RHS) & (LHS ^ Diff))
10222 auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);
10223 auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);
10224 auto T = MIRBuilder.buildAnd(Ty, X1, X2);
10225 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10226 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10227
10228 MI.eraseFromParent();
10229 return Legalized;
10230}
10231
10234 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10235 LLT Ty = MRI.getType(Res);
10236 bool IsSigned;
10237 bool IsAdd;
10238 unsigned BaseOp;
10239 switch (MI.getOpcode()) {
10240 default:
10241 llvm_unreachable("unexpected addsat/subsat opcode");
10242 case TargetOpcode::G_UADDSAT:
10243 IsSigned = false;
10244 IsAdd = true;
10245 BaseOp = TargetOpcode::G_ADD;
10246 break;
10247 case TargetOpcode::G_SADDSAT:
10248 IsSigned = true;
10249 IsAdd = true;
10250 BaseOp = TargetOpcode::G_ADD;
10251 break;
10252 case TargetOpcode::G_USUBSAT:
10253 IsSigned = false;
10254 IsAdd = false;
10255 BaseOp = TargetOpcode::G_SUB;
10256 break;
10257 case TargetOpcode::G_SSUBSAT:
10258 IsSigned = true;
10259 IsAdd = false;
10260 BaseOp = TargetOpcode::G_SUB;
10261 break;
10262 }
10263
10264 if (IsSigned) {
10265 // sadd.sat(a, b) ->
10266 // hi = 0x7fffffff - smax(a, 0)
10267 // lo = 0x80000000 - smin(a, 0)
10268 // a + smin(smax(lo, b), hi)
10269 // ssub.sat(a, b) ->
10270 // lo = smax(a, -1) - 0x7fffffff
10271 // hi = smin(a, -1) - 0x80000000
10272 // a - smin(smax(lo, b), hi)
10273 // TODO: AMDGPU can use a "median of 3" instruction here:
10274 // a +/- med3(lo, b, hi)
10275 uint64_t NumBits = Ty.getScalarSizeInBits();
10276 auto MaxVal =
10277 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
10278 auto MinVal =
10279 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10281 if (IsAdd) {
10282 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10283 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
10284 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
10285 } else {
10286 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
10287 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
10288 MaxVal);
10289 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
10290 MinVal);
10291 }
10292 auto RHSClamped =
10293 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
10294 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
10295 } else {
10296 // uadd.sat(a, b) -> a + umin(~a, b)
10297 // usub.sat(a, b) -> a - umin(a, b)
10298 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
10299 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
10300 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
10301 }
10302
10303 MI.eraseFromParent();
10304 return Legalized;
10305}
10306
10309 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10310 LLT Ty = MRI.getType(Res);
10311 LLT BoolTy = Ty.changeElementSize(1);
10312 bool IsSigned;
10313 bool IsAdd;
10314 unsigned OverflowOp;
10315 switch (MI.getOpcode()) {
10316 default:
10317 llvm_unreachable("unexpected addsat/subsat opcode");
10318 case TargetOpcode::G_UADDSAT:
10319 IsSigned = false;
10320 IsAdd = true;
10321 OverflowOp = TargetOpcode::G_UADDO;
10322 break;
10323 case TargetOpcode::G_SADDSAT:
10324 IsSigned = true;
10325 IsAdd = true;
10326 OverflowOp = TargetOpcode::G_SADDO;
10327 break;
10328 case TargetOpcode::G_USUBSAT:
10329 IsSigned = false;
10330 IsAdd = false;
10331 OverflowOp = TargetOpcode::G_USUBO;
10332 break;
10333 case TargetOpcode::G_SSUBSAT:
10334 IsSigned = true;
10335 IsAdd = false;
10336 OverflowOp = TargetOpcode::G_SSUBO;
10337 break;
10338 }
10339
10340 auto OverflowRes =
10341 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
10342 Register Tmp = OverflowRes.getReg(0);
10343 Register Ov = OverflowRes.getReg(1);
10344 MachineInstrBuilder Clamp;
10345 if (IsSigned) {
10346 // sadd.sat(a, b) ->
10347 // {tmp, ov} = saddo(a, b)
10348 // ov ? (tmp >>s 31) + 0x80000000 : r
10349 // ssub.sat(a, b) ->
10350 // {tmp, ov} = ssubo(a, b)
10351 // ov ? (tmp >>s 31) + 0x80000000 : r
10352 uint64_t NumBits = Ty.getScalarSizeInBits();
10353 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
10354 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
10355 auto MinVal =
10356 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10357 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
10358 } else {
10359 // uadd.sat(a, b) ->
10360 // {tmp, ov} = uaddo(a, b)
10361 // ov ? 0xffffffff : tmp
10362 // usub.sat(a, b) ->
10363 // {tmp, ov} = usubo(a, b)
10364 // ov ? 0 : tmp
10365 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
10366 }
10367 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
10368
10369 MI.eraseFromParent();
10370 return Legalized;
10371}
10372
10375 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
10376 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
10377 "Expected shlsat opcode!");
10378 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
10379 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10380 LLT Ty = MRI.getType(Res);
10381 LLT BoolTy = Ty.changeElementSize(1);
10382
10383 unsigned BW = Ty.getScalarSizeInBits();
10384 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
10385 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
10386 : MIRBuilder.buildLShr(Ty, Result, RHS);
10387
10388 MachineInstrBuilder SatVal;
10389 if (IsSigned) {
10390 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
10391 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
10392 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
10393 MIRBuilder.buildConstant(Ty, 0));
10394 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
10395 } else {
10396 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
10397 }
10398 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
10399 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
10400
10401 MI.eraseFromParent();
10402 return Legalized;
10403}
10404
10407 unsigned Opc = MI.getOpcode();
10408 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
10409 unsigned DstSize = DstTy.getScalarSizeInBits();
10410 unsigned SrcSize = SrcTy.getScalarSizeInBits();
10411
10412 if (Opc == TargetOpcode::G_TRUNC_SSAT_S) {
10413 auto Max = MIRBuilder.buildConstant(
10414 SrcTy, APInt::getSignedMaxValue(DstSize).sext(SrcSize));
10415 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10416 auto Min = MIRBuilder.buildConstant(
10417 SrcTy, APInt::getSignedMinValue(DstSize).sext(SrcSize));
10418 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10419 } else if (Opc == TargetOpcode::G_TRUNC_USAT_U) {
10420 auto Max = MIRBuilder.buildConstant(
10421 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10422 Src = MIRBuilder.buildUMin(SrcTy, Src, Max).getReg(0);
10423 } else if (Opc == TargetOpcode::G_TRUNC_SSAT_U) {
10424 auto Max = MIRBuilder.buildConstant(
10425 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10426 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10427 auto Min = MIRBuilder.buildConstant(SrcTy, APInt::getZero(SrcSize));
10428 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10429 } else {
10430 llvm_unreachable("Expected truncsat opcode!");
10431 }
10432
10433 MIRBuilder.buildTrunc(Dst, Src);
10434 MI.eraseFromParent();
10435 return Legalized;
10436}
10437
10439 auto [Dst, Src] = MI.getFirst2Regs();
10440 const LLT Ty = MRI.getType(Src);
10441 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
10442 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
10443
10444 // Swap most and least significant byte, set remaining bytes in Res to zero.
10445 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
10446 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
10447 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10448 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
10449
10450 // Set i-th high/low byte in Res to i-th low/high byte from Src.
10451 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
10452 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
10453 APInt APMask = APInt::getBitsSet(SizeInBytes * 8, i * 8, i * 8 + 8);
10454 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
10455 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
10456 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
10457 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
10458 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
10459 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
10460 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
10461 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10462 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
10463 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
10464 }
10465 Res.getInstr()->getOperand(0).setReg(Dst);
10466
10467 MI.eraseFromParent();
10468 return Legalized;
10469}
10470
10471//{ (Src & Mask) >> N } | { (Src << N) & Mask }
10473 MachineInstrBuilder Src, const APInt &Mask) {
10474 const LLT Ty = Dst.getLLTTy(*B.getMRI());
10475 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
10476 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
10477 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
10478 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
10479 return B.buildOr(Dst, LHS, RHS);
10480}
10481
10484 auto [Dst, Src] = MI.getFirst2Regs();
10485 const LLT SrcTy = MRI.getType(Src);
10486 unsigned Size = SrcTy.getScalarSizeInBits();
10487 unsigned VSize = SrcTy.getSizeInBits();
10488
10489 if (Size >= 8) {
10490 if (SrcTy.isVector() && (VSize % 8 == 0) &&
10491 (LI.isLegal({TargetOpcode::G_BITREVERSE,
10492 {LLT::fixed_vector(VSize / 8, LLT::integer(8)),
10493 LLT::fixed_vector(VSize / 8, LLT::integer(8))}}))) {
10494 // If bitreverse is legal for i8 vector of the same size, then cast
10495 // to i8 vector type.
10496 // e.g. v4s32 -> v16s8
10497 LLT VTy = LLT::fixed_vector(VSize / 8, LLT::integer(8));
10498 auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);
10499 auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);
10500 auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);
10501 MIRBuilder.buildBitcast(Dst, RBIT);
10502 } else {
10503 MachineInstrBuilder BSWAP =
10504 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});
10505
10506 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
10507 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
10508 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
10509 MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,
10510 APInt::getSplat(Size, APInt(8, 0xF0)));
10511
10512 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
10513 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
10514 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
10515 MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,
10516 APInt::getSplat(Size, APInt(8, 0xCC)));
10517
10518 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
10519 // 6|7
10520 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
10521 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
10522 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
10523 }
10524 } else {
10525 // Expand bitreverse for types smaller than 8 bits.
10527 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
10529 if (I < J) {
10530 auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);
10531 Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);
10532 } else {
10533 auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);
10534 Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);
10535 }
10536
10537 auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);
10538 Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);
10539 if (I == 0)
10540 Tmp = Tmp2;
10541 else
10542 Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);
10543 }
10544 MIRBuilder.buildCopy(Dst, Tmp);
10545 }
10546
10547 MI.eraseFromParent();
10548 return Legalized;
10549}
10550
10553 MachineFunction &MF = MIRBuilder.getMF();
10554
10555 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
10556 int NameOpIdx = IsRead ? 1 : 0;
10557 int ValRegIndex = IsRead ? 0 : 1;
10558
10559 Register ValReg = MI.getOperand(ValRegIndex).getReg();
10560 const LLT Ty = MRI.getType(ValReg);
10561 const MDString *RegStr = cast<MDString>(
10562 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
10563
10564 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
10565 if (!PhysReg) {
10566 const Function &Fn = MF.getFunction();
10568 "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +
10569 (IsRead ? "llvm.read_register" : "llvm.write_register"),
10570 Fn, MI.getDebugLoc()));
10571 if (IsRead)
10572 MIRBuilder.buildUndef(ValReg);
10573
10574 MI.eraseFromParent();
10575 return Legalized;
10576 }
10577
10578 if (IsRead)
10579 MIRBuilder.buildCopy(ValReg, PhysReg);
10580 else
10581 MIRBuilder.buildCopy(PhysReg, ValReg);
10582
10583 MI.eraseFromParent();
10584 return Legalized;
10585}
10586
10589 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
10590 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
10591 Register Result = MI.getOperand(0).getReg();
10592 LLT OrigTy = MRI.getType(Result);
10593 auto SizeInBits = OrigTy.getScalarSizeInBits();
10594 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
10595
10596 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
10597 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
10598 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
10599 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
10600
10601 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
10602 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
10603 MIRBuilder.buildTrunc(Result, Shifted);
10604
10605 MI.eraseFromParent();
10606 return Legalized;
10607}
10608
10611 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10612 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
10613
10614 if (Mask == fcNone) {
10615 MIRBuilder.buildConstant(DstReg, 0);
10616 MI.eraseFromParent();
10617 return Legalized;
10618 }
10619 if (Mask == fcAllFlags) {
10620 MIRBuilder.buildConstant(DstReg, 1);
10621 MI.eraseFromParent();
10622 return Legalized;
10623 }
10624
10625 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
10626 // version
10627
10628 unsigned BitSize = SrcTy.getScalarSizeInBits();
10629 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
10630
10631 LLT IntTy = SrcTy.changeElementType(LLT::integer(BitSize));
10632 auto AsInt = SrcTy == IntTy ? MIRBuilder.buildCopy(IntTy, SrcReg)
10633 : MIRBuilder.buildBitcast(IntTy, SrcReg);
10634
10635 // Various masks.
10636 APInt SignBit = APInt::getSignMask(BitSize);
10637 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
10638 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
10639 APInt ExpMask = Inf;
10640 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
10641 APInt QNaNBitMask =
10642 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
10643 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
10644
10645 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
10646 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
10647 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
10648 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
10649 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
10650
10651 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
10652 auto Sign =
10653 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
10654
10655 auto Res = MIRBuilder.buildConstant(DstTy, 0);
10656 // Clang doesn't support capture of structured bindings:
10657 LLT DstTyCopy = DstTy;
10658 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
10659 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
10660 };
10661
10662 // Tests that involve more than one class should be processed first.
10663 if ((Mask & fcFinite) == fcFinite) {
10664 // finite(V) ==> abs(V) u< exp_mask
10665 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10666 ExpMaskC));
10667 Mask &= ~fcFinite;
10668 } else if ((Mask & fcFinite) == fcPosFinite) {
10669 // finite(V) && V > 0 ==> V u< exp_mask
10670 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
10671 ExpMaskC));
10672 Mask &= ~fcPosFinite;
10673 } else if ((Mask & fcFinite) == fcNegFinite) {
10674 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
10675 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10676 ExpMaskC);
10677 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
10678 appendToRes(And);
10679 Mask &= ~fcNegFinite;
10680 }
10681
10682 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
10683 // fcZero | fcSubnormal => test all exponent bits are 0
10684 // TODO: Handle sign bit specific cases
10685 // TODO: Handle inverted case
10686 if (PartialCheck == (fcZero | fcSubnormal)) {
10687 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
10688 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10689 ExpBits, ZeroC));
10690 Mask &= ~PartialCheck;
10691 }
10692 }
10693
10694 // Check for individual classes.
10695 if (FPClassTest PartialCheck = Mask & fcZero) {
10696 if (PartialCheck == fcPosZero)
10697 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10698 AsInt, ZeroC));
10699 else if (PartialCheck == fcZero)
10700 appendToRes(
10701 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
10702 else // fcNegZero
10703 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10704 AsInt, SignBitC));
10705 }
10706
10707 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
10708 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
10709 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
10710 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
10711 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
10712 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
10713 auto SubnormalRes =
10714 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
10715 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
10716 if (PartialCheck == fcNegSubnormal)
10717 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
10718 appendToRes(SubnormalRes);
10719 }
10720
10721 if (FPClassTest PartialCheck = Mask & fcInf) {
10722 if (PartialCheck == fcPosInf)
10723 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10724 AsInt, InfC));
10725 else if (PartialCheck == fcInf)
10726 appendToRes(
10727 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
10728 else { // fcNegInf
10729 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
10730 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
10731 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10732 AsInt, NegInfC));
10733 }
10734 }
10735
10736 if (FPClassTest PartialCheck = Mask & fcNan) {
10737 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
10738 if (PartialCheck == fcNan) {
10739 // isnan(V) ==> abs(V) u> int(inf)
10740 appendToRes(
10741 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
10742 } else if (PartialCheck == fcQNan) {
10743 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
10744 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
10745 InfWithQnanBitC));
10746 } else { // fcSNan
10747 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
10748 // abs(V) u< (unsigned(Inf) | quiet_bit)
10749 auto IsNan =
10750 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
10751 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
10752 Abs, InfWithQnanBitC);
10753 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
10754 }
10755 }
10756
10757 if (FPClassTest PartialCheck = Mask & fcNormal) {
10758 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
10759 // (max_exp-1))
10760 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
10761 auto ExpMinusOne = MIRBuilder.buildSub(
10762 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
10763 APInt MaxExpMinusOne = ExpMask - ExpLSB;
10764 auto NormalRes =
10765 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
10766 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
10767 if (PartialCheck == fcNegNormal)
10768 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
10769 else if (PartialCheck == fcPosNormal) {
10770 auto PosSign = MIRBuilder.buildXor(
10771 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));
10772 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
10773 }
10774 appendToRes(NormalRes);
10775 }
10776
10777 MIRBuilder.buildCopy(DstReg, Res);
10778 MI.eraseFromParent();
10779 return Legalized;
10780}
10781
10783 // Implement G_SELECT in terms of XOR, AND, OR.
10784 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
10785 MI.getFirst4RegLLTs();
10786
10787 LLT Op1TyInt =
10788 Op1Ty.changeElementType(LLT::integer(Op1Ty.getScalarSizeInBits()));
10789
10790 bool IsEltPtr = DstTy.isPointerOrPointerVector();
10791 if (IsEltPtr) {
10792 LLT ScalarPtrTy = LLT::integer(DstTy.getScalarSizeInBits());
10793 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
10794 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
10795 Op1Ty = MRI.getType(Op1Reg);
10796 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
10797 Op2Ty = MRI.getType(Op2Reg);
10798 DstTy = NewTy;
10799 }
10800
10801 if (MaskTy.isScalar()) {
10802 // Turn the scalar condition into a vector condition mask if needed.
10803
10804 Register MaskElt = MaskReg;
10805
10806 // The condition was potentially zero extended before, but we want a sign
10807 // extended boolean.
10808 if (MaskTy != LLT::scalar(1))
10809 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
10810
10811 // Continue the sign extension (or truncate) to match the data type.
10812 MaskTy = DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10813 MaskElt =
10814 MIRBuilder.buildSExtOrTrunc(MaskTy.getScalarType(), MaskElt).getReg(0);
10815
10816 if (DstTy.isVector()) {
10817 // Generate a vector splat idiom.
10818 auto ShufSplat = MIRBuilder.buildShuffleSplat(MaskTy, MaskElt);
10819 MaskReg = ShufSplat.getReg(0);
10820 } else {
10821 MaskReg = MaskElt;
10822 }
10823 } else if (!DstTy.isVector()) {
10824 // Cannot handle the case that mask is a vector and dst is a scalar.
10825 return UnableToLegalize;
10826 }
10827
10828 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
10829 return UnableToLegalize;
10830 }
10831
10832 if (!Op1Ty.getScalarType().isAnyScalar() &&
10833 !Op1Ty.getScalarType().isInteger())
10834 Op1Reg = MIRBuilder.buildBitcast(Op1TyInt, Op1Reg).getReg(0);
10835
10836 if (!Op2Ty.getScalarType().isAnyScalar() &&
10837 !Op2Ty.getScalarType().isInteger()) {
10838 auto Op2TyInt =
10839 Op2Ty.changeElementType(LLT::integer(Op2Ty.getScalarSizeInBits()));
10840 Op2Reg = MIRBuilder.buildBitcast(Op2TyInt, Op2Reg).getReg(0);
10841 }
10842
10843 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
10844 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
10845 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
10846 if (IsEltPtr) {
10847 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
10848 MIRBuilder.buildIntToPtr(DstReg, Or);
10849 } else {
10850 if (DstTy == Op1TyInt)
10851 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
10852 else {
10853 auto Or = MIRBuilder.buildOr(Op1TyInt, NewOp1, NewOp2);
10854 MIRBuilder.buildBitcast(DstReg, Or.getReg(0));
10855 }
10856 }
10857 MI.eraseFromParent();
10858 return Legalized;
10859}
10860
10862 // Split DIVREM into individual instructions.
10863 unsigned Opcode = MI.getOpcode();
10864
10865 MIRBuilder.buildInstr(
10866 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
10867 : TargetOpcode::G_UDIV,
10868 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10869 MIRBuilder.buildInstr(
10870 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
10871 : TargetOpcode::G_UREM,
10872 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10873 MI.eraseFromParent();
10874 return Legalized;
10875}
10876
10879 // Expand %res = G_ABS %a into:
10880 // %v1 = G_ASHR %a, scalar_size-1
10881 // %v2 = G_ADD %a, %v1
10882 // %res = G_XOR %v2, %v1
10883 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
10884 Register OpReg = MI.getOperand(1).getReg();
10885 auto ShiftAmt =
10886 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
10887 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
10888 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
10889 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
10890 MI.eraseFromParent();
10891 return Legalized;
10892}
10893
10896 // Expand %res = G_ABS %a into:
10897 // %v1 = G_CONSTANT 0
10898 // %v2 = G_SUB %v1, %a
10899 // %res = G_SMAX %a, %v2
10900 Register SrcReg = MI.getOperand(1).getReg();
10901 LLT Ty = MRI.getType(SrcReg);
10902 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10903 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
10904 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
10905 MI.eraseFromParent();
10906 return Legalized;
10907}
10908
10911 Register SrcReg = MI.getOperand(1).getReg();
10912 Register DestReg = MI.getOperand(0).getReg();
10913 LLT Ty = MRI.getType(SrcReg), IType = LLT::integer(1);
10914 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
10915 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
10916 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
10917 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
10918 MI.eraseFromParent();
10919 return Legalized;
10920}
10921
10924 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10925 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10926 "Expected G_ABDS or G_ABDU instruction");
10927
10928 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10929 LLT Ty = MRI.getType(LHS);
10930
10931 // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10932 // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10933 Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);
10934 Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);
10935 CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)
10938 auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);
10939 MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);
10940
10941 MI.eraseFromParent();
10942 return Legalized;
10943}
10944
10947 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10948 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10949 "Expected G_ABDS or G_ABDU instruction");
10950
10951 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10952 LLT Ty = MRI.getType(LHS);
10953
10954 // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))
10955 // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))
10956 Register MaxReg, MinReg;
10957 if (MI.getOpcode() == TargetOpcode::G_ABDS) {
10958 MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);
10959 MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);
10960 } else {
10961 MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);
10962 MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);
10963 }
10964 MIRBuilder.buildSub(DstReg, MaxReg, MinReg);
10965
10966 MI.eraseFromParent();
10967 return Legalized;
10968}
10969
10971 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10972 LLT TyInt =
10973 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10974 Register CastedSrc = SrcReg;
10975
10976 if (!(SrcTy.getScalarType().isAnyScalar() ||
10977 SrcTy.getScalarType().isInteger())) {
10978 auto SrcTyInt =
10979 SrcTy.changeElementType(LLT::integer(SrcTy.getScalarSizeInBits()));
10980 CastedSrc = MIRBuilder.buildBitcast(SrcTyInt, SrcReg).getReg(0);
10981 }
10982
10983 if (MRI.getType(DstReg) != TyInt) {
10984 // Reset sign bit
10985 Register NewDst =
10987 .buildAnd(TyInt, CastedSrc,
10988 MIRBuilder.buildConstant(
10990 DstTy.getScalarSizeInBits())))
10991 .getReg(0);
10992
10993 MIRBuilder.buildBitcast(DstReg, NewDst);
10994 } else
10996 .buildAnd(
10997 DstReg, CastedSrc,
10998 MIRBuilder.buildConstant(
10999 TyInt, APInt::getSignedMaxValue(DstTy.getScalarSizeInBits())))
11000 .getReg(0);
11001
11002 MI.eraseFromParent();
11003 return Legalized;
11004}
11005
11008 Register SrcReg = MI.getOperand(1).getReg();
11009 LLT SrcTy = MRI.getType(SrcReg);
11010 LLT DstTy = MRI.getType(SrcReg);
11011
11012 // The source could be a scalar if the IR type was <1 x sN>.
11013 if (SrcTy.isScalar()) {
11014 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
11015 return UnableToLegalize; // FIXME: handle extension.
11016 // This can be just a plain copy.
11017 Observer.changingInstr(MI);
11018 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
11019 Observer.changedInstr(MI);
11020 return Legalized;
11021 }
11022 return UnableToLegalize;
11023}
11024
11026 MachineFunction &MF = *MI.getMF();
11027 const DataLayout &DL = MIRBuilder.getDataLayout();
11028 LLVMContext &Ctx = MF.getFunction().getContext();
11029 Register ListPtr = MI.getOperand(1).getReg();
11030 LLT PtrTy = MRI.getType(ListPtr);
11031
11032 // LstPtr is a pointer to the head of the list. Get the address
11033 // of the head of the list.
11034 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
11035 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
11036 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
11037 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
11038
11039 const Align A(MI.getOperand(2).getImm());
11040 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
11041 if (A > TLI.getMinStackArgumentAlignment()) {
11042 Register AlignAmt =
11043 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
11044 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
11045 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
11046 VAList = AndDst.getReg(0);
11047 }
11048
11049 // Increment the pointer, VAList, to the next vaarg
11050 // The list should be bumped by the size of element in the current head of
11051 // list.
11052 Register Dst = MI.getOperand(0).getReg();
11053 LLT LLTTy = MRI.getType(Dst);
11054 Type *Ty = getTypeForLLT(LLTTy, Ctx);
11055 auto IncAmt =
11056 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
11057 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
11058
11059 // Store the increment VAList to the legalized pointer
11061 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
11062 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
11063 // Load the actual argument out of the pointer VAList
11064 Align EltAlignment = DL.getABITypeAlign(Ty);
11065 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
11066 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
11067 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
11068
11069 MI.eraseFromParent();
11070 return Legalized;
11071}
11072
11074 unsigned OpCode = MI.getOpcode();
11075 assert((OpCode == TargetOpcode::G_SMULFIX ||
11076 OpCode == TargetOpcode::G_UMULFIX ||
11077 OpCode == TargetOpcode::G_SMULFIXSAT ||
11078 OpCode == TargetOpcode::G_UMULFIXSAT) &&
11079 "Operator must be either G_SMULFIX[SAT] or G_UMULFIX[SAT]!");
11080 auto [Dst, LHS, RHS] = MI.getFirst3Regs();
11081 LLT Ty = MRI.getType(Dst);
11082 unsigned Scale = MI.getOperand(3).getImm();
11083
11084 bool Saturating = (OpCode == TargetOpcode::G_SMULFIXSAT ||
11085 OpCode == TargetOpcode::G_UMULFIXSAT);
11086 bool IsSigned = (OpCode == TargetOpcode::G_SMULFIX ||
11087 OpCode == TargetOpcode::G_SMULFIXSAT);
11088
11089 if (!Saturating && Scale == 0) {
11090 MIRBuilder.buildMul(Dst, LHS, RHS);
11091 MI.eraseFromParent();
11092 return Legalized;
11093 }
11094
11095 // TODO: Port other lowering paths from SelectionDAG.
11096 LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
11097 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
11098 MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
11099 if (IsSigned) {
11100 ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
11101 ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
11102 } else {
11103 ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
11104 ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
11105 }
11106
11107 auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
11108 if (IsSigned)
11109 Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
11110 else
11111 Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
11112
11113 if (!Saturating)
11114 MIRBuilder.buildTrunc(Dst, Shift);
11115 else if (IsSigned)
11116 MIRBuilder.buildTruncSSatS(Dst, Shift);
11117 else
11118 MIRBuilder.buildTruncUSatU(Dst, Shift);
11119
11120 MI.eraseFromParent();
11121 return Legalized;
11122}
11123
11124// Get a vectorized representation of the memset value operand, GISel edition.
11126 MachineRegisterInfo &MRI = *MIB.getMRI();
11127 unsigned NumBits = Ty.getScalarSizeInBits();
11128 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
11129 if (!Ty.isVector() && ValVRegAndVal) {
11130 APInt Scalar = ValVRegAndVal->Value.trunc(8);
11131 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
11132 return MIB.buildConstant(Ty, SplatVal).getReg(0);
11133 }
11134
11135 // Extend the byte value to the larger type, and then multiply by a magic
11136 // value 0x010101... in order to replicate it across every byte.
11137 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
11138 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
11139 return MIB.buildConstant(Ty, 0).getReg(0);
11140 }
11141
11142 LLT ExtType = Ty.getScalarType();
11143 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
11144 if (NumBits > 8) {
11145 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
11146 auto MagicMI = MIB.buildConstant(ExtType, Magic);
11147 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
11148 }
11149
11150 // For vector types create a G_BUILD_VECTOR.
11151 if (Ty.isVector())
11152 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
11153
11154 return Val;
11155}
11156
11158LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
11159 uint64_t KnownLen, Align Alignment,
11160 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11161 auto &MF = *MI.getParent()->getParent();
11162 const auto &TLI = *MF.getSubtarget().getTargetLowering();
11163 auto &DL = MF.getDataLayout();
11164 LLVMContext &C = MF.getFunction().getContext();
11165
11166 assert(KnownLen != 0 && "Have a zero length memset length!");
11167 assert(!MemOps.empty() && "Expected at least one memory op");
11168
11169 MachineFrameInfo &MFI = MF.getFrameInfo();
11170 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11171 const auto &DstMMO = **MI.memoperands_begin();
11172
11173 if (DstAlignCanChange) {
11174 // Get an estimate of the type from the LLT.
11175 Type *IRTy = getTypeForLLT(MemOps[0], C);
11176 Align NewAlign = DL.getABITypeAlign(IRTy);
11177 if (NewAlign > Alignment) {
11178 Alignment = NewAlign;
11179 unsigned FI = FIDef->getOperand(1).getIndex();
11180 // Give the stack frame object a larger alignment if needed.
11181 if (MFI.getObjectAlign(FI) < Alignment)
11182 MFI.setObjectAlignment(FI, Alignment);
11183 }
11184 }
11185
11186 MachineIRBuilder MIB(MI);
11187 // Find the largest store and generate the bit pattern for it.
11188 LLT LargestTy = MemOps[0];
11189 for (unsigned i = 1; i < MemOps.size(); i++)
11190 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
11191 LargestTy = MemOps[i];
11192
11193 // The memset stored value is always defined as an s8, so in order to make it
11194 // work with larger store types we need to repeat the bit pattern across the
11195 // wider type.
11196 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
11197
11198 if (!MemSetValue)
11199 return UnableToLegalize;
11200
11201 // Generate the stores. For each store type in the list, we generate the
11202 // matching store of that type to the destination address.
11203 LLT PtrTy = MRI.getType(Dst);
11204 unsigned DstOff = 0;
11205 unsigned Size = KnownLen;
11206 for (unsigned I = 0; I < MemOps.size(); I++) {
11207 LLT Ty = MemOps[I];
11208 unsigned TySize = Ty.getSizeInBytes();
11209
11210 if (TySize > Size) {
11211 // Issuing a load / store pair that overlaps with the previous pair.
11212 // Adjust the offset accordingly.
11213 assert(I == MemOps.size() - 1 && I != 0);
11214 DstOff -= TySize - Size;
11215 }
11216
11217 // If this store is smaller than the largest store see whether we can get
11218 // the smaller value for free with a truncate.
11219 Register Value = MemSetValue;
11220 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
11221 MVT VT = getMVTForLLT(Ty);
11222 MVT LargestVT = getMVTForLLT(LargestTy);
11223 if (!LargestTy.isVector() && !Ty.isVector() &&
11224 TLI.isTruncateFree(LargestVT, VT))
11225 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
11226 else
11227 Value = getMemsetValue(Val, Ty, MIB);
11228 if (!Value)
11229 return UnableToLegalize;
11230 }
11231
11232 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
11233
11234 Register Ptr = Dst;
11235 if (DstOff != 0) {
11236 auto Offset =
11237 MIB.buildConstant(LLT::integer(PtrTy.getSizeInBits()), DstOff);
11238 Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);
11239 }
11240
11241 MIB.buildStore(Value, Ptr, *StoreMMO);
11242 DstOff += Ty.getSizeInBytes();
11243 Size -= TySize;
11244 }
11245
11246 MI.eraseFromParent();
11247 return Legalized;
11248}
11249
11251LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
11252 uint64_t KnownLen, Align Alignment,
11253 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11254 auto &MF = *MI.getParent()->getParent();
11255 auto &DL = MF.getDataLayout();
11256 LLVMContext &C = MF.getFunction().getContext();
11257
11258 assert(KnownLen != 0 && "Have a zero length memcpy length!");
11259 assert(!MemOps.empty() && "Expected at least one memory op");
11260
11261 MachineFrameInfo &MFI = MF.getFrameInfo();
11262 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11263
11264 // FIXME: infer better src pointer alignment like SelectionDAG does here.
11265 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
11266 // if the memcpy is in a tail call position.
11267
11268 const auto &DstMMO = **MI.memoperands_begin();
11269 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11270
11271 if (DstAlignCanChange) {
11272 // Get an estimate of the type from the LLT.
11273 Type *IRTy = getTypeForLLT(MemOps[0], C);
11274 Align NewAlign = DL.getABITypeAlign(IRTy);
11275
11276 // Don't promote to an alignment that would require dynamic stack
11277 // realignment.
11278 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11279 if (!TRI->hasStackRealignment(MF))
11280 if (MaybeAlign StackAlign = DL.getStackAlignment())
11281 NewAlign = std::min(NewAlign, *StackAlign);
11282
11283 if (NewAlign > Alignment) {
11284 Alignment = NewAlign;
11285 unsigned FI = FIDef->getOperand(1).getIndex();
11286 // Give the stack frame object a larger alignment if needed.
11287 if (MFI.getObjectAlign(FI) < Alignment)
11288 MFI.setObjectAlignment(FI, Alignment);
11289 }
11290 }
11291
11292 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
11293
11294 MachineIRBuilder MIB(MI);
11295 // Now we need to emit a pair of load and stores for each of the types we've
11296 // collected. I.e. for each type, generate a load from the source pointer of
11297 // that type width, and then generate a corresponding store to the dest buffer
11298 // of that value loaded. This can result in a sequence of loads and stores
11299 // mixed types, depending on what the target specifies as good types to use.
11300 LLT SrcTy = MRI.getType(Src);
11301 LLT DstTy = MRI.getType(Dst);
11302 unsigned SrcIndexSize = DL.getIndexSizeInBits(SrcTy.getAddressSpace());
11303 unsigned DstIndexSize = DL.getIndexSizeInBits(DstTy.getAddressSpace());
11304 unsigned CurrOffset = 0;
11305 unsigned Size = KnownLen;
11306 for (auto CopyTy : MemOps) {
11307 TypeSize TySize = CopyTy.getSizeInBytes();
11308
11309 // Issuing a load / store pair that overlaps with the previous pair. Adjust
11310 // the offset accordingly.
11311 if (TySize > Size) {
11312 unsigned Overlap = TySize - Size;
11313 assert(Overlap < CurrOffset &&
11314 "overlapping memcpy load/store spans the whole region or more");
11315 CurrOffset -= Overlap;
11316 }
11317
11318 // Construct MMOs for the accesses.
11319 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11320 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11321
11322 // Create the load.
11323 Register LoadPtr = Src;
11325 if (CurrOffset != 0) {
11326 Offset =
11327 MIB.buildConstant(LLT::integer(SrcIndexSize), CurrOffset).getReg(0);
11328 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11329 }
11330 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
11331
11332 // Create the store.
11333 Register StorePtr = Dst;
11334 if (CurrOffset != 0) {
11335 if (SrcIndexSize != DstIndexSize) {
11336 Offset =
11337 MIB.buildConstant(LLT::integer(DstIndexSize), CurrOffset).getReg(0);
11338 }
11339 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11340 }
11341 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
11342 CurrOffset += TySize;
11343 Size -= TySize;
11344 }
11345
11346 MI.eraseFromParent();
11347 return Legalized;
11348}
11349
11351LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
11352 uint64_t KnownLen, Align Alignment,
11353 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11354 auto &MF = *MI.getParent()->getParent();
11355 auto &DL = MF.getDataLayout();
11356 LLVMContext &C = MF.getFunction().getContext();
11357
11358 assert(KnownLen != 0 && "Have a zero length memmove length!");
11359 assert(!MemOps.empty() && "Expected at least one memory op");
11360
11361 MachineFrameInfo &MFI = MF.getFrameInfo();
11362 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11363 const auto &DstMMO = **MI.memoperands_begin();
11364 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11365
11366 if (DstAlignCanChange) {
11367 // Get an estimate of the type from the LLT.
11368 Type *IRTy = getTypeForLLT(MemOps[0], C);
11369 Align NewAlign = DL.getABITypeAlign(IRTy);
11370
11371 // Don't promote to an alignment that would require dynamic stack
11372 // realignment.
11373 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11374 if (!TRI->hasStackRealignment(MF))
11375 if (MaybeAlign StackAlign = DL.getStackAlignment())
11376 NewAlign = std::min(NewAlign, *StackAlign);
11377
11378 if (NewAlign > Alignment) {
11379 Alignment = NewAlign;
11380 unsigned FI = FIDef->getOperand(1).getIndex();
11381 // Give the stack frame object a larger alignment if needed.
11382 if (MFI.getObjectAlign(FI) < Alignment)
11383 MFI.setObjectAlignment(FI, Alignment);
11384 }
11385 }
11386
11387 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
11388
11389 MachineIRBuilder MIB(MI);
11390 // Memmove requires that we perform the loads first before issuing the stores.
11391 // Apart from that, this loop is pretty much doing the same thing as the
11392 // memcpy codegen function.
11393 unsigned CurrOffset = 0;
11394 unsigned Size = KnownLen;
11395 SmallVector<Register, 16> LoadVals;
11396 for (auto CopyTy : MemOps) {
11397 TypeSize TySize = CopyTy.getSizeInBytes();
11398
11399 // Issuing a load that overlaps with the previous load. Adjust the offset
11400 // accordingly.
11401 if (TySize > Size) {
11402 unsigned Overlap = TySize - Size;
11403 assert(Overlap < CurrOffset &&
11404 "overlapping memmove load spans the whole region or more");
11405 CurrOffset -= Overlap;
11406 }
11407
11408 // Construct MMO for the load.
11409 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11410
11411 // Create the load.
11412 Register LoadPtr = Src;
11413 if (CurrOffset != 0) {
11414 LLT SrcTy = MRI.getType(Src);
11415 auto Offset =
11416 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset);
11417 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11418 }
11419 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
11420 CurrOffset += TySize;
11421 Size -= TySize;
11422 }
11423
11424 CurrOffset = 0;
11425 Size = KnownLen;
11426 for (unsigned I = 0; I < MemOps.size(); ++I) {
11427 LLT CopyTy = MemOps[I];
11428 TypeSize TySize = CopyTy.getSizeInBytes();
11429
11430 // Issuing a store that overlaps with the previous store. Adjust the offset
11431 // accordingly.
11432 if (TySize > Size) {
11433 unsigned Overlap = TySize - Size;
11434 assert(Overlap < CurrOffset &&
11435 "overlapping memmove store spans the whole region or more");
11436 CurrOffset -= Overlap;
11437 }
11438
11439 // Now store the values loaded.
11440 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11441
11442 Register StorePtr = Dst;
11443 if (CurrOffset != 0) {
11444 LLT DstTy = MRI.getType(Dst);
11445 auto Offset =
11446 MIB.buildConstant(LLT::integer(DstTy.getSizeInBits()), CurrOffset);
11447 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11448 }
11449 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
11450 CurrOffset += TySize;
11451 Size -= TySize;
11452 }
11453 MI.eraseFromParent();
11454 return Legalized;
11455}
11456
11458 MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen,
11459 Align Alignment, bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11460 const unsigned Opc = MI.getOpcode();
11461 assert((Opc == TargetOpcode::G_MEMCPY ||
11462 Opc == TargetOpcode::G_MEMCPY_INLINE ||
11463 Opc == TargetOpcode::G_MEMMOVE || Opc == TargetOpcode::G_MEMSET ||
11464 Opc == TargetOpcode::G_MEMSET_INLINE) &&
11465 "Expected memcpy like instruction");
11466
11467 if (KnownLen == 0) {
11468 MI.eraseFromParent();
11469 return Legalized;
11470 }
11471
11472 if (Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMCPY_INLINE) {
11473 return lowerMemcpy(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11474 MemOps);
11475 }
11476 if (Opc == TargetOpcode::G_MEMMOVE)
11477 return lowerMemmove(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11478 MemOps);
11479 if (Opc == TargetOpcode::G_MEMSET || Opc == TargetOpcode::G_MEMSET_INLINE)
11480 return lowerMemset(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11481 MemOps);
11482 return UnableToLegalize;
11483}
11484
11487 Register Dst, Src;
11488 uint64_t KnownLen;
11489 Align Alignment;
11490 bool DstAlignCanChange;
11491 std::vector<LLT> MemOps;
11492 if (!canLowerMemCpyFamily(MI, MRI, MaxLen, Dst, Src, KnownLen, Alignment,
11493 DstAlignCanChange, MemOps))
11494 return UnableToLegalize;
11495 return lowerMemCpyFamily(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11496 MemOps);
11497}
unsigned NumParts
const TargetLowering & TLI
SDValue Pred
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
constexpr LLT S1
constexpr LLT S32
constexpr LLT S64
AMDGPU Register Bank Select
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
bpf unwind lower
#define X(NUM, ENUM, NAME)
Definition ELF.h:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file describes how to lower LLVM calls to machine code calls.
#define GISEL_VECREDUCE_CASES_NONSEQ
Definition Utils.h:79
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred)
#define RTLIBCASE_INT(LibcallPrefix)
static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI)
static Register buildBitFieldInsert(MachineIRBuilder &B, Register TargetReg, Register InsertReg, Register OffsetBits)
Emit code to insert InsertReg into TargetRet at OffsetBits in TargetReg, while preserving other bits ...
static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB)
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size)
static std::pair< RTLIB::Libcall, CmpInst::Predicate > getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size)
Returns the corresponding libcall for the given Pred and the ICMP predicate that should be generated ...
static void broadcastSrcOp(SmallVectorImpl< SrcOp > &Ops, unsigned N, MachineOperand &Op)
Operand Op is used on N sub-instructions.
static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result, MachineInstr &MI, const TargetInstrInfo &TII, MachineRegisterInfo &MRI)
True if an instruction is in tail position in its caller.
static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B, Register Idx, unsigned NewEltSize, unsigned OldEltSize)
Figure out the bit offset into a register when coercing a vector index for the wide element type.
static void makeDstOps(SmallVectorImpl< DstOp > &DstOps, LLT Ty, unsigned NumElts)
Fill DstOps with DstOps that have same number of elements combined as the Ty.
#define LCALL5(A)
static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B, MachineInstrBuilder Src, const APInt &Mask)
static bool isNonZeroModBitWidth(const MachineRegisterInfo &MRI, Register Reg, unsigned BW)
static bool hasSwiftErrorArg(MachineFunction &MF)
static LegalizerHelper::LegalizeResult loweri64tof16ITOFP(MachineInstr &MI, Register Dst, LLT DstTy, Register Src, LLT SrcTy, MachineIRBuilder &MIRBuilder)
i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16.
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
static void getUnmergePieces(SmallVectorImpl< Register > &Pieces, MachineIRBuilder &B, Register Src, LLT Ty)
static CmpInst::Predicate minMaxToCompare(unsigned Opc)
static MachineBasicBlock::iterator getPHIIncomingInsertPoint(MachineBasicBlock &MBB, Register Reg, const MachineRegisterInfo &MRI)
Choose an insertion point for a conversion of an incoming PHI value.
static RTLIB::Libcall getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI)
static std::pair< int, int > getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy)
Try to break down OrigTy into NarrowTy sized pieces.
static bool hasSameNumEltsOnAllVectorOperands(GenericMachineInstr &MI, MachineRegisterInfo &MRI, std::initializer_list< unsigned > NonVecOpIndices)
Check that all vector operands have same number of elements.
static Register clampVectorIndex(MachineIRBuilder &B, Register IdxReg, LLT VecTy)
static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType, Type *FromType)
static void getUnmergeResults(SmallVectorImpl< Register > &Regs, const MachineInstr &MI)
Append the result registers of G_UNMERGE_VALUES MI to Regs.
static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo &MRI, Register Reg, unsigned BW)
#define RTLIBCASE(LibcallPrefix)
static Type * getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty)
Interface for Targets to specify which operations they can successfully select and how the others sho...
Tracks DebugLocs between checkpoints and verifies that they are transferred.
Implement a low-level type suitable for MachineInstr level instruction selection.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t High
R600 Clause Merge
static constexpr MCPhysReg SPReg
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
Remove Loads Into Fake Uses
#define LLVM_DEBUG(...)
Definition Debug.h:119
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
Value * RHS
Value * LHS
BinaryOperator * Mul
The Input class is used to parse a yaml document into in-memory structs and vectors.
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
static constexpr roundingMode rmTowardZero
Definition APFloat.h:365
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:377
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
Definition APFloat.h:1451
APInt bitcastToAPInt() const
Definition APFloat.h:1475
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1242
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1202
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
Definition APFloat.h:1213
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
Definition APInt.h:202
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
Definition APInt.h:1186
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
Definition APInt.h:254
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:205
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
Definition APInt.h:212
void negate()
Negate this APInt in place.
Definition APInt.h:1488
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:648
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:215
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1030
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:875
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:235
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
static APInt getBitsSetWithWrap(unsigned numBits, unsigned loBit, unsigned hiBit)
Wrap version of getBitsSet.
Definition APInt.h:266
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator end() const
Definition ArrayRef.h:130
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:754
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:752
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
bool isSigned() const
Definition InstrTypes.h:993
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
Definition InstrTypes.h:852
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
const APFloat & getValueAPF() const
Definition Constants.h:463
This is the shared class of boolean and integer constants.
Definition Constants.h:87
const APInt & getValue() const
Return the constant as an APInt value reference.
Definition Constants.h:159
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
bool isBigEndian() const
Definition DataLayout.h:218
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
LLT getLLTTy(const MachineRegisterInfo &MRI) const
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:306
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition TypeSize.h:312
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:329
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getValueReg() const
Get the stored value register.
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
Represents a insert subvector.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
Represents a threeway compare.
Represents a G_STORE.
A base class for all GenericMachineInstrs.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static bool isEquality(Predicate P)
Return true if this predicate is either EQ or NE.
Predicate getUnsignedPredicate() const
For example, EQ->EQ, SLE->ULE, UGT->UGT, etc.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
bool isKnownNever(FPClassMask Mask) const
Return true if it's known this can never be one of the mask entries.
static constexpr LLT float64()
Get a 64-bit IEEE double value.
LLT changeElementCount(ElementCount EC) const
Return a vector or scalar with the same element type and the new element count.
constexpr unsigned getScalarSizeInBits() const
constexpr bool isScalar() const
constexpr LLT changeElementType(LLT NewEltTy) const
If this type is a vector, return a vector with the same number of elements but the new element type.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isFloat() const
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr bool isScalable() const
Returns true if the LLT is a scalable vector.
constexpr bool isByteSized() const
LLT changeToInteger() const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
constexpr bool isPointer() const
constexpr ElementCount getElementCount() const
static constexpr LLT float16()
Get a 16-bit IEEE half value.
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
static LLT integer(unsigned SizeInBits)
static constexpr LLT bfloat16()
constexpr LLT changeVectorElementType(LLT NewEltTy) const
Returns a vector with the same number of elements but the new element type.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LLT changeVectorElementCount(ElementCount EC) const
Return a vector with the same element type and the new element count.
static constexpr LLT float32()
Get a 32-bit IEEE float value.
static LLT floatIEEE(unsigned SizeInBits)
LLT changeElementSize(unsigned NewEltSize) const
If this type is a vector, return a vector with the same number of elements but the new element size.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LLVM_ABI LegalizeResult lowerShlSat(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerThreewayCompare(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI)
LLVM_ABI LegalizeResult equalizeVectorShuffleLengths(MachineInstr &MI)
Equalize source and destination vector sizes of G_SHUFFLE_VECTOR.
LLVM_ABI LegalizeResult bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_INSERT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerDynStackAlloc(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBitCount(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarMul(MachineInstr &MI, LLT Ty)
LLVM_ABI LegalizeResult lowerFMinNumMaxNum(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF64BitFloatOps(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSSUBE(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerIntrinsicRound(MachineInstr &MI)
LLVM_ABI void widenScalarSrc(MachineInstr &MI, LLT WideTy, unsigned OpIdx, unsigned ExtOpcode)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI LegalizeResult moreElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
LLVM_ABI LegalizeResult lowerSMULH_UMULH(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerLoad(GAnyLoad &MI)
LLVM_ABI LegalizeResult fewerElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerAbsToAddXor(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPEXT_BF16(MachineInstr &MI)
LLVM_ABI void moreElementsVectorDst(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Def by performing it with addition...
LLVM_ABI LegalizerHelper::LegalizeResult createAtomicLibcall(MachineInstr &MI) const
LLVM_ABI LegalizeResult lowerFConstant(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerBitreverse(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI)
Lower a vector extract or insert by writing the vector to a stack temporary and reloading the element...
LLVM_ABI LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
Legalize a vector instruction by increasing the number of vector elements involved and ignoring the a...
LLVM_ABI LegalizeResult lowerFunnelShiftWithInverse(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTLS(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStore(GStore &MI)
LLVM_ABI LegalizeResult lowerAbsToCNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastExtractSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
LLVM_ABI LegalizeResult narrowScalarShiftMultiway(MachineInstr &MI, LLT TargetTy)
Multi-way shift legalization: directly split wide shifts into target-sized parts in a single step,...
LLVM_ABI Register lowerRoundInexactToOdd(LLT ResultTy, Register Op)
LLVM_ABI LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
LLVM_ABI Register buildConstantShiftPart(unsigned Opcode, unsigned PartIdx, unsigned NumParts, ArrayRef< Register > SrcParts, const ShiftParams &Params, LLT TargetTy, LLT ShiftAmtTy)
Generates a single output part for constant shifts using direct indexing.
LLVM_ABI void narrowScalarSrc(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by truncating the operand's ty...
LLVM_ABI LegalizeResult fewerElementsVectorPhi(GenericMachineInstr &MI, unsigned NumElts)
LLVM_ABI LegalizeResult lowerFPTOUI(MachineInstr &MI)
const TargetLowering & getTargetLowering() const
LLVM_ABI LegalizeResult narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize an instruction by reducing the width of the underlying scalar type.
LLVM_ABI LegalizeResult narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult bitcastInsertSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
LLVM_ABI LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer, MachineIRBuilder &B, const LibcallLoweringInfo *Libcalls=nullptr)
LLVM_ABI LegalizeResult lowerUnmergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcast(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by replacing the value type.
LLVM_ABI LegalizeResult scalarizeVectorBooleanStore(GStore &MI)
Given a store of a boolean vector, scalarize it.
LLVM_ABI LegalizeResult lowerBitcast(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerInsert(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerReadWriteRegister(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerExtract(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsBitcast(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt, LLT HalfTy, LLT ShiftAmtTy)
LLVM_ABI LegalizeResult lowerISFPCLASS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPOWI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPExtAndTruncMem(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFAbs(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerVectorReduction(MachineInstr &MI)
const LegalizerInfo & getLegalizerInfo() const
Expose LegalizerInfo so the clients can re-use.
LLVM_ABI LegalizeResult reduceLoadStoreWidth(GLoadStore &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult fewerElementsVectorMultiEltType(GenericMachineInstr &MI, unsigned NumElts, std::initializer_list< unsigned > NonVecOpIndices={})
Handles most opcodes.
LLVM_ABI LegalizeResult narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarShiftByConstantMultiway(MachineInstr &MI, const APInt &Amt, LLT TargetTy, LLT ShiftAmtTy)
Optimized path for constant shift amounts using static indexing.
LLVM_ABI void widenScalarSrcUsingFPExt(MachineInstr &MI, LLT WideTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI MachineInstrBuilder createStackStoreLoad(const DstOp &Res, const SrcOp &Val)
Create a store of Val to a stack temporary and return a load as the same type as Res.
LLVM_ABI LegalizeResult lowerVAArg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMODF(MachineInstr &MI)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
@ AlreadyLegal
Instruction was already legal and no change was made to the MachineFunction.
@ UnableToLegalize
Some kind of error has occurred and we could not legalize this instruction.
LLVM_ABI LegalizeResult moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
LLVM_ABI LegalizeResult lowerFCopySign(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastConcatVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerRotateWithReverseRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSADDE(MachineInstr &MI)
LLVM_ABI LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
LLVM_ABI LegalizeResult lowerFunnelShift(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize a vector instruction by splitting into multiple components, each acting on the same scalar t...
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
LLVM_ABI LegalizeResult conversionLibcall(MachineInstr &MI, Type *ToType, Type *FromType, LostDebugLocObserver &LocObserver, bool IsSigned=false) const
LLVM_ABI void bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a def by inserting a G_BITCAST from ...
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMad(MachineInstr &MI)
LLVM_ABI LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy)
Legalize an instruction by performing the operation on a wider scalar type (for example a 16-bit addi...
LLVM_ABI LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerFFloor(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExt(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult fewerElementsVectorSeqReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Register getDynStackAllocTargetPtr(Register SPReg, Register AllocSize, Align Alignment, LLT PtrTy)
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerUITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerShuffleVector(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerMergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult createMemLibcall(MachineRegisterInfo &MRI, MachineInstr &MI, LostDebugLocObserver &LocObserver) const
Create a libcall to memcpy et al.
LLVM_ABI LegalizeResult lowerVECTOR_COMPRESS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI)
LLVM_ABI void moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by producing a vector with und...
LLVM_ABI LegalizeResult bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_EXTRACT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF32WithSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult createLibcall(const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr) const
Helper function that creates a libcall to the given Name using the given calling convention CC.
LLVM_ABI LegalizeResult bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerDIVREM(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI Register buildVariableShiftPart(unsigned Opcode, Register MainOperand, Register ShiftAmt, LLT TargetTy, Register CarryOperand=Register())
Generates a shift part with carry for variable shifts.
LLVM_ABI void bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a use by inserting a G_BITCAST to Ca...
LLVM_ABI void narrowScalarDst(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx, unsigned ExtOpcode)
LLVM_ABI LegalizeResult libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Legalize an instruction by emiting a runtime library call instead.
LLVM_ABI LegalizeResult lowerStackRestore(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerTruncSat(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStackSave(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI void widenScalarDstUsingFPTrunc(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBswap(MachineInstr &MI)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
LLVM_ABI LegalizeResult narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LLVM_ABI Register coerceToInteger(Register Val)
Cast the given value to an LLT::integer with an equivalent size.
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LLVM_ABI LegalizeResult simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType, LostDebugLocObserver &LocObserver) const
LLVM_ABI LegalizeResult legalizeInstrStep(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Replace MI by a sequence of legal instructions that can implement the same operation.
LLVM_ABI LegalizeResult lowerFMinimumMaximum(MachineInstr &MI)
Tracks which library functions to use for a particular subtarget or function.
TypeSize getValue() const
void checkpoint(bool CheckDebugLocs=true)
Call this to indicate that it's a good point to assess whether locations have been lost.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:89
A single uniqued string.
Definition Metadata.h:733
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:613
static LLVM_ABI MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MachineInstrBundleIterator< MachineInstr > iterator
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
void setObjectAlignment(int ObjectIdx, Align Alignment)
setObjectAlignment - Change the alignment of the specified stack object.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)
Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_UITOFP Src0.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildFPTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FPTRUNC Op.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
void setType(LLT NewTy)
Reset the tracked memory type.
LLT getMemoryType() const
Return the memory type of the memory reference.
void clearRanges()
Unset the tracked range metadata.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const MachinePointerInfo & getPointerInfo() const
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
const ConstantInt * getCImm() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setCImm(const ConstantInt *CI)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:887
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLT getLLTTy(const MachineRegisterInfo &MRI) const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:467
TargetInstrInfo - Interface to description of machine instruction set.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:352
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
static LLVM_ABI Type * getFP128Ty(LLVMContext &C)
Definition Type.cpp:281
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:277
static LLVM_ABI Type * getX86_FP80Ty(LLVMContext &C)
Definition Type.cpp:280
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:274
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition TypeSize.h:181
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
Definition TypeSize.h:253
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ Libcall
The operation should be implemented as a call to some kind of runtime support library.
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
@ NarrowScalar
The operation should be synthesized from multiple instructions acting on a narrower scalar base-type.
@ MoreElements
The (vector) operation should be implemented by widening the input vector and ignoring the lanes adde...
ConstantMatch< APInt > m_ICst(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOUINT(EVT OpVT, EVT RetVT)
getFPTOUINT - Return the FPTOUINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPEXT(EVT OpVT, EVT RetVT)
getFPEXT - Return the FPEXT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
Definition Utils.cpp:1677
@ Offset
Definition DWP.cpp:577
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h:846
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition Utils.cpp:2138
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:679
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:301
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
constexpr int64_t minIntN(int64_t N)
Gets the minimum value for a N-bit signed integer.
Definition MathExtras.h:224
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, llvm::function_ref< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
Definition Utils.cpp:1732
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1167
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
LLVM_ABI LLVM_READNONE LLT getLCMType(LLT OrigTy, LLT TargetTy)
Return the least common multiple type of OrigTy and TargetTy, by changing the number of vector elemen...
Definition Utils.cpp:1300
unsigned M1(unsigned Val)
Definition VE.h:394
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
Definition MathExtras.h:352
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ Success
The lock was released successfully.
LLVM_ABI EVT getApproximateEVTForLLT(LLT Ty, LLVMContext &Ctx)
LLVM_ABI void extractParts(Register Reg, LLT Ty, int NumParts, SmallVectorImpl< Register > &VRegs, MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
Helper function to split a wide generic register into bitwise blocks with the given Type (which impli...
Definition Utils.cpp:534
LLVM_ABI bool canLowerMemCpyFamily(const MachineInstr &MI, const MachineRegisterInfo &MRI, unsigned MaxLen, Register &Dst, Register &Src, uint64_t &KnownLen, Align &Alignment, bool &DstAlignCanChange, std::vector< LLT > &MemOps)
Matcher for memcpy-like instructions.
Definition Utils.cpp:2305
To bit_cast(const From &from) noexcept
Definition bit.h:90
@ Mul
Product of integers.
@ FSub
Subtraction of floats.
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
IntPtrTy
Definition InstrProf.h:82
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1901
constexpr int64_t maxIntN(int64_t N)
Gets the maximum value for a N-bit signed integer.
Definition MathExtras.h:233
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:440
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
Definition Alignment.h:105
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:202
LLVM_ABI LLVM_READNONE LLT getGCDType(LLT OrigTy, LLT TargetTy)
Return a type where the total size is the greatest common divisor of OrigTy and TargetTy.
Definition Utils.cpp:1388
T bit_floor(T Value)
Returns the largest integral power of two no greater than Value if Value is nonzero.
Definition bit.h:347
@ Custom
The result value requires a custom uniformity check.
Definition Uniformity.h:31
LLVM_ABI void extractVectorParts(Register Reg, unsigned NumElts, SmallVectorImpl< Register > &VRegs, MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
Version which handles irregular sub-vector splits.
Definition Utils.cpp:637
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
SmallVector< ISD::ArgFlagsTy, 4 > Flags
CallingConv::ID CallConv
Calling convention to be used for the call.
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
Matching combinators.
This class contains a discriminated union of information about pointers in memory operands,...
static LLVM_ABI MachinePointerInfo getConstantPool(MachineFunction &MF)
Return a MachinePointerInfo record that refers to the constant pool.
MachinePointerInfo getWithOffset(int64_t O) const
static LLVM_ABI MachinePointerInfo getUnknownStack(MachineFunction &MF)
Stack memory without other information.
static LLVM_ABI MachinePointerInfo getFixedStack(MachineFunction &MF, int FI, int64_t Offset=0)
Return a MachinePointerInfo record that refers to the specified FrameIndex.
static StringRef getLibcallImplName(RTLIB::LibcallImpl CallImpl)
Get the libcall routine name for the specified libcall implementation.