LLVM 23.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/// Try to break down \p OrigTy into \p NarrowTy sized pieces.
51///
52/// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
53/// with any leftover piece as type \p LeftoverTy
54///
55/// Returns -1 in the first element of the pair if the breakdown is not
56/// satisfiable.
57static std::pair<int, int>
58getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
59 assert(!LeftoverTy.isValid() && "this is an out argument");
60
61 unsigned Size = OrigTy.getSizeInBits();
62 unsigned NarrowSize = NarrowTy.getSizeInBits();
63 unsigned NumParts = Size / NarrowSize;
64 unsigned LeftoverSize = Size - NumParts * NarrowSize;
65 assert(Size > NarrowSize);
66
67 if (LeftoverSize == 0)
68 return {NumParts, 0};
69
70 if (NarrowTy.isVector()) {
71 unsigned EltSize = OrigTy.getScalarSizeInBits();
72 if (LeftoverSize % EltSize != 0)
73 return {-1, -1};
74 LeftoverTy = OrigTy.changeElementCount(
75 ElementCount::getFixed(LeftoverSize / EltSize));
76 } else {
77 LeftoverTy = LLT::integer(LeftoverSize);
78 }
79
80 int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
81 return std::make_pair(NumParts, NumLeftover);
82}
83
85
86 if (!Ty.isScalar())
87 return nullptr;
88
89 switch (Ty.getSizeInBits()) {
90 case 16:
91 return Type::getHalfTy(Ctx);
92 case 32:
93 return Type::getFloatTy(Ctx);
94 case 64:
95 return Type::getDoubleTy(Ctx);
96 case 80:
97 return Type::getX86_FP80Ty(Ctx);
98 case 128:
99 return Type::getFP128Ty(Ctx);
100 default:
101 return nullptr;
102 }
103}
104
107 MachineIRBuilder &Builder,
108 const LibcallLoweringInfo *Libcalls)
109 : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
110 LI(*MF.getSubtarget().getLegalizerInfo()),
111 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls) {}
112
116 const LibcallLoweringInfo *Libcalls,
118 : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
119 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls), VT(VT) {}
120
123 LostDebugLocObserver &LocObserver) {
124 LLVM_DEBUG(dbgs() << "\nLegalizing: " << MI);
125
126 MIRBuilder.setInstrAndDebugLoc(MI);
127
128 if (isa<GIntrinsic>(MI))
129 return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
130 auto Step = LI.getAction(MI, MRI);
131 switch (Step.Action) {
132 case Legal:
133 LLVM_DEBUG(dbgs() << ".. Already legal\n");
134 return AlreadyLegal;
135 case Libcall:
136 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
137 return libcall(MI, LocObserver);
138 case NarrowScalar:
139 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
140 return narrowScalar(MI, Step.TypeIdx, Step.NewType);
141 case WidenScalar:
142 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
143 return widenScalar(MI, Step.TypeIdx, Step.NewType);
144 case Bitcast:
145 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
146 return bitcast(MI, Step.TypeIdx, Step.NewType);
147 case Lower:
148 LLVM_DEBUG(dbgs() << ".. Lower\n");
149 return lower(MI, Step.TypeIdx, Step.NewType);
150 case FewerElements:
151 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
152 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
153 case MoreElements:
154 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
155 return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
156 case Custom:
157 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
158 return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
160 default:
161 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
162 return UnableToLegalize;
163 }
164}
165
166void LegalizerHelper::insertParts(Register DstReg,
167 LLT ResultTy, LLT PartTy,
168 ArrayRef<Register> PartRegs,
169 LLT LeftoverTy,
170 ArrayRef<Register> LeftoverRegs) {
171 if (!LeftoverTy.isValid()) {
172 assert(LeftoverRegs.empty());
173
174 if (!ResultTy.isVector()) {
175 MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
176 return;
177 }
178
179 if (PartTy.isVector())
180 MIRBuilder.buildConcatVectors(DstReg, PartRegs);
181 else
182 MIRBuilder.buildBuildVector(DstReg, PartRegs);
183 return;
184 }
185
186 // Merge sub-vectors with different number of elements and insert into DstReg.
187 if (ResultTy.isVector()) {
188 assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
189 SmallVector<Register, 8> AllRegs(PartRegs);
190 AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());
191 return mergeMixedSubvectors(DstReg, AllRegs);
192 }
193
194 SmallVector<Register> GCDRegs;
195 LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
196 for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
197 extractGCDType(GCDRegs, GCDTy, PartReg);
198 LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
199 buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
200}
201
202void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
203 Register Reg) {
204 LLT Ty = MRI.getType(Reg);
206 extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
207 MIRBuilder, MRI);
208 Elts.append(RegElts);
209}
210
211/// Merge \p PartRegs with different types into \p DstReg.
212void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
213 ArrayRef<Register> PartRegs) {
215 for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
216 appendVectorElts(AllElts, PartRegs[i]);
217
218 Register Leftover = PartRegs[PartRegs.size() - 1];
219 if (!MRI.getType(Leftover).isVector())
220 AllElts.push_back(Leftover);
221 else
222 appendVectorElts(AllElts, Leftover);
223
224 MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
225}
226
227/// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
229 const MachineInstr &MI) {
230 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
231
232 const int StartIdx = Regs.size();
233 const int NumResults = MI.getNumOperands() - 1;
234 Regs.resize(Regs.size() + NumResults);
235 for (int I = 0; I != NumResults; ++I)
236 Regs[StartIdx + I] = MI.getOperand(I).getReg();
237}
238
239void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
240 LLT GCDTy, Register SrcReg) {
241 LLT SrcTy = MRI.getType(SrcReg);
242 if (SrcTy == GCDTy) {
243 // If the source already evenly divides the result type, we don't need to do
244 // anything.
245 Parts.push_back(SrcReg);
246 } else {
247 // Need to split into common type sized pieces.
248 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
249 getUnmergeResults(Parts, *Unmerge);
250 }
251}
252
253LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
254 LLT NarrowTy, Register SrcReg) {
255 LLT SrcTy = MRI.getType(SrcReg);
256 LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
257 extractGCDType(Parts, GCDTy, SrcReg);
258 return GCDTy;
259}
260
261LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
263 unsigned PadStrategy) {
264 LLT LCMTy = getLCMType(DstTy, NarrowTy);
265
266 int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
267 int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
268 int NumOrigSrc = VRegs.size();
269
270 Register PadReg;
271
272 // Get a value we can use to pad the source value if the sources won't evenly
273 // cover the result type.
274 if (NumOrigSrc < NumParts * NumSubParts) {
275 if (PadStrategy == TargetOpcode::G_ZEXT)
276 PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
277 else if (PadStrategy == TargetOpcode::G_ANYEXT)
278 PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
279 else {
280 assert(PadStrategy == TargetOpcode::G_SEXT);
281
282 // Shift the sign bit of the low register through the high register.
283 auto ShiftAmt =
284 MIRBuilder.buildConstant(LLT::integer(64), GCDTy.getSizeInBits() - 1);
285 PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
286 }
287 }
288
289 // Registers for the final merge to be produced.
290 SmallVector<Register, 4> Remerge(NumParts);
291
292 // Registers needed for intermediate merges, which will be merged into a
293 // source for Remerge.
294 SmallVector<Register, 4> SubMerge(NumSubParts);
295
296 // Once we've fully read off the end of the original source bits, we can reuse
297 // the same high bits for remaining padding elements.
298 Register AllPadReg;
299
300 // Build merges to the LCM type to cover the original result type.
301 for (int I = 0; I != NumParts; ++I) {
302 bool AllMergePartsArePadding = true;
303
304 // Build the requested merges to the requested type.
305 for (int J = 0; J != NumSubParts; ++J) {
306 int Idx = I * NumSubParts + J;
307 if (Idx >= NumOrigSrc) {
308 SubMerge[J] = PadReg;
309 continue;
310 }
311
312 SubMerge[J] = VRegs[Idx];
313
314 // There are meaningful bits here we can't reuse later.
315 AllMergePartsArePadding = false;
316 }
317
318 // If we've filled up a complete piece with padding bits, we can directly
319 // emit the natural sized constant if applicable, rather than a merge of
320 // smaller constants.
321 if (AllMergePartsArePadding && !AllPadReg) {
322 if (PadStrategy == TargetOpcode::G_ANYEXT)
323 AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
324 else if (PadStrategy == TargetOpcode::G_ZEXT)
325 AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
326
327 // If this is a sign extension, we can't materialize a trivial constant
328 // with the right type and have to produce a merge.
329 }
330
331 if (AllPadReg) {
332 // Avoid creating additional instructions if we're just adding additional
333 // copies of padding bits.
334 Remerge[I] = AllPadReg;
335 continue;
336 }
337
338 if (NumSubParts == 1)
339 Remerge[I] = SubMerge[0];
340 else
341 Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
342
343 // In the sign extend padding case, re-use the first all-signbit merge.
344 if (AllMergePartsArePadding && !AllPadReg)
345 AllPadReg = Remerge[I];
346 }
347
348 VRegs = std::move(Remerge);
349 return LCMTy;
350}
351
352void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
353 ArrayRef<Register> RemergeRegs) {
354 LLT DstTy = MRI.getType(DstReg);
355
356 // Create the merge to the widened source, and extract the relevant bits into
357 // the result.
358
359 if (DstTy == LCMTy) {
360 MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
361 return;
362 }
363
364 auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
365 if (DstTy.isScalar() && LCMTy.isScalar()) {
366 MIRBuilder.buildTrunc(DstReg, Remerge);
367 return;
368 }
369
370 if (LCMTy.isVector()) {
371 unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
372 SmallVector<Register, 8> UnmergeDefs(NumDefs);
373 UnmergeDefs[0] = DstReg;
374 for (unsigned I = 1; I != NumDefs; ++I)
375 UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
376
377 MIRBuilder.buildUnmerge(UnmergeDefs,
378 MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
379 return;
380 }
381
382 llvm_unreachable("unhandled case");
383}
384
385static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
386#define RTLIBCASE_INT(LibcallPrefix) \
387 do { \
388 switch (Size) { \
389 case 32: \
390 return RTLIB::LibcallPrefix##32; \
391 case 64: \
392 return RTLIB::LibcallPrefix##64; \
393 case 128: \
394 return RTLIB::LibcallPrefix##128; \
395 default: \
396 llvm_unreachable("unexpected size"); \
397 } \
398 } while (0)
399
400#define RTLIBCASE(LibcallPrefix) \
401 do { \
402 switch (Size) { \
403 case 32: \
404 return RTLIB::LibcallPrefix##32; \
405 case 64: \
406 return RTLIB::LibcallPrefix##64; \
407 case 80: \
408 return RTLIB::LibcallPrefix##80; \
409 case 128: \
410 return RTLIB::LibcallPrefix##128; \
411 default: \
412 llvm_unreachable("unexpected size"); \
413 } \
414 } while (0)
415
416 switch (Opcode) {
417 case TargetOpcode::G_LROUND:
418 RTLIBCASE(LROUND_F);
419 case TargetOpcode::G_LLROUND:
420 RTLIBCASE(LLROUND_F);
421 case TargetOpcode::G_MUL:
422 RTLIBCASE_INT(MUL_I);
423 case TargetOpcode::G_SDIV:
424 RTLIBCASE_INT(SDIV_I);
425 case TargetOpcode::G_UDIV:
426 RTLIBCASE_INT(UDIV_I);
427 case TargetOpcode::G_SREM:
428 RTLIBCASE_INT(SREM_I);
429 case TargetOpcode::G_UREM:
430 RTLIBCASE_INT(UREM_I);
431 case TargetOpcode::G_CTLZ_ZERO_POISON:
432 RTLIBCASE_INT(CTLZ_I);
433 case TargetOpcode::G_FADD:
434 RTLIBCASE(ADD_F);
435 case TargetOpcode::G_FSUB:
436 RTLIBCASE(SUB_F);
437 case TargetOpcode::G_FMUL:
438 RTLIBCASE(MUL_F);
439 case TargetOpcode::G_FDIV:
440 RTLIBCASE(DIV_F);
441 case TargetOpcode::G_FEXP:
442 RTLIBCASE(EXP_F);
443 case TargetOpcode::G_FEXP2:
444 RTLIBCASE(EXP2_F);
445 case TargetOpcode::G_FEXP10:
446 RTLIBCASE(EXP10_F);
447 case TargetOpcode::G_FREM:
448 RTLIBCASE(REM_F);
449 case TargetOpcode::G_FPOW:
450 RTLIBCASE(POW_F);
451 case TargetOpcode::G_FPOWI:
452 RTLIBCASE(POWI_F);
453 case TargetOpcode::G_FMA:
454 RTLIBCASE(FMA_F);
455 case TargetOpcode::G_FSIN:
456 RTLIBCASE(SIN_F);
457 case TargetOpcode::G_FCOS:
458 RTLIBCASE(COS_F);
459 case TargetOpcode::G_FTAN:
460 RTLIBCASE(TAN_F);
461 case TargetOpcode::G_FASIN:
462 RTLIBCASE(ASIN_F);
463 case TargetOpcode::G_FACOS:
464 RTLIBCASE(ACOS_F);
465 case TargetOpcode::G_FATAN:
466 RTLIBCASE(ATAN_F);
467 case TargetOpcode::G_FATAN2:
468 RTLIBCASE(ATAN2_F);
469 case TargetOpcode::G_FSINH:
470 RTLIBCASE(SINH_F);
471 case TargetOpcode::G_FCOSH:
472 RTLIBCASE(COSH_F);
473 case TargetOpcode::G_FTANH:
474 RTLIBCASE(TANH_F);
475 case TargetOpcode::G_FSINCOS:
476 RTLIBCASE(SINCOS_F);
477 case TargetOpcode::G_FMODF:
478 RTLIBCASE(MODF_F);
479 case TargetOpcode::G_FLOG10:
480 RTLIBCASE(LOG10_F);
481 case TargetOpcode::G_FLOG:
482 RTLIBCASE(LOG_F);
483 case TargetOpcode::G_FLOG2:
484 RTLIBCASE(LOG2_F);
485 case TargetOpcode::G_FLDEXP:
486 RTLIBCASE(LDEXP_F);
487 case TargetOpcode::G_FCEIL:
488 RTLIBCASE(CEIL_F);
489 case TargetOpcode::G_FFLOOR:
490 RTLIBCASE(FLOOR_F);
491 case TargetOpcode::G_FMINNUM:
492 RTLIBCASE(FMIN_F);
493 case TargetOpcode::G_FMAXNUM:
494 RTLIBCASE(FMAX_F);
495 case TargetOpcode::G_FMINIMUMNUM:
496 RTLIBCASE(FMINIMUM_NUM_F);
497 case TargetOpcode::G_FMAXIMUMNUM:
498 RTLIBCASE(FMAXIMUM_NUM_F);
499 case TargetOpcode::G_FSQRT:
500 RTLIBCASE(SQRT_F);
501 case TargetOpcode::G_FRINT:
502 RTLIBCASE(RINT_F);
503 case TargetOpcode::G_FNEARBYINT:
504 RTLIBCASE(NEARBYINT_F);
505 case TargetOpcode::G_INTRINSIC_TRUNC:
506 RTLIBCASE(TRUNC_F);
507 case TargetOpcode::G_INTRINSIC_ROUND:
508 RTLIBCASE(ROUND_F);
509 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
510 RTLIBCASE(ROUNDEVEN_F);
511 case TargetOpcode::G_INTRINSIC_LRINT:
512 RTLIBCASE(LRINT_F);
513 case TargetOpcode::G_INTRINSIC_LLRINT:
514 RTLIBCASE(LLRINT_F);
515 }
516 llvm_unreachable("Unknown libcall function");
517#undef RTLIBCASE_INT
518#undef RTLIBCASE
519}
520
521/// True if an instruction is in tail position in its caller. Intended for
522/// legalizing libcalls as tail calls when possible.
525 const TargetInstrInfo &TII,
526 MachineRegisterInfo &MRI) {
527 MachineBasicBlock &MBB = *MI.getParent();
528 const Function &F = MBB.getParent()->getFunction();
529
530 // Conservatively require the attributes of the call to match those of
531 // the return. Ignore NoAlias and NonNull because they don't affect the
532 // call sequence.
533 AttributeList CallerAttrs = F.getAttributes();
534 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
535 .removeAttribute(Attribute::NoAlias)
536 .removeAttribute(Attribute::NonNull)
537 .hasAttributes())
538 return false;
539
540 // It's not safe to eliminate the sign / zero extension of the return value.
541 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
542 CallerAttrs.hasRetAttr(Attribute::SExt))
543 return false;
544
545 // Only tail call if the following instruction is a standard return or if we
546 // have a `thisreturn` callee, and a sequence like:
547 //
548 // G_MEMCPY %0, %1, %2
549 // $x0 = COPY %0
550 // RET_ReallyLR implicit $x0
551 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
552 if (Next != MBB.instr_end() && Next->isCopy()) {
553 if (MI.getOpcode() == TargetOpcode::G_BZERO)
554 return false;
555
556 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
557 // mempy/etc routines return the same parameter. For other it will be the
558 // returned value.
559 Register VReg = MI.getOperand(0).getReg();
560 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
561 return false;
562
563 Register PReg = Next->getOperand(0).getReg();
564 if (!PReg.isPhysical())
565 return false;
566
567 auto Ret = next_nodbg(Next, MBB.instr_end());
568 if (Ret == MBB.instr_end() || !Ret->isReturn())
569 return false;
570
571 if (Ret->getNumImplicitOperands() != 1)
572 return false;
573
574 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
575 return false;
576
577 // Skip over the COPY that we just validated.
578 Next = Ret;
579 }
580
581 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
582 return false;
583
584 return true;
585}
586
588 const char *Name, const CallLowering::ArgInfo &Result,
590 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
591 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
592
594 Info.CallConv = CC;
595 Info.Callee = MachineOperand::CreateES(Name);
596 Info.OrigRet = Result;
597 if (MI)
598 Info.IsTailCall =
599 (Result.Ty->isVoidTy() ||
600 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
601 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
602 *MIRBuilder.getMRI());
603
604 llvm::append_range(Info.OrigArgs, Args);
605 if (!CLI.lowerCall(MIRBuilder, Info))
607
608 if (MI && Info.LoweredTailCall) {
609 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
610
611 // Check debug locations before removing the return.
612 LocObserver.checkpoint(true);
613
614 // We must have a return following the call (or debug insts) to get past
615 // isLibCallInTailPosition.
616 do {
617 MachineInstr *Next = MI->getNextNode();
618 assert(Next &&
619 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
620 "Expected instr following MI to be return or debug inst?");
621 // We lowered a tail call, so the call is now the return from the block.
622 // Delete the old return.
623 Next->eraseFromParent();
624 } while (MI->getNextNode());
625
626 // We expect to lose the debug location from the return.
627 LocObserver.checkpoint(false);
628 }
630}
631
633 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
635 MachineInstr *MI) const {
636 if (!Libcalls)
638
639 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
640 if (LibcallImpl == RTLIB::Unsupported)
642
644 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
645 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
646}
647
648// Useful for libcalls where all operands have the same type.
651 unsigned Size, Type *OpType,
652 LostDebugLocObserver &LocObserver) const {
653 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
654
655 // FIXME: What does the original arg index mean here?
657 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
658 Args.push_back({MO.getReg(), OpType, 0});
659 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
660 LocObserver, &MI);
661}
662
663LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
664 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
665 LostDebugLocObserver &LocObserver) {
666 MachineFunction &MF = *MI.getMF();
668
669 Register DstSin = MI.getOperand(0).getReg();
670 Register DstCos = MI.getOperand(1).getReg();
671 Register Src = MI.getOperand(2).getReg();
672 LLT DstTy = MRI.getType(DstSin);
673
674 int MemSize = DstTy.getSizeInBytes();
675 Align Alignment = getStackTemporaryAlignment(DstTy);
677 unsigned AddrSpace = DL.getAllocaAddrSpace();
678 MachinePointerInfo PtrInfo;
679
680 Register StackPtrSin =
681 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
682 .getReg(0);
683 Register StackPtrCos =
684 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
685 .getReg(0);
686
687 auto &Ctx = MF.getFunction().getContext();
688 auto LibcallResult = createLibcall(
689 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
690 {{Src, OpType, 0},
691 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
692 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
693 LocObserver, &MI);
694
695 if (LibcallResult != LegalizeResult::Legalized)
697
699 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
701 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
702
703 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
704 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
705 MI.eraseFromParent();
706
708}
709
711LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
712 unsigned Size, Type *OpType,
713 LostDebugLocObserver &LocObserver) {
714 MachineFunction &MF = MIRBuilder.getMF();
715 MachineRegisterInfo &MRI = MF.getRegInfo();
716
717 Register DstFrac = MI.getOperand(0).getReg();
718 Register DstInt = MI.getOperand(1).getReg();
719 Register Src = MI.getOperand(2).getReg();
720 LLT DstTy = MRI.getType(DstFrac);
721
722 int MemSize = DstTy.getSizeInBytes();
723 Align Alignment = getStackTemporaryAlignment(DstTy);
724 const DataLayout &DL = MIRBuilder.getDataLayout();
725 unsigned AddrSpace = DL.getAllocaAddrSpace();
726 MachinePointerInfo PtrInfo;
727
728 Register StackPtrInt =
729 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
730 .getReg(0);
731
732 auto &Ctx = MF.getFunction().getContext();
733 auto LibcallResult = createLibcall(
734 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
735 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
736 LocObserver, &MI);
737
738 if (LibcallResult != LegalizeResult::Legalized)
740
742 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
743
744 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
745 MI.eraseFromParent();
746
748}
749
750static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
751 Type *FromType) {
752 auto ToMVT = MVT::getVT(ToType);
753 auto FromMVT = MVT::getVT(FromType);
754
755 switch (Opcode) {
756 case TargetOpcode::G_FPEXT:
757 return RTLIB::getFPEXT(FromMVT, ToMVT);
758 case TargetOpcode::G_FPTRUNC:
759 return RTLIB::getFPROUND(FromMVT, ToMVT);
760 case TargetOpcode::G_FPTOSI:
761 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
762 case TargetOpcode::G_FPTOUI:
763 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
764 case TargetOpcode::G_SITOFP:
765 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
766 case TargetOpcode::G_UITOFP:
767 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
768 }
769 llvm_unreachable("Unsupported libcall function");
770}
771
773 MachineInstr &MI, Type *ToType, Type *FromType,
774 LostDebugLocObserver &LocObserver, bool IsSigned) const {
775 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
776 if (FromType->isIntegerTy()) {
777 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
778 Arg.Flags[0].setSExt();
779 else
780 Arg.Flags[0].setZExt();
781 }
782
783 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
784 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
785 LocObserver, &MI);
786}
787
790 LostDebugLocObserver &LocObserver) const {
791 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
792
794 // Add all the args, except for the last which is an imm denoting 'tail'.
795 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
796 Register Reg = MI.getOperand(i).getReg();
797
798 // Need derive an IR type for call lowering.
799 LLT OpLLT = MRI.getType(Reg);
800 Type *OpTy = nullptr;
801 if (OpLLT.isPointer())
802 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
803 else
804 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
805 Args.push_back({Reg, OpTy, 0});
806 }
807
808 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
809 RTLIB::Libcall RTLibcall;
810 unsigned Opc = MI.getOpcode();
811 switch (Opc) {
812 case TargetOpcode::G_BZERO:
813 RTLibcall = RTLIB::BZERO;
814 break;
815 case TargetOpcode::G_MEMCPY:
816 RTLibcall = RTLIB::MEMCPY;
817 Args[0].Flags[0].setReturned();
818 break;
819 case TargetOpcode::G_MEMMOVE:
820 RTLibcall = RTLIB::MEMMOVE;
821 Args[0].Flags[0].setReturned();
822 break;
823 case TargetOpcode::G_MEMSET:
824 RTLibcall = RTLIB::MEMSET;
825 Args[0].Flags[0].setReturned();
826 break;
827 default:
828 llvm_unreachable("unsupported opcode");
829 }
830
831 if (!Libcalls) // FIXME: Should be mandatory
833
834 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
835
836 // Unsupported libcall on the target.
837 if (RTLibcallImpl == RTLIB::Unsupported) {
838 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
839 << MIRBuilder.getTII().getName(Opc) << "\n");
841 }
842
844 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
845
846 StringRef LibcallName =
848 Info.Callee = MachineOperand::CreateES(LibcallName.data());
849 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
850 Info.IsTailCall =
851 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
852 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI);
853
854 llvm::append_range(Info.OrigArgs, Args);
855 if (!CLI.lowerCall(MIRBuilder, Info))
857
858 if (Info.LoweredTailCall) {
859 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
860
861 // Check debug locations before removing the return.
862 LocObserver.checkpoint(true);
863
864 // We must have a return following the call (or debug insts) to get past
865 // isLibCallInTailPosition.
866 do {
867 MachineInstr *Next = MI.getNextNode();
868 assert(Next &&
869 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
870 "Expected instr following MI to be return or debug inst?");
871 // We lowered a tail call, so the call is now the return from the block.
872 // Delete the old return.
873 Next->eraseFromParent();
874 } while (MI.getNextNode());
875
876 // We expect to lose the debug location from the return.
877 LocObserver.checkpoint(false);
878 }
879
881}
882
883static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
884 unsigned Opc = MI.getOpcode();
885 auto &AtomicMI = cast<GMemOperation>(MI);
886 auto &MMO = AtomicMI.getMMO();
887 auto Ordering = MMO.getMergedOrdering();
888 LLT MemType = MMO.getMemoryType();
889 uint64_t MemSize = MemType.getSizeInBytes();
890 if (MemType.isVector())
891 return RTLIB::UNKNOWN_LIBCALL;
892
893#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
894#define LCALL5(A) \
895 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
896 switch (Opc) {
897 case TargetOpcode::G_ATOMIC_CMPXCHG:
898 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
899 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
900 return getOutlineAtomicHelper(LC, Ordering, MemSize);
901 }
902 case TargetOpcode::G_ATOMICRMW_XCHG: {
903 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
904 return getOutlineAtomicHelper(LC, Ordering, MemSize);
905 }
906 case TargetOpcode::G_ATOMICRMW_ADD:
907 case TargetOpcode::G_ATOMICRMW_SUB: {
908 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
909 return getOutlineAtomicHelper(LC, Ordering, MemSize);
910 }
911 case TargetOpcode::G_ATOMICRMW_AND: {
912 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
913 return getOutlineAtomicHelper(LC, Ordering, MemSize);
914 }
915 case TargetOpcode::G_ATOMICRMW_OR: {
916 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
917 return getOutlineAtomicHelper(LC, Ordering, MemSize);
918 }
919 case TargetOpcode::G_ATOMICRMW_XOR: {
920 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
921 return getOutlineAtomicHelper(LC, Ordering, MemSize);
922 }
923 default:
924 return RTLIB::UNKNOWN_LIBCALL;
925 }
926#undef LCALLS
927#undef LCALL5
928}
929
932 auto &Ctx = MIRBuilder.getContext();
933
934 Type *RetTy;
935 SmallVector<Register> RetRegs;
937 unsigned Opc = MI.getOpcode();
938 switch (Opc) {
939 case TargetOpcode::G_ATOMIC_CMPXCHG:
940 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
942 LLT SuccessLLT;
943 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
944 MI.getFirst4RegLLTs();
945 RetRegs.push_back(Ret);
946 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
947 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
948 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
949 NewLLT) = MI.getFirst5RegLLTs();
950 RetRegs.push_back(Success);
951 RetTy = StructType::get(
952 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
953 }
954 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
955 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
956 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
957 break;
958 }
959 case TargetOpcode::G_ATOMICRMW_XCHG:
960 case TargetOpcode::G_ATOMICRMW_ADD:
961 case TargetOpcode::G_ATOMICRMW_SUB:
962 case TargetOpcode::G_ATOMICRMW_AND:
963 case TargetOpcode::G_ATOMICRMW_OR:
964 case TargetOpcode::G_ATOMICRMW_XOR: {
965 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
966 RetRegs.push_back(Ret);
967 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
968 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
969 Val =
970 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
971 .getReg(0);
972 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
973 Val =
974 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
975 .getReg(0);
976 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
977 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
978 break;
979 }
980 default:
981 llvm_unreachable("unsupported opcode");
982 }
983
984 if (!Libcalls) // FIXME: Should be mandatory
986
987 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
988 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
989 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
990
991 // Unsupported libcall on the target.
992 if (RTLibcallImpl == RTLIB::Unsupported) {
993 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
994 << MIRBuilder.getTII().getName(Opc) << "\n");
996 }
997
999 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1000
1001 StringRef LibcallName =
1003 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1004 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1005
1006 llvm::append_range(Info.OrigArgs, Args);
1007 if (!CLI.lowerCall(MIRBuilder, Info))
1009
1011}
1012
1013static RTLIB::Libcall
1015 RTLIB::Libcall RTLibcall;
1016 switch (MI.getOpcode()) {
1017 case TargetOpcode::G_GET_FPENV:
1018 RTLibcall = RTLIB::FEGETENV;
1019 break;
1020 case TargetOpcode::G_SET_FPENV:
1021 case TargetOpcode::G_RESET_FPENV:
1022 RTLibcall = RTLIB::FESETENV;
1023 break;
1024 case TargetOpcode::G_GET_FPMODE:
1025 RTLibcall = RTLIB::FEGETMODE;
1026 break;
1027 case TargetOpcode::G_SET_FPMODE:
1028 case TargetOpcode::G_RESET_FPMODE:
1029 RTLibcall = RTLIB::FESETMODE;
1030 break;
1031 default:
1032 llvm_unreachable("Unexpected opcode");
1033 }
1034 return RTLibcall;
1035}
1036
1037// Some library functions that read FP state (fegetmode, fegetenv) write the
1038// state into a region in memory. IR intrinsics that do the same operations
1039// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1040// intrinsics via the library functions, we need to use temporary variable,
1041// for example:
1042//
1043// %0:_(s32) = G_GET_FPMODE
1044//
1045// is transformed to:
1046//
1047// %1:_(p0) = G_FRAME_INDEX %stack.0
1048// BL &fegetmode
1049// %0:_(s32) = G_LOAD % 1
1050//
1052LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1053 LostDebugLocObserver &LocObserver) {
1054 const DataLayout &DL = MIRBuilder.getDataLayout();
1055 auto &MF = MIRBuilder.getMF();
1056 auto &MRI = *MIRBuilder.getMRI();
1057 auto &Ctx = MF.getFunction().getContext();
1058
1059 // Create temporary, where library function will put the read state.
1060 Register Dst = MI.getOperand(0).getReg();
1061 LLT StateTy = MRI.getType(Dst);
1062 TypeSize StateSize = StateTy.getSizeInBytes();
1063 Align TempAlign = getStackTemporaryAlignment(StateTy);
1064 MachinePointerInfo TempPtrInfo;
1065 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1066
1067 // Create a call to library function, with the temporary as an argument.
1068 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1069 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1070 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1071 auto Res = createLibcall(
1072 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1073 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1074 nullptr);
1075 if (Res != LegalizerHelper::Legalized)
1076 return Res;
1077
1078 // Create a load from the temporary.
1079 MachineMemOperand *MMO = MF.getMachineMemOperand(
1080 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1081 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1082
1084}
1085
1086// Similar to `createGetStateLibcall` the function calls a library function
1087// using transient space in stack. In this case the library function reads
1088// content of memory region.
1090LegalizerHelper::createSetStateLibcall(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 get the new state.
1098 Register Src = MI.getOperand(0).getReg();
1099 LLT StateTy = MRI.getType(Src);
1100 TypeSize StateSize = StateTy.getSizeInBytes();
1101 Align TempAlign = getStackTemporaryAlignment(StateTy);
1102 MachinePointerInfo TempPtrInfo;
1103 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1104
1105 // Put the new state into the temporary.
1106 MachineMemOperand *MMO = MF.getMachineMemOperand(
1107 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1108 MIRBuilder.buildStore(Src, Temp, *MMO);
1109
1110 // Create a call to library function, with the temporary as an argument.
1111 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1112 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1113 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1114 return createLibcall(RTLibcall,
1115 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1116 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1117 LocObserver, nullptr);
1118}
1119
1120/// Returns the corresponding libcall for the given Pred and
1121/// the ICMP predicate that should be generated to compare with #0
1122/// after the libcall.
1123static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1125#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1126 do { \
1127 switch (Size) { \
1128 case 32: \
1129 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1130 case 64: \
1131 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1132 case 128: \
1133 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1134 default: \
1135 llvm_unreachable("unexpected size"); \
1136 } \
1137 } while (0)
1138
1139 switch (Pred) {
1140 case CmpInst::FCMP_OEQ:
1142 case CmpInst::FCMP_UNE:
1144 case CmpInst::FCMP_OGE:
1146 case CmpInst::FCMP_OLT:
1148 case CmpInst::FCMP_OLE:
1150 case CmpInst::FCMP_OGT:
1152 case CmpInst::FCMP_UNO:
1154 default:
1155 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1156 }
1157}
1158
1160LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1161 LostDebugLocObserver &LocObserver) {
1162 auto &MF = MIRBuilder.getMF();
1163 auto &Ctx = MF.getFunction().getContext();
1164 const GFCmp *Cmp = cast<GFCmp>(&MI);
1165
1166 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1167 unsigned Size = OpLLT.getSizeInBits();
1168 if ((Size != 32 && Size != 64 && Size != 128) ||
1169 OpLLT != MRI.getType(Cmp->getRHSReg()))
1170 return UnableToLegalize;
1171
1172 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1173
1174 // DstReg type is s32
1175 const Register DstReg = Cmp->getReg(0);
1176 LLT DstTy = MRI.getType(DstReg);
1177 const auto Cond = Cmp->getCond();
1178
1179 // Reference:
1180 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1181 // Generates a libcall followed by ICMP.
1182 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1183 const CmpInst::Predicate ICmpPred,
1184 const DstOp &Res) -> Register {
1185 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1186 LLT TempLLT = LLT::integer(32);
1187 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1188 // Generate libcall, holding result in Temp
1189 const auto Status = createLibcall(
1190 Libcall, {Temp, Type::getInt32Ty(Ctx), 0},
1191 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1192 LocObserver, &MI);
1193 if (!Status)
1194 return {};
1195
1196 // Compare temp with #0 to get the final result.
1197 return MIRBuilder
1198 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1199 .getReg(0);
1200 };
1201
1202 // Simple case if we have a direct mapping from predicate to libcall
1203 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1204 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1205 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1206 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1207 return Legalized;
1208 }
1209 return UnableToLegalize;
1210 }
1211
1212 // No direct mapping found, should be generated as combination of libcalls.
1213
1214 switch (Cond) {
1215 case CmpInst::FCMP_UEQ: {
1216 // FCMP_UEQ: unordered or equal
1217 // Convert into (FCMP_OEQ || FCMP_UNO).
1218
1219 const auto [OeqLibcall, OeqPred] =
1221 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1222
1223 const auto [UnoLibcall, UnoPred] =
1225 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1226 if (Oeq && Uno)
1227 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1228 else
1229 return UnableToLegalize;
1230
1231 break;
1232 }
1233 case CmpInst::FCMP_ONE: {
1234 // FCMP_ONE: ordered and operands are unequal
1235 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1236
1237 // We inverse the predicate instead of generating a NOT
1238 // to save one instruction.
1239 // On AArch64 isel can even select two cmp into a single ccmp.
1240 const auto [OeqLibcall, OeqPred] =
1242 const auto NotOeq =
1243 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1244
1245 const auto [UnoLibcall, UnoPred] =
1247 const auto NotUno =
1248 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1249
1250 if (NotOeq && NotUno)
1251 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1252 else
1253 return UnableToLegalize;
1254
1255 break;
1256 }
1257 case CmpInst::FCMP_ULT:
1258 case CmpInst::FCMP_UGE:
1259 case CmpInst::FCMP_UGT:
1260 case CmpInst::FCMP_ULE:
1261 case CmpInst::FCMP_ORD: {
1262 // Convert into: !(inverse(Pred))
1263 // E.g. FCMP_ULT becomes !FCMP_OGE
1264 // This is equivalent to the following, but saves some instructions.
1265 // MIRBuilder.buildNot(
1266 // PredTy,
1267 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1268 // Op1, Op2));
1269 const auto [InversedLibcall, InversedPred] =
1271 if (!BuildLibcall(InversedLibcall,
1272 CmpInst::getInversePredicate(InversedPred), DstReg))
1273 return UnableToLegalize;
1274 break;
1275 }
1276 default:
1277 return UnableToLegalize;
1278 }
1279
1280 return Legalized;
1281}
1282
1283// The function is used to legalize operations that set default environment
1284// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1285// On most targets supported in glibc FE_DFL_MODE is defined as
1286// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1287// it is not true, the target must provide custom lowering.
1289LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1290 LostDebugLocObserver &LocObserver) {
1291 const DataLayout &DL = MIRBuilder.getDataLayout();
1292 auto &MF = MIRBuilder.getMF();
1293 auto &Ctx = MF.getFunction().getContext();
1294
1295 // Create an argument for the library function.
1296 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1297 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1298 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1299 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1300 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1301 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1302 MIRBuilder.buildIntToPtr(Dest, DefValue);
1303
1304 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1305 return createLibcall(
1306 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1307 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1308}
1309
1312 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1313
1314 switch (MI.getOpcode()) {
1315 default:
1316 return UnableToLegalize;
1317 case TargetOpcode::G_MUL:
1318 case TargetOpcode::G_SDIV:
1319 case TargetOpcode::G_UDIV:
1320 case TargetOpcode::G_SREM:
1321 case TargetOpcode::G_UREM:
1322 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1323 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1324 unsigned Size = LLTy.getSizeInBits();
1325 Type *HLTy = IntegerType::get(Ctx, Size);
1326 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1327 if (Status != Legalized)
1328 return Status;
1329 break;
1330 }
1331 case TargetOpcode::G_FADD:
1332 case TargetOpcode::G_FSUB:
1333 case TargetOpcode::G_FMUL:
1334 case TargetOpcode::G_FDIV:
1335 case TargetOpcode::G_FMA:
1336 case TargetOpcode::G_FPOW:
1337 case TargetOpcode::G_FREM:
1338 case TargetOpcode::G_FCOS:
1339 case TargetOpcode::G_FSIN:
1340 case TargetOpcode::G_FTAN:
1341 case TargetOpcode::G_FACOS:
1342 case TargetOpcode::G_FASIN:
1343 case TargetOpcode::G_FATAN:
1344 case TargetOpcode::G_FATAN2:
1345 case TargetOpcode::G_FCOSH:
1346 case TargetOpcode::G_FSINH:
1347 case TargetOpcode::G_FTANH:
1348 case TargetOpcode::G_FLOG10:
1349 case TargetOpcode::G_FLOG:
1350 case TargetOpcode::G_FLOG2:
1351 case TargetOpcode::G_FEXP:
1352 case TargetOpcode::G_FEXP2:
1353 case TargetOpcode::G_FEXP10:
1354 case TargetOpcode::G_FCEIL:
1355 case TargetOpcode::G_FFLOOR:
1356 case TargetOpcode::G_FMINNUM:
1357 case TargetOpcode::G_FMAXNUM:
1358 case TargetOpcode::G_FMINIMUMNUM:
1359 case TargetOpcode::G_FMAXIMUMNUM:
1360 case TargetOpcode::G_FSQRT:
1361 case TargetOpcode::G_FRINT:
1362 case TargetOpcode::G_FNEARBYINT:
1363 case TargetOpcode::G_INTRINSIC_TRUNC:
1364 case TargetOpcode::G_INTRINSIC_ROUND:
1365 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1366 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1367 unsigned Size = LLTy.getSizeInBits();
1368 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1369 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1370 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1371 return UnableToLegalize;
1372 }
1373 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1374 if (Status != Legalized)
1375 return Status;
1376 break;
1377 }
1378 case TargetOpcode::G_FSINCOS: {
1379 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1380 unsigned Size = LLTy.getSizeInBits();
1381 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1382 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1383 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1384 return UnableToLegalize;
1385 }
1386 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1387 }
1388 case TargetOpcode::G_FMODF: {
1389 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1390 unsigned Size = LLTy.getSizeInBits();
1391 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1392 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1393 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1394 return UnableToLegalize;
1395 }
1396 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1397 }
1398 case TargetOpcode::G_LROUND:
1399 case TargetOpcode::G_LLROUND:
1400 case TargetOpcode::G_INTRINSIC_LRINT:
1401 case TargetOpcode::G_INTRINSIC_LLRINT: {
1402 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1403 unsigned Size = LLTy.getSizeInBits();
1404 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1405 Type *ITy = IntegerType::get(
1406 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1407 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1408 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1409 return UnableToLegalize;
1410 }
1411 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1413 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1414 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1415 if (Status != Legalized)
1416 return Status;
1417 MI.eraseFromParent();
1418 return Legalized;
1419 }
1420 case TargetOpcode::G_FPOWI:
1421 case TargetOpcode::G_FLDEXP: {
1422 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1423 unsigned Size = LLTy.getSizeInBits();
1424 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1425 Type *ITy = IntegerType::get(
1426 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1427 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1428 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1429 return UnableToLegalize;
1430 }
1431 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1433 {MI.getOperand(1).getReg(), HLTy, 0},
1434 {MI.getOperand(2).getReg(), ITy, 1}};
1435 Args[1].Flags[0].setSExt();
1437 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1438 if (Status != Legalized)
1439 return Status;
1440 break;
1441 }
1442 case TargetOpcode::G_FPEXT:
1443 case TargetOpcode::G_FPTRUNC: {
1444 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1445 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1446 if (!FromTy || !ToTy)
1447 return UnableToLegalize;
1448 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1449 if (Status != Legalized)
1450 return Status;
1451 break;
1452 }
1453 case TargetOpcode::G_FCMP: {
1454 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1455 if (Status != Legalized)
1456 return Status;
1457 MI.eraseFromParent();
1458 return Status;
1459 }
1460 case TargetOpcode::G_FPTOSI:
1461 case TargetOpcode::G_FPTOUI: {
1462 // FIXME: Support other types
1463 Type *FromTy =
1464 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1465 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1466 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1467 return UnableToLegalize;
1469 FromTy, LocObserver);
1470 if (Status != Legalized)
1471 return Status;
1472 break;
1473 }
1474 case TargetOpcode::G_SITOFP:
1475 case TargetOpcode::G_UITOFP: {
1476 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1477 Type *ToTy =
1478 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1479 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1480 return UnableToLegalize;
1481 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1483 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1484 if (Status != Legalized)
1485 return Status;
1486 break;
1487 }
1488 case TargetOpcode::G_ATOMICRMW_XCHG:
1489 case TargetOpcode::G_ATOMICRMW_ADD:
1490 case TargetOpcode::G_ATOMICRMW_SUB:
1491 case TargetOpcode::G_ATOMICRMW_AND:
1492 case TargetOpcode::G_ATOMICRMW_OR:
1493 case TargetOpcode::G_ATOMICRMW_XOR:
1494 case TargetOpcode::G_ATOMIC_CMPXCHG:
1495 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1497 if (Status != Legalized)
1498 return Status;
1499 break;
1500 }
1501 case TargetOpcode::G_BZERO:
1502 case TargetOpcode::G_MEMCPY:
1503 case TargetOpcode::G_MEMMOVE:
1504 case TargetOpcode::G_MEMSET: {
1505 LegalizeResult Result =
1506 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1507 if (Result != Legalized)
1508 return Result;
1509 MI.eraseFromParent();
1510 return Result;
1511 }
1512 case TargetOpcode::G_GET_FPENV:
1513 case TargetOpcode::G_GET_FPMODE: {
1514 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1515 if (Result != Legalized)
1516 return Result;
1517 break;
1518 }
1519 case TargetOpcode::G_SET_FPENV:
1520 case TargetOpcode::G_SET_FPMODE: {
1521 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1522 if (Result != Legalized)
1523 return Result;
1524 break;
1525 }
1526 case TargetOpcode::G_RESET_FPENV:
1527 case TargetOpcode::G_RESET_FPMODE: {
1528 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1529 if (Result != Legalized)
1530 return Result;
1531 break;
1532 }
1533 }
1534
1535 MI.eraseFromParent();
1536 return Legalized;
1537}
1538
1540 unsigned TypeIdx,
1541 LLT NarrowTy) {
1542 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1543 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1544
1545 switch (MI.getOpcode()) {
1546 default:
1547 return UnableToLegalize;
1548 case TargetOpcode::G_IMPLICIT_DEF: {
1549 Register DstReg = MI.getOperand(0).getReg();
1550 LLT DstTy = MRI.getType(DstReg);
1551
1552 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1553 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1554 // FIXME: Although this would also be legal for the general case, it causes
1555 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1556 // combines not being hit). This seems to be a problem related to the
1557 // artifact combiner.
1558 if (SizeOp0 % NarrowSize != 0) {
1559 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1560 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1561 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1562
1563 MI.eraseFromParent();
1564 return Legalized;
1565 }
1566
1567 int NumParts = SizeOp0 / NarrowSize;
1568
1570 for (int i = 0; i < NumParts; ++i)
1571 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1572
1573 if (DstTy.isVector())
1574 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1575 else
1576 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1577 MI.eraseFromParent();
1578 return Legalized;
1579 }
1580 case TargetOpcode::G_CONSTANT: {
1581 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1582 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1583 unsigned TotalSize = Ty.getSizeInBits();
1584 unsigned NarrowSize = NarrowTy.getSizeInBits();
1585 int NumParts = TotalSize / NarrowSize;
1586
1587 SmallVector<Register, 4> PartRegs;
1588 for (int I = 0; I != NumParts; ++I) {
1589 unsigned Offset = I * NarrowSize;
1590 auto K = MIRBuilder.buildConstant(NarrowTy,
1591 Val.lshr(Offset).trunc(NarrowSize));
1592 PartRegs.push_back(K.getReg(0));
1593 }
1594
1595 LLT LeftoverTy;
1596 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1597 SmallVector<Register, 1> LeftoverRegs;
1598 if (LeftoverBits != 0) {
1599 LeftoverTy = LLT::scalar(LeftoverBits);
1600 auto K = MIRBuilder.buildConstant(
1601 LeftoverTy,
1602 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1603 LeftoverRegs.push_back(K.getReg(0));
1604 }
1605
1606 insertParts(MI.getOperand(0).getReg(),
1607 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1608
1609 MI.eraseFromParent();
1610 return Legalized;
1611 }
1612 case TargetOpcode::G_SEXT:
1613 case TargetOpcode::G_ZEXT:
1614 case TargetOpcode::G_ANYEXT:
1615 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1616 case TargetOpcode::G_TRUNC: {
1617 if (TypeIdx != 1)
1618 return UnableToLegalize;
1619
1620 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1621 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1622 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1623 return UnableToLegalize;
1624 }
1625
1626 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1627 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1628 MI.eraseFromParent();
1629 return Legalized;
1630 }
1631 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1632 case TargetOpcode::G_FREEZE: {
1633 if (TypeIdx != 0)
1634 return UnableToLegalize;
1635
1636 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1637 // Should widen scalar first
1638 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1639 return UnableToLegalize;
1640
1641 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1643 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1644 Parts.push_back(
1645 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1646 .getReg(0));
1647 }
1648
1649 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1650 MI.eraseFromParent();
1651 return Legalized;
1652 }
1653 case TargetOpcode::G_ADD:
1654 case TargetOpcode::G_SUB:
1655 case TargetOpcode::G_SADDO:
1656 case TargetOpcode::G_SSUBO:
1657 case TargetOpcode::G_SADDE:
1658 case TargetOpcode::G_SSUBE:
1659 case TargetOpcode::G_UADDO:
1660 case TargetOpcode::G_USUBO:
1661 case TargetOpcode::G_UADDE:
1662 case TargetOpcode::G_USUBE:
1663 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1664 case TargetOpcode::G_MUL:
1665 case TargetOpcode::G_UMULH:
1666 return narrowScalarMul(MI, NarrowTy);
1667 case TargetOpcode::G_EXTRACT:
1668 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1669 case TargetOpcode::G_INSERT:
1670 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1671 case TargetOpcode::G_LOAD: {
1672 auto &LoadMI = cast<GLoad>(MI);
1673 Register DstReg = LoadMI.getDstReg();
1674 LLT DstTy = MRI.getType(DstReg);
1675 if (DstTy.isVector())
1676 return UnableToLegalize;
1677
1678 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1679 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1680 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1681 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1682 LoadMI.eraseFromParent();
1683 return Legalized;
1684 }
1685
1686 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1687 }
1688 case TargetOpcode::G_ZEXTLOAD:
1689 case TargetOpcode::G_SEXTLOAD:
1690 case TargetOpcode::G_FPEXTLOAD: {
1691 auto &LoadMI = cast<GExtLoad>(MI);
1692 Register DstReg = LoadMI.getDstReg();
1693 Register PtrReg = LoadMI.getPointerReg();
1694
1695 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1696 auto &MMO = LoadMI.getMMO();
1697 unsigned MemSize = MMO.getSizeInBits().getValue();
1698
1699 if (MemSize == NarrowSize) {
1700 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1701 } else if (MemSize < NarrowSize) {
1702 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1703 } else if (MemSize > NarrowSize) {
1704 // FIXME: Need to split the load.
1705 return UnableToLegalize;
1706 }
1707
1708 if (isa<GZExtLoad>(LoadMI))
1709 MIRBuilder.buildZExt(DstReg, TmpReg);
1710 else if (isa<GSExtLoad>(LoadMI))
1711 MIRBuilder.buildSExt(DstReg, TmpReg);
1712 else
1713 MIRBuilder.buildFPExt(DstReg, TmpReg);
1714
1715 LoadMI.eraseFromParent();
1716 return Legalized;
1717 }
1718 case TargetOpcode::G_STORE: {
1719 auto &StoreMI = cast<GStore>(MI);
1720
1721 Register SrcReg = StoreMI.getValueReg();
1722 LLT SrcTy = MRI.getType(SrcReg);
1723 if (SrcTy.isVector())
1724 return UnableToLegalize;
1725
1726 int NumParts = SizeOp0 / NarrowSize;
1727 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1728 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1729 if (SrcTy.isVector() && LeftoverBits != 0)
1730 return UnableToLegalize;
1731
1732 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1733 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1734 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1735 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1736 StoreMI.eraseFromParent();
1737 return Legalized;
1738 }
1739
1740 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1741 }
1742 case TargetOpcode::G_FPTRUNCSTORE: {
1743 auto &StoreMI = cast<GFPTruncStore>(MI);
1744 Register SrcReg = StoreMI.getValueReg();
1745 Register PtrReg = StoreMI.getPointerReg();
1746
1747 auto &MMO = StoreMI.getMMO();
1748 unsigned MemSize = MMO.getSizeInBits().getValue();
1749 if (MemSize > NarrowSize) {
1750 return UnableToLegalize;
1751 }
1752
1753 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1754 if (MemSize == NarrowSize) {
1755 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1756 } else if (MemSize < NarrowSize) {
1757 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1758 MMO);
1759 }
1760
1761 StoreMI.eraseFromParent();
1762 return Legalized;
1763 }
1764 case TargetOpcode::G_SELECT:
1765 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1766 case TargetOpcode::G_AND:
1767 case TargetOpcode::G_OR:
1768 case TargetOpcode::G_XOR: {
1769 // Legalize bitwise operation:
1770 // A = BinOp<Ty> B, C
1771 // into:
1772 // B1, ..., BN = G_UNMERGE_VALUES B
1773 // C1, ..., CN = G_UNMERGE_VALUES C
1774 // A1 = BinOp<Ty/N> B1, C2
1775 // ...
1776 // AN = BinOp<Ty/N> BN, CN
1777 // A = G_MERGE_VALUES A1, ..., AN
1778 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1779 }
1780 case TargetOpcode::G_SHL:
1781 case TargetOpcode::G_LSHR:
1782 case TargetOpcode::G_ASHR:
1783 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1784 case TargetOpcode::G_CTLZ:
1785 case TargetOpcode::G_CTLZ_ZERO_POISON:
1786 case TargetOpcode::G_CTTZ:
1787 case TargetOpcode::G_CTTZ_ZERO_POISON:
1788 case TargetOpcode::G_CTLS:
1789 case TargetOpcode::G_CTPOP:
1790 if (TypeIdx == 1)
1791 switch (MI.getOpcode()) {
1792 case TargetOpcode::G_CTLZ:
1793 case TargetOpcode::G_CTLZ_ZERO_POISON:
1794 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1795 case TargetOpcode::G_CTTZ:
1796 case TargetOpcode::G_CTTZ_ZERO_POISON:
1797 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1798 case TargetOpcode::G_CTPOP:
1799 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1800 case TargetOpcode::G_CTLS:
1801 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1802 default:
1803 return UnableToLegalize;
1804 }
1805
1806 Observer.changingInstr(MI);
1807 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1808 Observer.changedInstr(MI);
1809 return Legalized;
1810 case TargetOpcode::G_INTTOPTR:
1811 if (TypeIdx != 1)
1812 return UnableToLegalize;
1813
1814 Observer.changingInstr(MI);
1815 narrowScalarSrc(MI, NarrowTy, 1);
1816 Observer.changedInstr(MI);
1817 return Legalized;
1818 case TargetOpcode::G_PTRTOINT:
1819 if (TypeIdx != 0)
1820 return UnableToLegalize;
1821
1822 Observer.changingInstr(MI);
1823 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1824 Observer.changedInstr(MI);
1825 return Legalized;
1826 case TargetOpcode::G_PHI: {
1827 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1828 // NarrowSize.
1829 if (SizeOp0 % NarrowSize != 0)
1830 return UnableToLegalize;
1831
1832 unsigned NumParts = SizeOp0 / NarrowSize;
1833 SmallVector<Register, 2> DstRegs(NumParts);
1834 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1835 Observer.changingInstr(MI);
1836 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1837 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1838 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1839 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1840 SrcRegs[i / 2], MIRBuilder, MRI);
1841 }
1842 MachineBasicBlock &MBB = *MI.getParent();
1843 MIRBuilder.setInsertPt(MBB, MI);
1844 for (unsigned i = 0; i < NumParts; ++i) {
1845 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1847 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1848 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1849 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1850 }
1851 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1852 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1853 Observer.changedInstr(MI);
1854 MI.eraseFromParent();
1855 return Legalized;
1856 }
1857 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1858 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1859 if (TypeIdx != 2)
1860 return UnableToLegalize;
1861
1862 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1863 Observer.changingInstr(MI);
1864 narrowScalarSrc(MI, NarrowTy, OpIdx);
1865 Observer.changedInstr(MI);
1866 return Legalized;
1867 }
1868 case TargetOpcode::G_ICMP: {
1869 Register LHS = MI.getOperand(2).getReg();
1870 LLT SrcTy = MRI.getType(LHS);
1871 CmpInst::Predicate Pred =
1872 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1873
1874 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1875 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1876 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1877 LHSLeftoverRegs, MIRBuilder, MRI))
1878 return UnableToLegalize;
1879
1880 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1881 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1882 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1883 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1884 return UnableToLegalize;
1885
1886 // We now have the LHS and RHS of the compare split into narrow-type
1887 // registers, plus potentially some leftover type.
1888 Register Dst = MI.getOperand(0).getReg();
1889 LLT ResTy = MRI.getType(Dst);
1890 if (ICmpInst::isEquality(Pred)) {
1891 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1892 // them together. For each equal part, the result should be all 0s. For
1893 // each non-equal part, we'll get at least one 1.
1894 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1896 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1897 auto LHS = std::get<0>(LHSAndRHS);
1898 auto RHS = std::get<1>(LHSAndRHS);
1899 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1900 Xors.push_back(Xor);
1901 }
1902
1903 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1904 // to the desired narrow type so that we can OR them together later.
1905 SmallVector<Register, 4> WidenedXors;
1906 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1907 auto LHS = std::get<0>(LHSAndRHS);
1908 auto RHS = std::get<1>(LHSAndRHS);
1909 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1910 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1911 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1912 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1913 llvm::append_range(Xors, WidenedXors);
1914 }
1915
1916 // Now, for each part we broke up, we know if they are equal/not equal
1917 // based off the G_XOR. We can OR these all together and compare against
1918 // 0 to get the result.
1919 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1920 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1921 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1922 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1923 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1924 } else {
1925 Register CmpIn;
1926 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1927 Register CmpOut;
1928 CmpInst::Predicate PartPred;
1929
1930 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1931 PartPred = Pred;
1932 CmpOut = Dst;
1933 } else {
1934 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1935 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1936 }
1937
1938 if (!CmpIn) {
1939 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1940 RHSPartRegs[I]);
1941 } else {
1942 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1943 RHSPartRegs[I]);
1944 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1945 LHSPartRegs[I], RHSPartRegs[I]);
1946 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1947 }
1948
1949 CmpIn = CmpOut;
1950 }
1951
1952 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1953 Register CmpOut;
1954 CmpInst::Predicate PartPred;
1955
1956 if (I == E - 1) {
1957 PartPred = Pred;
1958 CmpOut = Dst;
1959 } else {
1960 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1961 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1962 }
1963
1964 if (!CmpIn) {
1965 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1966 RHSLeftoverRegs[I]);
1967 } else {
1968 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1969 RHSLeftoverRegs[I]);
1970 auto CmpEq =
1971 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1972 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1973 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1974 }
1975
1976 CmpIn = CmpOut;
1977 }
1978 }
1979 MI.eraseFromParent();
1980 return Legalized;
1981 }
1982 case TargetOpcode::G_FCMP:
1983 if (TypeIdx != 0)
1984 return UnableToLegalize;
1985
1986 Observer.changingInstr(MI);
1987 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1988 Observer.changedInstr(MI);
1989 return Legalized;
1990
1991 case TargetOpcode::G_SEXT_INREG: {
1992 if (TypeIdx != 0)
1993 return UnableToLegalize;
1994
1995 int64_t SizeInBits = MI.getOperand(2).getImm();
1996
1997 // So long as the new type has more bits than the bits we're extending we
1998 // don't need to break it apart.
1999 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2000 Observer.changingInstr(MI);
2001 // We don't lose any non-extension bits by truncating the src and
2002 // sign-extending the dst.
2003 MachineOperand &MO1 = MI.getOperand(1);
2004 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2005 MO1.setReg(TruncMIB.getReg(0));
2006
2007 MachineOperand &MO2 = MI.getOperand(0);
2008 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2009 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2010 MIRBuilder.buildSExt(MO2, DstExt);
2011 MO2.setReg(DstExt);
2012 Observer.changedInstr(MI);
2013 return Legalized;
2014 }
2015
2016 // Break it apart. Components below the extension point are unmodified. The
2017 // component containing the extension point becomes a narrower SEXT_INREG.
2018 // Components above it are ashr'd from the component containing the
2019 // extension point.
2020 if (SizeOp0 % NarrowSize != 0)
2021 return UnableToLegalize;
2022 int NumParts = SizeOp0 / NarrowSize;
2023
2024 // List the registers where the destination will be scattered.
2026 // List the registers where the source will be split.
2028
2029 // Create all the temporary registers.
2030 for (int i = 0; i < NumParts; ++i) {
2031 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2032
2033 SrcRegs.push_back(SrcReg);
2034 }
2035
2036 // Explode the big arguments into smaller chunks.
2037 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2038
2039 Register AshrCstReg =
2040 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2041 .getReg(0);
2042 Register FullExtensionReg;
2043 Register PartialExtensionReg;
2044
2045 // Do the operation on each small part.
2046 for (int i = 0; i < NumParts; ++i) {
2047 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2048 DstRegs.push_back(SrcRegs[i]);
2049 PartialExtensionReg = DstRegs.back();
2050 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2051 assert(PartialExtensionReg &&
2052 "Expected to visit partial extension before full");
2053 if (FullExtensionReg) {
2054 DstRegs.push_back(FullExtensionReg);
2055 continue;
2056 }
2057 DstRegs.push_back(
2058 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2059 .getReg(0));
2060 FullExtensionReg = DstRegs.back();
2061 } else {
2062 DstRegs.push_back(
2064 .buildInstr(
2065 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2066 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2067 .getReg(0));
2068 PartialExtensionReg = DstRegs.back();
2069 }
2070 }
2071
2072 // Gather the destination registers into the final destination.
2073 Register DstReg = MI.getOperand(0).getReg();
2074 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2075 MI.eraseFromParent();
2076 return Legalized;
2077 }
2078 case TargetOpcode::G_BSWAP:
2079 case TargetOpcode::G_BITREVERSE: {
2080 if (SizeOp0 % NarrowSize != 0)
2081 return UnableToLegalize;
2082
2083 Observer.changingInstr(MI);
2084 SmallVector<Register, 2> SrcRegs, DstRegs;
2085 unsigned NumParts = SizeOp0 / NarrowSize;
2086 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2087 MIRBuilder, MRI);
2088
2089 for (unsigned i = 0; i < NumParts; ++i) {
2090 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2091 {SrcRegs[NumParts - 1 - i]});
2092 DstRegs.push_back(DstPart.getReg(0));
2093 }
2094
2095 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2096
2097 Observer.changedInstr(MI);
2098 MI.eraseFromParent();
2099 return Legalized;
2100 }
2101 case TargetOpcode::G_PTR_ADD:
2102 case TargetOpcode::G_PTRMASK: {
2103 if (TypeIdx != 1)
2104 return UnableToLegalize;
2105 Observer.changingInstr(MI);
2106 narrowScalarSrc(MI, NarrowTy, 2);
2107 Observer.changedInstr(MI);
2108 return Legalized;
2109 }
2110 case TargetOpcode::G_FPTOUI:
2111 case TargetOpcode::G_FPTOSI:
2112 case TargetOpcode::G_FPTOUI_SAT:
2113 case TargetOpcode::G_FPTOSI_SAT:
2114 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2115 case TargetOpcode::G_FPEXT:
2116 if (TypeIdx != 0)
2117 return UnableToLegalize;
2118 Observer.changingInstr(MI);
2119 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2120 Observer.changedInstr(MI);
2121 return Legalized;
2122 case TargetOpcode::G_FLDEXP:
2123 case TargetOpcode::G_STRICT_FLDEXP:
2124 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2125 case TargetOpcode::G_VSCALE: {
2126 Register Dst = MI.getOperand(0).getReg();
2127 LLT Ty = MRI.getType(Dst);
2128
2129 // Assume VSCALE(1) fits into a legal integer
2130 const APInt One(NarrowTy.getSizeInBits(), 1);
2131 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2132 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2133 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2134 MIRBuilder.buildMul(Dst, ZExt, C);
2135
2136 MI.eraseFromParent();
2137 return Legalized;
2138 }
2139 }
2140}
2141
2143 LLT Ty = MRI.getType(Val);
2144 if (Ty.isScalar())
2145 return Val;
2146
2147 const DataLayout &DL = MIRBuilder.getDataLayout();
2148 LLT NewTy = LLT::scalar(Ty.getSizeInBits());
2149 if (Ty.isPointer()) {
2150 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2151 return Register();
2152 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2153 }
2154
2155 Register NewVal = Val;
2156
2157 assert(Ty.isVector());
2158 if (Ty.isPointerVector())
2159 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2160 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2161}
2162
2164 unsigned OpIdx, unsigned ExtOpcode) {
2165 MachineOperand &MO = MI.getOperand(OpIdx);
2166 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2167 MO.setReg(ExtB.getReg(0));
2168}
2169
2171 unsigned OpIdx) {
2172 MachineOperand &MO = MI.getOperand(OpIdx);
2173 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2174 MI.getFlags());
2175 MO.setReg(ExtB.getReg(0));
2176}
2177
2179 unsigned OpIdx) {
2180 MachineOperand &MO = MI.getOperand(OpIdx);
2181 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2182 MO.setReg(ExtB.getReg(0));
2183}
2184
2186 unsigned OpIdx, unsigned TruncOpcode) {
2187 MachineOperand &MO = MI.getOperand(OpIdx);
2188 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2189 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2190 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2191 MO.setReg(DstExt);
2192}
2193
2195 unsigned OpIdx) {
2196 MachineOperand &MO = MI.getOperand(OpIdx);
2197 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2198 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2199 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2200 MO.setReg(DstExt);
2201}
2202
2204 unsigned OpIdx, unsigned ExtOpcode) {
2205 MachineOperand &MO = MI.getOperand(OpIdx);
2206 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2207 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2208 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2209 MO.setReg(DstTrunc);
2210}
2211
2213 unsigned OpIdx) {
2214 MachineOperand &MO = MI.getOperand(OpIdx);
2215 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2216 Register Dst = MO.getReg();
2217 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2218 MO.setReg(DstExt);
2219 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2220}
2221
2223 unsigned OpIdx) {
2224 MachineOperand &MO = MI.getOperand(OpIdx);
2225 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2226}
2227
2229 MachineOperand &Op = MI.getOperand(OpIdx);
2230 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2231}
2232
2234 MachineOperand &MO = MI.getOperand(OpIdx);
2235 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2236 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2237 MIRBuilder.buildBitcast(MO, CastDst);
2238 MO.setReg(CastDst);
2239}
2240
2242LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2243 LLT WideTy) {
2244 if (TypeIdx != 1)
2245 return UnableToLegalize;
2246
2247 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2248 if (DstTy.isVector())
2249 return UnableToLegalize;
2250
2251 LLT SrcTy = MRI.getType(Src1Reg);
2252 const int DstSize = DstTy.getSizeInBits();
2253 const int SrcSize = SrcTy.getSizeInBits();
2254 const int WideSize = WideTy.getSizeInBits();
2255 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2256
2257 unsigned NumOps = MI.getNumOperands();
2258 unsigned NumSrc = MI.getNumOperands() - 1;
2259 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2260
2261 if (WideSize >= DstSize) {
2262 // Directly pack the bits in the target type.
2263 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2264
2265 for (unsigned I = 2; I != NumOps; ++I) {
2266 const unsigned Offset = (I - 1) * PartSize;
2267
2268 Register SrcReg = MI.getOperand(I).getReg();
2269 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2270
2271 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2272
2273 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2274 MRI.createGenericVirtualRegister(WideTy);
2275
2276 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2277 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2278 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2279 ResultReg = NextResult;
2280 }
2281
2282 if (WideSize > DstSize)
2283 MIRBuilder.buildTrunc(DstReg, ResultReg);
2284 else if (DstTy.isPointer())
2285 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2286
2287 MI.eraseFromParent();
2288 return Legalized;
2289 }
2290
2291 // Unmerge the original values to the GCD type, and recombine to the next
2292 // multiple greater than the original type.
2293 //
2294 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2295 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2296 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2297 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2298 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2299 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2300 // %12:_(s12) = G_MERGE_VALUES %10, %11
2301 //
2302 // Padding with undef if necessary:
2303 //
2304 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2305 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2306 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2307 // %7:_(s2) = G_IMPLICIT_DEF
2308 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2309 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2310 // %10:_(s12) = G_MERGE_VALUES %8, %9
2311
2312 const int GCD = std::gcd(SrcSize, WideSize);
2313 LLT GCDTy = WideTy.changeElementSize(GCD);
2314
2315 SmallVector<Register, 8> NewMergeRegs;
2316 SmallVector<Register, 8> Unmerges;
2317 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2318
2319 // Decompose the original operands if they don't evenly divide.
2320 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2321 Register SrcReg = MO.getReg();
2322 if (GCD == SrcSize) {
2323 Unmerges.push_back(SrcReg);
2324 } else {
2325 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2326 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2327 Unmerges.push_back(Unmerge.getReg(J));
2328 }
2329 }
2330
2331 // Pad with undef to the next size that is a multiple of the requested size.
2332 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2333 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2334 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2335 Unmerges.push_back(UndefReg);
2336 }
2337
2338 const int PartsPerGCD = WideSize / GCD;
2339
2340 // Build merges of each piece.
2341 ArrayRef<Register> Slicer(Unmerges);
2342 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2343 auto Merge =
2344 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2345 NewMergeRegs.push_back(Merge.getReg(0));
2346 }
2347
2348 // A truncate may be necessary if the requested type doesn't evenly divide the
2349 // original result type.
2350 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2351 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2352 } else {
2353 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2354 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2355 }
2356
2357 MI.eraseFromParent();
2358 return Legalized;
2359}
2360
2362LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2363 LLT WideTy) {
2364 if (TypeIdx != 0)
2365 return UnableToLegalize;
2366
2367 int NumDst = MI.getNumOperands() - 1;
2368 Register SrcReg = MI.getOperand(NumDst).getReg();
2369 LLT SrcTy = MRI.getType(SrcReg);
2370 if (SrcTy.isVector())
2371 return UnableToLegalize;
2372
2373 Register Dst0Reg = MI.getOperand(0).getReg();
2374 LLT DstTy = MRI.getType(Dst0Reg);
2375 if (!DstTy.isScalar())
2376 return UnableToLegalize;
2377
2378 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2379 if (SrcTy.isPointer()) {
2380 const DataLayout &DL = MIRBuilder.getDataLayout();
2381 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2382 LLVM_DEBUG(
2383 dbgs() << "Not casting non-integral address space integer\n");
2384 return UnableToLegalize;
2385 }
2386
2387 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2388 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2389 }
2390
2391 // Widen SrcTy to WideTy. This does not affect the result, but since the
2392 // user requested this size, it is probably better handled than SrcTy and
2393 // should reduce the total number of legalization artifacts.
2394 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2395 SrcTy = WideTy;
2396 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2397 }
2398
2399 // Theres no unmerge type to target. Directly extract the bits from the
2400 // source type
2401 unsigned DstSize = DstTy.getSizeInBits();
2402
2403 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2404 for (int I = 1; I != NumDst; ++I) {
2405 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2406 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2407 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2408 }
2409
2410 MI.eraseFromParent();
2411 return Legalized;
2412 }
2413
2414 // Extend the source to a wider type.
2415 LLT LCMTy = getLCMType(SrcTy, WideTy);
2416
2417 Register WideSrc = SrcReg;
2418 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2419 // TODO: If this is an integral address space, cast to integer and anyext.
2420 if (SrcTy.isPointer()) {
2421 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2422 return UnableToLegalize;
2423 }
2424
2425 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2426 }
2427
2428 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2429
2430 // Create a sequence of unmerges and merges to the original results. Since we
2431 // may have widened the source, we will need to pad the results with dead defs
2432 // to cover the source register.
2433 // e.g. widen s48 to s64:
2434 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2435 //
2436 // =>
2437 // %4:_(s192) = G_ANYEXT %0:_(s96)
2438 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2439 // ; unpack to GCD type, with extra dead defs
2440 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2441 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2442 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2443 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2444 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2445 const LLT GCDTy = getGCDType(WideTy, DstTy);
2446 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2447 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2448
2449 // Directly unmerge to the destination without going through a GCD type
2450 // if possible
2451 if (PartsPerRemerge == 1) {
2452 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2453
2454 for (int I = 0; I != NumUnmerge; ++I) {
2455 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2456
2457 for (int J = 0; J != PartsPerUnmerge; ++J) {
2458 int Idx = I * PartsPerUnmerge + J;
2459 if (Idx < NumDst)
2460 MIB.addDef(MI.getOperand(Idx).getReg());
2461 else {
2462 // Create dead def for excess components.
2463 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2464 }
2465 }
2466
2467 MIB.addUse(Unmerge.getReg(I));
2468 }
2469 } else {
2470 SmallVector<Register, 16> Parts;
2471 for (int J = 0; J != NumUnmerge; ++J)
2472 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2473
2474 SmallVector<Register, 8> RemergeParts;
2475 for (int I = 0; I != NumDst; ++I) {
2476 for (int J = 0; J < PartsPerRemerge; ++J) {
2477 const int Idx = I * PartsPerRemerge + J;
2478 RemergeParts.emplace_back(Parts[Idx]);
2479 }
2480
2481 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2482 RemergeParts.clear();
2483 }
2484 }
2485
2486 MI.eraseFromParent();
2487 return Legalized;
2488}
2489
2491LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2492 LLT WideTy) {
2493 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2494 unsigned Offset = MI.getOperand(2).getImm();
2495
2496 if (TypeIdx == 0) {
2497 if (SrcTy.isVector() || DstTy.isVector())
2498 return UnableToLegalize;
2499
2500 SrcOp Src(SrcReg);
2501 if (SrcTy.isPointer()) {
2502 // Extracts from pointers can be handled only if they are really just
2503 // simple integers.
2504 const DataLayout &DL = MIRBuilder.getDataLayout();
2505 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2506 return UnableToLegalize;
2507
2508 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2509 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2510 SrcTy = SrcAsIntTy;
2511 }
2512
2513 if (DstTy.isPointer())
2514 return UnableToLegalize;
2515
2516 if (Offset == 0) {
2517 // Avoid a shift in the degenerate case.
2518 MIRBuilder.buildTrunc(DstReg,
2519 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2520 MI.eraseFromParent();
2521 return Legalized;
2522 }
2523
2524 // Do a shift in the source type.
2525 LLT ShiftTy = SrcTy;
2526 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2527 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2528 ShiftTy = WideTy;
2529 }
2530
2531 auto LShr = MIRBuilder.buildLShr(
2532 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2533 MIRBuilder.buildTrunc(DstReg, LShr);
2534 MI.eraseFromParent();
2535 return Legalized;
2536 }
2537
2538 if (SrcTy.isScalar()) {
2539 Observer.changingInstr(MI);
2540 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2541 Observer.changedInstr(MI);
2542 return Legalized;
2543 }
2544
2545 if (!SrcTy.isVector())
2546 return UnableToLegalize;
2547
2548 if (DstTy != SrcTy.getElementType())
2549 return UnableToLegalize;
2550
2551 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2552 return UnableToLegalize;
2553
2554 Observer.changingInstr(MI);
2555 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2556
2557 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2558 Offset);
2559 widenScalarDst(MI, WideTy.getScalarType(), 0);
2560 Observer.changedInstr(MI);
2561 return Legalized;
2562}
2563
2565LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2566 LLT WideTy) {
2567 if (TypeIdx != 0 || WideTy.isVector())
2568 return UnableToLegalize;
2569 Observer.changingInstr(MI);
2570 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2571 widenScalarDst(MI, WideTy);
2572 Observer.changedInstr(MI);
2573 return Legalized;
2574}
2575
2577LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2578 LLT WideTy) {
2579 unsigned Opcode;
2580 unsigned ExtOpcode;
2581 std::optional<Register> CarryIn;
2582 switch (MI.getOpcode()) {
2583 default:
2584 llvm_unreachable("Unexpected opcode!");
2585 case TargetOpcode::G_SADDO:
2586 Opcode = TargetOpcode::G_ADD;
2587 ExtOpcode = TargetOpcode::G_SEXT;
2588 break;
2589 case TargetOpcode::G_SSUBO:
2590 Opcode = TargetOpcode::G_SUB;
2591 ExtOpcode = TargetOpcode::G_SEXT;
2592 break;
2593 case TargetOpcode::G_UADDO:
2594 Opcode = TargetOpcode::G_ADD;
2595 ExtOpcode = TargetOpcode::G_ZEXT;
2596 break;
2597 case TargetOpcode::G_USUBO:
2598 Opcode = TargetOpcode::G_SUB;
2599 ExtOpcode = TargetOpcode::G_ZEXT;
2600 break;
2601 case TargetOpcode::G_SADDE:
2602 Opcode = TargetOpcode::G_UADDE;
2603 ExtOpcode = TargetOpcode::G_SEXT;
2604 CarryIn = MI.getOperand(4).getReg();
2605 break;
2606 case TargetOpcode::G_SSUBE:
2607 Opcode = TargetOpcode::G_USUBE;
2608 ExtOpcode = TargetOpcode::G_SEXT;
2609 CarryIn = MI.getOperand(4).getReg();
2610 break;
2611 case TargetOpcode::G_UADDE:
2612 Opcode = TargetOpcode::G_UADDE;
2613 ExtOpcode = TargetOpcode::G_ZEXT;
2614 CarryIn = MI.getOperand(4).getReg();
2615 break;
2616 case TargetOpcode::G_USUBE:
2617 Opcode = TargetOpcode::G_USUBE;
2618 ExtOpcode = TargetOpcode::G_ZEXT;
2619 CarryIn = MI.getOperand(4).getReg();
2620 break;
2621 }
2622
2623 if (TypeIdx == 1) {
2624 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2625
2626 Observer.changingInstr(MI);
2627 if (CarryIn)
2628 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2629 widenScalarDst(MI, WideTy, 1);
2630
2631 Observer.changedInstr(MI);
2632 return Legalized;
2633 }
2634
2635 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2636 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2637 // Do the arithmetic in the larger type.
2638 Register NewOp;
2639 if (CarryIn) {
2640 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2641 NewOp = MIRBuilder
2642 .buildInstr(Opcode, {WideTy, CarryOutTy},
2643 {LHSExt, RHSExt, *CarryIn})
2644 .getReg(0);
2645 } else {
2646 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2647 }
2648 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2649 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2650 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2651 // There is no overflow if the ExtOp is the same as NewOp.
2652 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2653 // Now trunc the NewOp to the original result.
2654 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2655 MI.eraseFromParent();
2656 return Legalized;
2657}
2658
2660LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2661 LLT WideTy) {
2662 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2663 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2664 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2665 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2666 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2667 // We can convert this to:
2668 // 1. Any extend iN to iM
2669 // 2. SHL by M-N
2670 // 3. [US][ADD|SUB|SHL]SAT
2671 // 4. L/ASHR by M-N
2672 //
2673 // It may be more efficient to lower this to a min and a max operation in
2674 // the higher precision arithmetic if the promoted operation isn't legal,
2675 // but this decision is up to the target's lowering request.
2676 Register DstReg = MI.getOperand(0).getReg();
2677
2678 unsigned NewBits = WideTy.getScalarSizeInBits();
2679 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2680
2681 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2682 // must not left shift the RHS to preserve the shift amount.
2683 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2684 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2685 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2686 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2687 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2688 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2689
2690 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2691 {ShiftL, ShiftR}, MI.getFlags());
2692
2693 // Use a shift that will preserve the number of sign bits when the trunc is
2694 // folded away.
2695 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2696 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2697
2698 MIRBuilder.buildTrunc(DstReg, Result);
2699 MI.eraseFromParent();
2700 return Legalized;
2701}
2702
2704LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2705 LLT WideTy) {
2706 if (TypeIdx == 1) {
2707 Observer.changingInstr(MI);
2708 widenScalarDst(MI, WideTy, 1);
2709 Observer.changedInstr(MI);
2710 return Legalized;
2711 }
2712
2713 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2714 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2715 LLT SrcTy = MRI.getType(LHS);
2716 LLT OverflowTy = MRI.getType(OriginalOverflow);
2717 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2718
2719 // To determine if the result overflowed in the larger type, we extend the
2720 // input to the larger type, do the multiply (checking if it overflows),
2721 // then also check the high bits of the result to see if overflow happened
2722 // there.
2723 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2724 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2725 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2726
2727 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2728 // so we don't need to check the overflow result of larger type Mulo.
2729 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2730
2731 unsigned MulOpc =
2732 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2733
2734 MachineInstrBuilder Mulo;
2735 if (WideMulCanOverflow)
2736 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2737 {LeftOperand, RightOperand});
2738 else
2739 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2740
2741 auto Mul = Mulo->getOperand(0);
2742 MIRBuilder.buildTrunc(Result, Mul);
2743
2744 MachineInstrBuilder ExtResult;
2745 // Overflow occurred if it occurred in the larger type, or if the high part
2746 // of the result does not zero/sign-extend the low part. Check this second
2747 // possibility first.
2748 if (IsSigned) {
2749 // For signed, overflow occurred when the high part does not sign-extend
2750 // the low part.
2751 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2752 } else {
2753 // Unsigned overflow occurred when the high part does not zero-extend the
2754 // low part.
2755 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2756 }
2757
2758 if (WideMulCanOverflow) {
2759 auto Overflow =
2760 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2761 // Finally check if the multiplication in the larger type itself overflowed.
2762 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2763 } else {
2764 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2765 }
2766 MI.eraseFromParent();
2767 return Legalized;
2768}
2769
2772 unsigned Opcode = MI.getOpcode();
2773 switch (Opcode) {
2774 default:
2775 return UnableToLegalize;
2776 case TargetOpcode::G_ATOMICRMW_XCHG:
2777 case TargetOpcode::G_ATOMICRMW_ADD:
2778 case TargetOpcode::G_ATOMICRMW_SUB:
2779 case TargetOpcode::G_ATOMICRMW_AND:
2780 case TargetOpcode::G_ATOMICRMW_OR:
2781 case TargetOpcode::G_ATOMICRMW_XOR:
2782 case TargetOpcode::G_ATOMICRMW_MIN:
2783 case TargetOpcode::G_ATOMICRMW_MAX:
2784 case TargetOpcode::G_ATOMICRMW_UMIN:
2785 case TargetOpcode::G_ATOMICRMW_UMAX:
2786 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2787 Observer.changingInstr(MI);
2788 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2789 widenScalarDst(MI, WideTy, 0);
2790 Observer.changedInstr(MI);
2791 return Legalized;
2792 case TargetOpcode::G_ATOMIC_CMPXCHG:
2793 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2794 Observer.changingInstr(MI);
2795 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2796 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2797 widenScalarDst(MI, WideTy, 0);
2798 Observer.changedInstr(MI);
2799 return Legalized;
2800 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2801 if (TypeIdx == 0) {
2802 Observer.changingInstr(MI);
2803 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2804 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2805 widenScalarDst(MI, WideTy, 0);
2806 Observer.changedInstr(MI);
2807 return Legalized;
2808 }
2809 assert(TypeIdx == 1 &&
2810 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2811 Observer.changingInstr(MI);
2812 widenScalarDst(MI, WideTy, 1);
2813 Observer.changedInstr(MI);
2814 return Legalized;
2815 case TargetOpcode::G_EXTRACT:
2816 return widenScalarExtract(MI, TypeIdx, WideTy);
2817 case TargetOpcode::G_INSERT:
2818 return widenScalarInsert(MI, TypeIdx, WideTy);
2819 case TargetOpcode::G_MERGE_VALUES:
2820 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2821 case TargetOpcode::G_UNMERGE_VALUES:
2822 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2823 case TargetOpcode::G_SADDO:
2824 case TargetOpcode::G_SSUBO:
2825 case TargetOpcode::G_UADDO:
2826 case TargetOpcode::G_USUBO:
2827 case TargetOpcode::G_SADDE:
2828 case TargetOpcode::G_SSUBE:
2829 case TargetOpcode::G_UADDE:
2830 case TargetOpcode::G_USUBE:
2831 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2832 case TargetOpcode::G_UMULO:
2833 case TargetOpcode::G_SMULO:
2834 return widenScalarMulo(MI, TypeIdx, WideTy);
2835 case TargetOpcode::G_SADDSAT:
2836 case TargetOpcode::G_SSUBSAT:
2837 case TargetOpcode::G_SSHLSAT:
2838 case TargetOpcode::G_UADDSAT:
2839 case TargetOpcode::G_USUBSAT:
2840 case TargetOpcode::G_USHLSAT:
2841 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2842 case TargetOpcode::G_CTTZ:
2843 case TargetOpcode::G_CTTZ_ZERO_POISON:
2844 case TargetOpcode::G_CTLZ:
2845 case TargetOpcode::G_CTLZ_ZERO_POISON:
2846 case TargetOpcode::G_CTLS:
2847 case TargetOpcode::G_CTPOP: {
2848 if (TypeIdx == 0) {
2849 Observer.changingInstr(MI);
2850 widenScalarDst(MI, WideTy, 0);
2851 Observer.changedInstr(MI);
2852 return Legalized;
2853 }
2854
2855 Register SrcReg = MI.getOperand(1).getReg();
2856
2857 // First extend the input.
2858 unsigned ExtOpc;
2859 switch (Opcode) {
2860 case TargetOpcode::G_CTTZ:
2861 case TargetOpcode::G_CTTZ_ZERO_POISON:
2862 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2863 ExtOpc = TargetOpcode::G_ANYEXT;
2864 break;
2865 case TargetOpcode::G_CTLS:
2866 ExtOpc = TargetOpcode::G_SEXT;
2867 break;
2868 default:
2869 ExtOpc = TargetOpcode::G_ZEXT;
2870 }
2871
2872 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2873 LLT CurTy = MRI.getType(SrcReg);
2874 unsigned NewOpc = Opcode;
2875 if (NewOpc == TargetOpcode::G_CTTZ) {
2876 // The count is the same in the larger type except if the original
2877 // value was zero. This can be handled by setting the bit just off
2878 // the top of the original type.
2879 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2880 CurTy.getScalarSizeInBits());
2881 MIBSrc = MIRBuilder.buildOr(
2882 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2883 // Now we know the operand is non-zero, use the more relaxed opcode.
2884 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2885 }
2886
2887 unsigned SizeDiff =
2888 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2889
2890 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2891 // An optimization where the result is the CTLZ after the left shift by
2892 // (Difference in widety and current ty), that is,
2893 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2894 // Result = ctlz MIBSrc
2895 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2896 MIRBuilder.buildConstant(WideTy, SizeDiff));
2897 }
2898
2899 // Perform the operation at the larger size.
2900 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2901 // This is already the correct result for CTPOP and CTTZs
2902 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2903 // The correct result is NewOp - (Difference in widety and current ty).
2904 // At this stage SUB is guaranteed to be positive no-wrap,
2905 // that to be used in further KnownBits optimizations for CTLZ.
2906 MIBNewOp = MIRBuilder.buildSub(
2907 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2908 Opcode == TargetOpcode::G_CTLZ
2909 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2910 : std::nullopt);
2911 }
2912
2913 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2914 MI.eraseFromParent();
2915 return Legalized;
2916 }
2917 case TargetOpcode::G_BSWAP: {
2918 Observer.changingInstr(MI);
2919 Register DstReg = MI.getOperand(0).getReg();
2920
2921 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2922 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2923 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2924 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2925
2926 MI.getOperand(0).setReg(DstExt);
2927
2928 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2929
2930 LLT Ty = MRI.getType(DstReg);
2931 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2932 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2933 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2934
2935 MIRBuilder.buildTrunc(DstReg, ShrReg);
2936 Observer.changedInstr(MI);
2937 return Legalized;
2938 }
2939 case TargetOpcode::G_BITREVERSE: {
2940 Observer.changingInstr(MI);
2941
2942 Register DstReg = MI.getOperand(0).getReg();
2943 LLT Ty = MRI.getType(DstReg);
2944 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2945
2946 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2947 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2948 MI.getOperand(0).setReg(DstExt);
2949 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2950
2951 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2952 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2953 MIRBuilder.buildTrunc(DstReg, Shift);
2954 Observer.changedInstr(MI);
2955 return Legalized;
2956 }
2957 case TargetOpcode::G_FREEZE:
2958 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2959 Observer.changingInstr(MI);
2960 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2961 widenScalarDst(MI, WideTy);
2962 Observer.changedInstr(MI);
2963 return Legalized;
2964
2965 case TargetOpcode::G_ABS:
2966 Observer.changingInstr(MI);
2967 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2968 widenScalarDst(MI, WideTy);
2969 Observer.changedInstr(MI);
2970 return Legalized;
2971
2972 case TargetOpcode::G_ADD:
2973 case TargetOpcode::G_AND:
2974 case TargetOpcode::G_MUL:
2975 case TargetOpcode::G_OR:
2976 case TargetOpcode::G_XOR:
2977 case TargetOpcode::G_SUB:
2978 case TargetOpcode::G_SHUFFLE_VECTOR:
2979 // Perform operation at larger width (any extension is fines here, high bits
2980 // don't affect the result) and then truncate the result back to the
2981 // original type.
2982 Observer.changingInstr(MI);
2983 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2984 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2985 widenScalarDst(MI, WideTy);
2986 Observer.changedInstr(MI);
2987 return Legalized;
2988
2989 case TargetOpcode::G_SBFX:
2990 case TargetOpcode::G_UBFX:
2991 Observer.changingInstr(MI);
2992
2993 if (TypeIdx == 0) {
2994 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2995 widenScalarDst(MI, WideTy);
2996 } else {
2997 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
2998 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
2999 }
3000
3001 Observer.changedInstr(MI);
3002 return Legalized;
3003
3004 case TargetOpcode::G_SHL:
3005 Observer.changingInstr(MI);
3006
3007 if (TypeIdx == 0) {
3008 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3009 widenScalarDst(MI, WideTy);
3010 } else {
3011 assert(TypeIdx == 1);
3012 // The "number of bits to shift" operand must preserve its value as an
3013 // unsigned integer:
3014 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3015 }
3016
3017 Observer.changedInstr(MI);
3018 return Legalized;
3019
3020 case TargetOpcode::G_ROTR:
3021 case TargetOpcode::G_ROTL:
3022 if (TypeIdx != 1)
3023 return UnableToLegalize;
3024
3025 Observer.changingInstr(MI);
3026 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3027 Observer.changedInstr(MI);
3028 return Legalized;
3029
3030 case TargetOpcode::G_SDIV:
3031 case TargetOpcode::G_SREM:
3032 case TargetOpcode::G_SMIN:
3033 case TargetOpcode::G_SMAX:
3034 case TargetOpcode::G_ABDS:
3035 Observer.changingInstr(MI);
3036 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3037 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3038 widenScalarDst(MI, WideTy);
3039 Observer.changedInstr(MI);
3040 return Legalized;
3041
3042 case TargetOpcode::G_SDIVREM:
3043 Observer.changingInstr(MI);
3044 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3045 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3046 widenScalarDst(MI, WideTy);
3047 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3048 widenScalarDst(MI, WideTy, 1);
3049 Observer.changedInstr(MI);
3050 return Legalized;
3051
3052 case TargetOpcode::G_ASHR:
3053 case TargetOpcode::G_LSHR:
3054 Observer.changingInstr(MI);
3055
3056 if (TypeIdx == 0) {
3057 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3058 : TargetOpcode::G_ZEXT;
3059
3060 widenScalarSrc(MI, WideTy, 1, CvtOp);
3061 widenScalarDst(MI, WideTy);
3062 } else {
3063 assert(TypeIdx == 1);
3064 // The "number of bits to shift" operand must preserve its value as an
3065 // unsigned integer:
3066 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3067 }
3068
3069 Observer.changedInstr(MI);
3070 return Legalized;
3071 case TargetOpcode::G_UDIV:
3072 case TargetOpcode::G_UREM:
3073 case TargetOpcode::G_ABDU:
3074 Observer.changingInstr(MI);
3075 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3076 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3077 widenScalarDst(MI, WideTy);
3078 Observer.changedInstr(MI);
3079 return Legalized;
3080 case TargetOpcode::G_UDIVREM:
3081 Observer.changingInstr(MI);
3082 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3083 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3084 widenScalarDst(MI, WideTy);
3085 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3086 widenScalarDst(MI, WideTy, 1);
3087 Observer.changedInstr(MI);
3088 return Legalized;
3089 case TargetOpcode::G_UMIN:
3090 case TargetOpcode::G_UMAX: {
3091 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3092
3093 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3094 unsigned ExtOpc =
3095 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3096 getApproximateEVTForLLT(WideTy, Ctx))
3097 ? TargetOpcode::G_SEXT
3098 : TargetOpcode::G_ZEXT;
3099
3100 Observer.changingInstr(MI);
3101 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3102 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3103 widenScalarDst(MI, WideTy);
3104 Observer.changedInstr(MI);
3105 return Legalized;
3106 }
3107
3108 case TargetOpcode::G_SELECT:
3109 Observer.changingInstr(MI);
3110 if (TypeIdx == 0) {
3111 // Perform operation at larger width (any extension is fine here, high
3112 // bits don't affect the result) and then truncate the result back to the
3113 // original type.
3114 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3115 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3116 widenScalarDst(MI, WideTy);
3117 } else {
3118 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3119 // Explicit extension is required here since high bits affect the result.
3120 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3121 }
3122 Observer.changedInstr(MI);
3123 return Legalized;
3124
3125 case TargetOpcode::G_FPEXT:
3126 if (TypeIdx != 1)
3127 return UnableToLegalize;
3128
3129 Observer.changingInstr(MI);
3130 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3131 Observer.changedInstr(MI);
3132 return Legalized;
3133 case TargetOpcode::G_FPTOSI:
3134 case TargetOpcode::G_FPTOUI:
3135 case TargetOpcode::G_INTRINSIC_LRINT:
3136 case TargetOpcode::G_INTRINSIC_LLRINT:
3137 case TargetOpcode::G_IS_FPCLASS:
3138 Observer.changingInstr(MI);
3139
3140 if (TypeIdx == 0)
3141 widenScalarDst(MI, WideTy);
3142 else
3143 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3144
3145 Observer.changedInstr(MI);
3146 return Legalized;
3147 case TargetOpcode::G_SITOFP:
3148 Observer.changingInstr(MI);
3149
3150 if (TypeIdx == 0)
3151 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3152 else
3153 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3154
3155 Observer.changedInstr(MI);
3156 return Legalized;
3157 case TargetOpcode::G_UITOFP:
3158 Observer.changingInstr(MI);
3159
3160 if (TypeIdx == 0)
3161 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3162 else
3163 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3164
3165 Observer.changedInstr(MI);
3166 return Legalized;
3167 case TargetOpcode::G_FPTOSI_SAT:
3168 case TargetOpcode::G_FPTOUI_SAT:
3169 Observer.changingInstr(MI);
3170
3171 if (TypeIdx == 0) {
3172 Register OldDst = MI.getOperand(0).getReg();
3173 LLT Ty = MRI.getType(OldDst);
3174 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3175 Register NewDst;
3176 MI.getOperand(0).setReg(ExtReg);
3177 uint64_t ShortBits = Ty.getScalarSizeInBits();
3178 uint64_t WideBits = WideTy.getScalarSizeInBits();
3179 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3180 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3181 // z = i16 fptosi_sat(a)
3182 // ->
3183 // x = i32 fptosi_sat(a)
3184 // y = smin(x, 32767)
3185 // z = smax(y, -32768)
3186 auto MaxVal = MIRBuilder.buildConstant(
3187 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3188 auto MinVal = MIRBuilder.buildConstant(
3189 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3190 Register MidReg =
3191 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3192 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3193 } else {
3194 // z = i16 fptoui_sat(a)
3195 // ->
3196 // x = i32 fptoui_sat(a)
3197 // y = smin(x, 65535)
3198 auto MaxVal = MIRBuilder.buildConstant(
3199 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3200 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3201 }
3202 MIRBuilder.buildTrunc(OldDst, NewDst);
3203 } else
3204 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3205
3206 Observer.changedInstr(MI);
3207 return Legalized;
3208 case TargetOpcode::G_LOAD:
3209 case TargetOpcode::G_SEXTLOAD:
3210 case TargetOpcode::G_ZEXTLOAD:
3211 case TargetOpcode::G_FPEXTLOAD:
3212 Observer.changingInstr(MI);
3213 widenScalarDst(MI, WideTy);
3214 Observer.changedInstr(MI);
3215 return Legalized;
3216
3217 case TargetOpcode::G_STORE: {
3218 if (TypeIdx != 0)
3219 return UnableToLegalize;
3220
3221 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3222 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3223 if (!Ty.isScalar()) {
3224 // We need to widen the vector element type.
3225 Observer.changingInstr(MI);
3226 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3227 // We also need to adjust the MMO to turn this into a truncating store.
3228 MachineMemOperand &MMO = **MI.memoperands_begin();
3229 MachineFunction &MF = MIRBuilder.getMF();
3230 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3231 MI.setMemRefs(MF, {NewMMO});
3232 Observer.changedInstr(MI);
3233 return Legalized;
3234 }
3235
3236 Observer.changingInstr(MI);
3237
3238 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3239 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3240 widenScalarSrc(MI, WideTy, 0, ExtType);
3241
3242 Observer.changedInstr(MI);
3243 return Legalized;
3244 }
3245 case TargetOpcode::G_FPTRUNCSTORE:
3246 if (TypeIdx != 0)
3247 return UnableToLegalize;
3248 Observer.changingInstr(MI);
3249 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3250 Observer.changedInstr(MI);
3251 return Legalized;
3252 case TargetOpcode::G_CONSTANT: {
3253 MachineOperand &SrcMO = MI.getOperand(1);
3254 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3255 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3256 MRI.getType(MI.getOperand(0).getReg()));
3257 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3258 ExtOpc == TargetOpcode::G_ANYEXT) &&
3259 "Illegal Extend");
3260 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3261 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3262 ? SrcVal.sext(WideTy.getSizeInBits())
3263 : SrcVal.zext(WideTy.getSizeInBits());
3264 Observer.changingInstr(MI);
3265 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3266
3267 widenScalarDst(MI, WideTy);
3268 Observer.changedInstr(MI);
3269 return Legalized;
3270 }
3271 case TargetOpcode::G_FCONSTANT: {
3272 // To avoid changing the bits of the constant due to extension to a larger
3273 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3274 MachineOperand &SrcMO = MI.getOperand(1);
3275 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3276 MIRBuilder.setInstrAndDebugLoc(MI);
3277 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3278 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3279 MI.eraseFromParent();
3280 return Legalized;
3281 }
3282 case TargetOpcode::G_IMPLICIT_DEF: {
3283 Observer.changingInstr(MI);
3284 widenScalarDst(MI, WideTy);
3285 Observer.changedInstr(MI);
3286 return Legalized;
3287 }
3288 case TargetOpcode::G_BRCOND:
3289 Observer.changingInstr(MI);
3290 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3291 Observer.changedInstr(MI);
3292 return Legalized;
3293
3294 case TargetOpcode::G_FCMP:
3295 Observer.changingInstr(MI);
3296 if (TypeIdx == 0)
3297 widenScalarDst(MI, WideTy);
3298 else {
3299 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3300 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3301 }
3302 Observer.changedInstr(MI);
3303 return Legalized;
3304
3305 case TargetOpcode::G_ICMP:
3306 Observer.changingInstr(MI);
3307 if (TypeIdx == 0)
3308 widenScalarDst(MI, WideTy);
3309 else {
3310 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3311 CmpInst::Predicate Pred =
3312 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3313
3314 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3315 unsigned ExtOpcode =
3316 (CmpInst::isSigned(Pred) ||
3317 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3318 getApproximateEVTForLLT(WideTy, Ctx)))
3319 ? TargetOpcode::G_SEXT
3320 : TargetOpcode::G_ZEXT;
3321 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3322 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3323 }
3324 Observer.changedInstr(MI);
3325 return Legalized;
3326
3327 case TargetOpcode::G_PTR_ADD:
3328 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3329 Observer.changingInstr(MI);
3330 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3331 Observer.changedInstr(MI);
3332 return Legalized;
3333
3334 case TargetOpcode::G_PHI: {
3335 assert(TypeIdx == 0 && "Expecting only Idx 0");
3336
3337 Observer.changingInstr(MI);
3338 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3339 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3340 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3341 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3342 }
3343
3344 MachineBasicBlock &MBB = *MI.getParent();
3345 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3346 widenScalarDst(MI, WideTy);
3347 Observer.changedInstr(MI);
3348 return Legalized;
3349 }
3350 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3351 if (TypeIdx == 0) {
3352 Register VecReg = MI.getOperand(1).getReg();
3353 LLT VecTy = MRI.getType(VecReg);
3354 Observer.changingInstr(MI);
3355
3356 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3357 TargetOpcode::G_ANYEXT);
3358
3359 widenScalarDst(MI, WideTy, 0);
3360 Observer.changedInstr(MI);
3361 return Legalized;
3362 }
3363
3364 if (TypeIdx != 2)
3365 return UnableToLegalize;
3366 Observer.changingInstr(MI);
3367 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3368 Observer.changedInstr(MI);
3369 return Legalized;
3370 }
3371 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3372 if (TypeIdx == 0) {
3373 Observer.changingInstr(MI);
3374 const LLT WideEltTy = WideTy.getElementType();
3375
3376 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3377 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3378 widenScalarDst(MI, WideTy, 0);
3379 Observer.changedInstr(MI);
3380 return Legalized;
3381 }
3382
3383 if (TypeIdx == 1) {
3384 Observer.changingInstr(MI);
3385
3386 Register VecReg = MI.getOperand(1).getReg();
3387 LLT VecTy = MRI.getType(VecReg);
3388 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3389
3390 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3391 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3392 widenScalarDst(MI, WideVecTy, 0);
3393 Observer.changedInstr(MI);
3394 return Legalized;
3395 }
3396
3397 if (TypeIdx == 2) {
3398 Observer.changingInstr(MI);
3399 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3400 Observer.changedInstr(MI);
3401 return Legalized;
3402 }
3403
3404 return UnableToLegalize;
3405 }
3406 case TargetOpcode::G_FADD:
3407 case TargetOpcode::G_FMUL:
3408 case TargetOpcode::G_FSUB:
3409 case TargetOpcode::G_FMA:
3410 case TargetOpcode::G_FMAD:
3411 case TargetOpcode::G_FNEG:
3412 case TargetOpcode::G_FABS:
3413 case TargetOpcode::G_FCANONICALIZE:
3414 case TargetOpcode::G_FMINNUM:
3415 case TargetOpcode::G_FMAXNUM:
3416 case TargetOpcode::G_FMINNUM_IEEE:
3417 case TargetOpcode::G_FMAXNUM_IEEE:
3418 case TargetOpcode::G_FMINIMUM:
3419 case TargetOpcode::G_FMAXIMUM:
3420 case TargetOpcode::G_FMINIMUMNUM:
3421 case TargetOpcode::G_FMAXIMUMNUM:
3422 case TargetOpcode::G_FDIV:
3423 case TargetOpcode::G_FREM:
3424 case TargetOpcode::G_FCEIL:
3425 case TargetOpcode::G_FFLOOR:
3426 case TargetOpcode::G_FCOS:
3427 case TargetOpcode::G_FSIN:
3428 case TargetOpcode::G_FTAN:
3429 case TargetOpcode::G_FACOS:
3430 case TargetOpcode::G_FASIN:
3431 case TargetOpcode::G_FATAN:
3432 case TargetOpcode::G_FATAN2:
3433 case TargetOpcode::G_FCOSH:
3434 case TargetOpcode::G_FSINH:
3435 case TargetOpcode::G_FTANH:
3436 case TargetOpcode::G_FLOG10:
3437 case TargetOpcode::G_FLOG:
3438 case TargetOpcode::G_FLOG2:
3439 case TargetOpcode::G_FRINT:
3440 case TargetOpcode::G_FNEARBYINT:
3441 case TargetOpcode::G_FSQRT:
3442 case TargetOpcode::G_FEXP:
3443 case TargetOpcode::G_FEXP2:
3444 case TargetOpcode::G_FEXP10:
3445 case TargetOpcode::G_FPOW:
3446 case TargetOpcode::G_INTRINSIC_TRUNC:
3447 case TargetOpcode::G_INTRINSIC_ROUND:
3448 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3449 assert(TypeIdx == 0);
3450 Observer.changingInstr(MI);
3451
3452 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3453 widenScalarSrcUsingFPExt(MI, WideTy, I);
3454
3455 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3456 Observer.changedInstr(MI);
3457 return Legalized;
3458 case TargetOpcode::G_FMODF: {
3459 Observer.changingInstr(MI);
3460 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3461
3462 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3463 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3464 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3465 Observer.changedInstr(MI);
3466 return Legalized;
3467 }
3468 case TargetOpcode::G_FPOWI:
3469 case TargetOpcode::G_FLDEXP:
3470 case TargetOpcode::G_STRICT_FLDEXP: {
3471 if (TypeIdx == 0) {
3472 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3473 return UnableToLegalize;
3474
3475 Observer.changingInstr(MI);
3476 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3477 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3478 Observer.changedInstr(MI);
3479 return Legalized;
3480 }
3481
3482 if (TypeIdx == 1) {
3483 // For some reason SelectionDAG tries to promote to a libcall without
3484 // actually changing the integer type for promotion.
3485 Observer.changingInstr(MI);
3486 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3487 Observer.changedInstr(MI);
3488 return Legalized;
3489 }
3490
3491 return UnableToLegalize;
3492 }
3493 case TargetOpcode::G_FFREXP: {
3494 Observer.changingInstr(MI);
3495
3496 if (TypeIdx == 0) {
3497 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3498 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3499 } else {
3500 widenScalarDst(MI, WideTy, 1);
3501 }
3502
3503 Observer.changedInstr(MI);
3504 return Legalized;
3505 }
3506 case TargetOpcode::G_LROUND:
3507 case TargetOpcode::G_LLROUND:
3508 Observer.changingInstr(MI);
3509
3510 if (TypeIdx == 0)
3511 widenScalarDst(MI, WideTy);
3512 else
3513 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3514
3515 Observer.changedInstr(MI);
3516 return Legalized;
3517
3518 case TargetOpcode::G_INTTOPTR:
3519 if (TypeIdx != 1)
3520 return UnableToLegalize;
3521
3522 Observer.changingInstr(MI);
3523 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3524 Observer.changedInstr(MI);
3525 return Legalized;
3526 case TargetOpcode::G_PTRTOINT:
3527 if (TypeIdx != 0)
3528 return UnableToLegalize;
3529
3530 Observer.changingInstr(MI);
3531 widenScalarDst(MI, WideTy, 0);
3532 Observer.changedInstr(MI);
3533 return Legalized;
3534 case TargetOpcode::G_BUILD_VECTOR: {
3535 Observer.changingInstr(MI);
3536
3537 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3538 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3539 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3540
3541 // Avoid changing the result vector type if the source element type was
3542 // requested.
3543 if (TypeIdx == 1) {
3544 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3545 } else {
3546 widenScalarDst(MI, WideTy, 0);
3547 }
3548
3549 Observer.changedInstr(MI);
3550 return Legalized;
3551 }
3552 case TargetOpcode::G_SEXT_INREG:
3553 if (TypeIdx != 0)
3554 return UnableToLegalize;
3555
3556 Observer.changingInstr(MI);
3557 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3558 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3559 Observer.changedInstr(MI);
3560 return Legalized;
3561 case TargetOpcode::G_PTRMASK: {
3562 if (TypeIdx != 1)
3563 return UnableToLegalize;
3564 Observer.changingInstr(MI);
3565 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3566 Observer.changedInstr(MI);
3567 return Legalized;
3568 }
3569 case TargetOpcode::G_VECREDUCE_ADD: {
3570 if (TypeIdx != 1)
3571 return UnableToLegalize;
3572 Observer.changingInstr(MI);
3573 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3574 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3575 Observer.changedInstr(MI);
3576 return Legalized;
3577 }
3578 case TargetOpcode::G_VECREDUCE_FADD:
3579 case TargetOpcode::G_VECREDUCE_FMUL:
3580 case TargetOpcode::G_VECREDUCE_FMIN:
3581 case TargetOpcode::G_VECREDUCE_FMAX:
3582 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3583 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3584 if (TypeIdx != 0)
3585 return UnableToLegalize;
3586 Observer.changingInstr(MI);
3587 Register VecReg = MI.getOperand(1).getReg();
3588 LLT VecTy = MRI.getType(VecReg);
3589 LLT WideVecTy = VecTy.changeElementType(WideTy);
3590 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3591 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3592 Observer.changedInstr(MI);
3593 return Legalized;
3594 }
3595 case TargetOpcode::G_VSCALE: {
3596 MachineOperand &SrcMO = MI.getOperand(1);
3597 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3598 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3599 // The CImm is always a signed value
3600 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3601 Observer.changingInstr(MI);
3602 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3603 widenScalarDst(MI, WideTy);
3604 Observer.changedInstr(MI);
3605 return Legalized;
3606 }
3607 case TargetOpcode::G_SPLAT_VECTOR: {
3608 if (TypeIdx != 1)
3609 return UnableToLegalize;
3610
3611 Observer.changingInstr(MI);
3612 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3613 Observer.changedInstr(MI);
3614 return Legalized;
3615 }
3616 case TargetOpcode::G_INSERT_SUBVECTOR: {
3617 if (TypeIdx != 0)
3618 return UnableToLegalize;
3619
3621 Register BigVec = IS.getBigVec();
3622 Register SubVec = IS.getSubVec();
3623
3624 LLT SubVecTy = MRI.getType(SubVec);
3625 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3626
3627 // Widen the G_INSERT_SUBVECTOR
3628 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3629 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3630 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3631 IS.getIndexImm());
3632
3633 // Truncate back down
3634 auto SplatZero = MIRBuilder.buildSplatVector(
3635 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3636 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3637 SplatZero);
3638
3639 MI.eraseFromParent();
3640
3641 return Legalized;
3642 }
3643 }
3644}
3645
3647 MachineIRBuilder &B, Register Src, LLT Ty) {
3648 auto Unmerge = B.buildUnmerge(Ty, Src);
3649 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3650 Pieces.push_back(Unmerge.getReg(I));
3651}
3652
3653static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3654 MachineIRBuilder &MIRBuilder) {
3655 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3656 MachineFunction &MF = MIRBuilder.getMF();
3657 const DataLayout &DL = MIRBuilder.getDataLayout();
3658 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3659 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3660 LLT DstLLT = MRI.getType(DstReg);
3661
3662 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3663
3664 auto Addr = MIRBuilder.buildConstantPool(
3665 AddrPtrTy,
3666 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3667
3668 MachineMemOperand *MMO =
3670 MachineMemOperand::MOLoad, DstLLT, Alignment);
3671
3672 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3673}
3674
3677 const MachineOperand &ConstOperand = MI.getOperand(1);
3678 const Constant *ConstantVal = ConstOperand.getCImm();
3679
3680 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3681 MI.eraseFromParent();
3682
3683 return Legalized;
3684}
3685
3688 const MachineOperand &ConstOperand = MI.getOperand(1);
3689 const Constant *ConstantVal = ConstOperand.getFPImm();
3690
3691 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3692 MI.eraseFromParent();
3693
3694 return Legalized;
3695}
3696
3699 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3700 if (SrcTy.isVector()) {
3701 LLT SrcEltTy = SrcTy.getElementType();
3703
3704 if (DstTy.isVector()) {
3705 int NumDstElt = DstTy.getNumElements();
3706 int NumSrcElt = SrcTy.getNumElements();
3707
3708 LLT DstEltTy = DstTy.getElementType();
3709 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3710 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3711
3712 // If there's an element size mismatch, insert intermediate casts to match
3713 // the result element type.
3714 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3715 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3716 //
3717 // =>
3718 //
3719 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3720 // %3:_(<2 x s8>) = G_BITCAST %2
3721 // %4:_(<2 x s8>) = G_BITCAST %3
3722 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3723 DstCastTy = DstTy.changeVectorElementCount(
3724 ElementCount::getFixed(NumDstElt / NumSrcElt));
3725 SrcPartTy = SrcEltTy;
3726 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3727 //
3728 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3729 //
3730 // =>
3731 //
3732 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3733 // %3:_(s16) = G_BITCAST %2
3734 // %4:_(s16) = G_BITCAST %3
3735 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3736 SrcPartTy = SrcTy.changeVectorElementCount(
3737 ElementCount::getFixed(NumSrcElt / NumDstElt));
3738 DstCastTy = DstEltTy;
3739 }
3740
3741 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3742 for (Register &SrcReg : SrcRegs)
3743 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3744 } else
3745 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3746
3747 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3748 MI.eraseFromParent();
3749 return Legalized;
3750 }
3751
3752 if (DstTy.isVector()) {
3754 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3755 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3756 MI.eraseFromParent();
3757 return Legalized;
3758 }
3759
3760 return UnableToLegalize;
3761}
3762
3763/// Figure out the bit offset into a register when coercing a vector index for
3764/// the wide element type. This is only for the case when promoting vector to
3765/// one with larger elements.
3766//
3767///
3768/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3769/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3771 Register Idx,
3772 unsigned NewEltSize,
3773 unsigned OldEltSize) {
3774 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3775 LLT IdxTy = B.getMRI()->getType(Idx);
3776
3777 // Now figure out the amount we need to shift to get the target bits.
3778 auto OffsetMask = B.buildConstant(
3779 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3780 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3781 return B.buildShl(IdxTy, OffsetIdx,
3782 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3783}
3784
3785/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3786/// is casting to a vector with a smaller element size, perform multiple element
3787/// extracts and merge the results. If this is coercing to a vector with larger
3788/// elements, index the bitcasted vector and extract the target element with bit
3789/// operations. This is intended to force the indexing in the native register
3790/// size for architectures that can dynamically index the register file.
3793 LLT CastTy) {
3794 if (TypeIdx != 1)
3795 return UnableToLegalize;
3796
3797 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3798
3799 LLT SrcEltTy = SrcVecTy.getElementType();
3800 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3801 unsigned OldNumElts = SrcVecTy.getNumElements();
3802
3803 LLT NewEltTy = CastTy.getScalarType();
3804 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3805
3806 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3807 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3808 if (NewNumElts > OldNumElts) {
3809 // Decreasing the vector element size
3810 //
3811 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3812 // =>
3813 // v4i32:castx = bitcast x:v2i64
3814 //
3815 // i64 = bitcast
3816 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3817 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3818 //
3819 if (NewNumElts % OldNumElts != 0)
3820 return UnableToLegalize;
3821
3822 // Type of the intermediate result vector.
3823 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3824 LLT MidTy =
3825 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3826
3827 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3828
3829 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3830 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3831
3832 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3833 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3834 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3835 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3836 NewOps[I] = Elt.getReg(0);
3837 }
3838
3839 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3840 MIRBuilder.buildBitcast(Dst, NewVec);
3841 MI.eraseFromParent();
3842 return Legalized;
3843 }
3844
3845 if (NewNumElts < OldNumElts) {
3846 if (NewEltSize % OldEltSize != 0)
3847 return UnableToLegalize;
3848
3849 // This only depends on powers of 2 because we use bit tricks to figure out
3850 // the bit offset we need to shift to get the target element. A general
3851 // expansion could emit division/multiply.
3852 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3853 return UnableToLegalize;
3854
3855 // Increasing the vector element size.
3856 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3857 //
3858 // =>
3859 //
3860 // %cast = G_BITCAST %vec
3861 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3862 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3863 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3864 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3865 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3866 // %elt = G_TRUNC %elt_bits
3867
3868 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3869 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3870
3871 // Divide to get the index in the wider element type.
3872 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3873
3874 Register WideElt = CastVec;
3875 if (CastTy.isVector()) {
3876 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3877 ScaledIdx).getReg(0);
3878 }
3879
3880 // Compute the bit offset into the register of the target element.
3882 MIRBuilder, Idx, NewEltSize, OldEltSize);
3883
3884 // Shift the wide element to get the target element.
3885 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3886 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3887 MI.eraseFromParent();
3888 return Legalized;
3889 }
3890
3891 return UnableToLegalize;
3892}
3893
3894/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3895/// TargetReg, while preserving other bits in \p TargetReg.
3896///
3897/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3899 Register TargetReg, Register InsertReg,
3900 Register OffsetBits) {
3901 LLT TargetTy = B.getMRI()->getType(TargetReg);
3902 LLT InsertTy = B.getMRI()->getType(InsertReg);
3903 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3904 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3905
3906 // Produce a bitmask of the value to insert
3907 auto EltMask = B.buildConstant(
3908 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3909 InsertTy.getSizeInBits()));
3910 // Shift it into position
3911 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3912 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3913
3914 // Clear out the bits in the wide element
3915 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3916
3917 // The value to insert has all zeros already, so stick it into the masked
3918 // wide element.
3919 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3920}
3921
3922/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3923/// is increasing the element size, perform the indexing in the target element
3924/// type, and use bit operations to insert at the element position. This is
3925/// intended for architectures that can dynamically index the register file and
3926/// want to force indexing in the native register size.
3929 LLT CastTy) {
3930 if (TypeIdx != 0)
3931 return UnableToLegalize;
3932
3933 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3934 MI.getFirst4RegLLTs();
3935 LLT VecTy = DstTy;
3936
3937 LLT VecEltTy = VecTy.getElementType();
3938 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3939 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3940 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3941
3942 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3943 unsigned OldNumElts = VecTy.getNumElements();
3944
3945 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3946 if (NewNumElts < OldNumElts) {
3947 if (NewEltSize % OldEltSize != 0)
3948 return UnableToLegalize;
3949
3950 // This only depends on powers of 2 because we use bit tricks to figure out
3951 // the bit offset we need to shift to get the target element. A general
3952 // expansion could emit division/multiply.
3953 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3954 return UnableToLegalize;
3955
3956 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3957 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3958
3959 // Divide to get the index in the wider element type.
3960 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3961
3962 Register ExtractedElt = CastVec;
3963 if (CastTy.isVector()) {
3964 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3965 ScaledIdx).getReg(0);
3966 }
3967
3968 // Compute the bit offset into the register of the target element.
3970 MIRBuilder, Idx, NewEltSize, OldEltSize);
3971
3972 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
3973 Val, OffsetBits);
3974 if (CastTy.isVector()) {
3975 InsertedElt = MIRBuilder.buildInsertVectorElement(
3976 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
3977 }
3978
3979 MIRBuilder.buildBitcast(Dst, InsertedElt);
3980 MI.eraseFromParent();
3981 return Legalized;
3982 }
3983
3984 return UnableToLegalize;
3985}
3986
3987// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
3988// those that have smaller than legal operands.
3989//
3990// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
3991//
3992// ===>
3993//
3994// s32 = G_BITCAST <4 x s8>
3995// s32 = G_BITCAST <4 x s8>
3996// s32 = G_BITCAST <4 x s8>
3997// s32 = G_BITCAST <4 x s8>
3998// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
3999// <16 x s8> = G_BITCAST <4 x s32>
4002 LLT CastTy) {
4003 // Convert it to CONCAT instruction
4004 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4005 if (!ConcatMI) {
4006 return UnableToLegalize;
4007 }
4008
4009 // Check if bitcast is Legal
4010 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4011 LLT SrcScalTy = CastTy.getScalarType();
4012
4013 // Check if the build vector is Legal
4014 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4015 return UnableToLegalize;
4016 }
4017
4018 // Bitcast the sources
4019 SmallVector<Register> BitcastRegs;
4020 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4021 BitcastRegs.push_back(
4022 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4023 .getReg(0));
4024 }
4025
4026 // Build the scalar values into a vector
4027 Register BuildReg =
4028 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4029 MIRBuilder.buildBitcast(DstReg, BuildReg);
4030
4031 MI.eraseFromParent();
4032 return Legalized;
4033}
4034
4035// This bitcasts a shuffle vector to a different type currently of the same
4036// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4037// will be used instead.
4038//
4039// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4040// ===>
4041// <4 x s64> = G_PTRTOINT <4 x p0>
4042// <4 x s64> = G_PTRTOINT <4 x p0>
4043// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4044// <16 x p0> = G_INTTOPTR <16 x s64>
4047 LLT CastTy) {
4048 auto ShuffleMI = cast<GShuffleVector>(&MI);
4049 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4050 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4051
4052 // We currently only handle vectors of the same size.
4053 if (TypeIdx != 0 ||
4054 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4055 CastTy.getElementCount() != DstTy.getElementCount())
4056 return UnableToLegalize;
4057
4058 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4059
4060 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4061 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4062 auto Shuf =
4063 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4064 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4065
4066 MI.eraseFromParent();
4067 return Legalized;
4068}
4069
4070/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4071///
4072/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4073///
4074/// ===>
4075///
4076/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4077/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4078/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4081 LLT CastTy) {
4082 auto ES = cast<GExtractSubvector>(&MI);
4083
4084 if (!CastTy.isVector())
4085 return UnableToLegalize;
4086
4087 if (TypeIdx != 0)
4088 return UnableToLegalize;
4089
4090 Register Dst = ES->getReg(0);
4091 Register Src = ES->getSrcVec();
4092 uint64_t Idx = ES->getIndexImm();
4093
4094 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4095
4096 LLT DstTy = MRI.getType(Dst);
4097 LLT SrcTy = MRI.getType(Src);
4098 ElementCount DstTyEC = DstTy.getElementCount();
4099 ElementCount SrcTyEC = SrcTy.getElementCount();
4100 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4101 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4102
4103 if (DstTy == CastTy)
4104 return Legalized;
4105
4106 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4107 return UnableToLegalize;
4108
4109 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4110 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4111 if (CastEltSize < DstEltSize)
4112 return UnableToLegalize;
4113
4114 auto AdjustAmt = CastEltSize / DstEltSize;
4115 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4116 SrcTyMinElts % AdjustAmt != 0)
4117 return UnableToLegalize;
4118
4119 Idx /= AdjustAmt;
4120 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4121 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4122 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4123 MIRBuilder.buildBitcast(Dst, PromotedES);
4124
4125 ES->eraseFromParent();
4126 return Legalized;
4127}
4128
4129/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4130///
4131/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4132/// <vscale x 8 x i1>,
4133/// N
4134///
4135/// ===>
4136///
4137/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4138/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4139/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4140/// <vscale x 1 x i8>, N / 8
4141/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4144 LLT CastTy) {
4145 auto ES = cast<GInsertSubvector>(&MI);
4146
4147 if (!CastTy.isVector())
4148 return UnableToLegalize;
4149
4150 if (TypeIdx != 0)
4151 return UnableToLegalize;
4152
4153 Register Dst = ES->getReg(0);
4154 Register BigVec = ES->getBigVec();
4155 Register SubVec = ES->getSubVec();
4156 uint64_t Idx = ES->getIndexImm();
4157
4158 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4159
4160 LLT DstTy = MRI.getType(Dst);
4161 LLT BigVecTy = MRI.getType(BigVec);
4162 LLT SubVecTy = MRI.getType(SubVec);
4163
4164 if (DstTy == CastTy)
4165 return Legalized;
4166
4167 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4168 return UnableToLegalize;
4169
4170 ElementCount DstTyEC = DstTy.getElementCount();
4171 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4172 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4173 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4174 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4175 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4176
4177 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4178 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4179 if (CastEltSize < DstEltSize)
4180 return UnableToLegalize;
4181
4182 auto AdjustAmt = CastEltSize / DstEltSize;
4183 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4184 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4185 return UnableToLegalize;
4186
4187 Idx /= AdjustAmt;
4188 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4189 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4190 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4191 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4192 auto PromotedIS =
4193 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4194 MIRBuilder.buildBitcast(Dst, PromotedIS);
4195
4196 ES->eraseFromParent();
4197 return Legalized;
4198}
4199
4201 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4202 Register DstReg = LoadMI.getDstReg();
4203 Register PtrReg = LoadMI.getPointerReg();
4204 LLT DstTy = MRI.getType(DstReg);
4205 MachineMemOperand &MMO = LoadMI.getMMO();
4206 LLT MemTy = MMO.getMemoryType();
4207 MachineFunction &MF = MIRBuilder.getMF();
4208
4209 LLT EltTy = MemTy.getScalarType();
4210
4211 unsigned MemSizeInBits = MemTy.getSizeInBits();
4212 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4213
4214 if (MemSizeInBits != MemStoreSizeInBits) {
4215 if (MemTy.isVector())
4216 return UnableToLegalize;
4217
4218 // Promote to a byte-sized load if not loading an integral number of
4219 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4220 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4221 MachineMemOperand *NewMMO =
4222 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4223
4224 Register LoadReg = DstReg;
4225 LLT LoadTy = DstTy;
4226
4227 // If this wasn't already an extending load, we need to widen the result
4228 // register to avoid creating a load with a narrower result than the source.
4229 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4230 LoadTy = WideMemTy;
4231 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4232 }
4233
4234 if (isa<GSExtLoad>(LoadMI)) {
4235 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4236 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4237 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4238 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4239 // The extra bits are guaranteed to be zero, since we stored them that
4240 // way. A zext load from Wide thus automatically gives zext from MemVT.
4241 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4242 } else {
4243 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4244 }
4245
4246 if (DstTy != LoadTy)
4247 MIRBuilder.buildTrunc(DstReg, LoadReg);
4248
4249 LoadMI.eraseFromParent();
4250 return Legalized;
4251 }
4252
4253 // Big endian lowering not implemented.
4254 if (MIRBuilder.getDataLayout().isBigEndian())
4255 return UnableToLegalize;
4256
4257 // This load needs splitting into power of 2 sized loads.
4258 //
4259 // Our strategy here is to generate anyextending loads for the smaller
4260 // types up to next power-2 result type, and then combine the two larger
4261 // result values together, before truncating back down to the non-pow-2
4262 // type.
4263 // E.g. v1 = i24 load =>
4264 // v2 = i32 zextload (2 byte)
4265 // v3 = i32 load (1 byte)
4266 // v4 = i32 shl v3, 16
4267 // v5 = i32 or v4, v2
4268 // v1 = i24 trunc v5
4269 // By doing this we generate the correct truncate which should get
4270 // combined away as an artifact with a matching extend.
4271
4272 uint64_t LargeSplitSize, SmallSplitSize;
4273
4274 if (!isPowerOf2_32(MemSizeInBits)) {
4275 // This load needs splitting into power of 2 sized loads.
4276 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4277 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4278 } else {
4279 // This is already a power of 2, but we still need to split this in half.
4280 //
4281 // Assume we're being asked to decompose an unaligned load.
4282 // TODO: If this requires multiple splits, handle them all at once.
4283 auto &Ctx = MF.getFunction().getContext();
4284 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4285 return UnableToLegalize;
4286
4287 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4288 }
4289
4290 if (MemTy.isVector()) {
4291 // TODO: Handle vector extloads
4292 if (MemTy != DstTy)
4293 return UnableToLegalize;
4294
4295 Align Alignment = LoadMI.getAlign();
4296 // Given an alignment larger than the size of the memory, we can increase
4297 // the size of the load without needing to scalarize it.
4298 if (Alignment.value() * 8 > MemSizeInBits &&
4300 LLT MoreTy = DstTy.changeVectorElementCount(
4302 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4303 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4304 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4305 NewLoad.getReg(0));
4306 LoadMI.eraseFromParent();
4307 return Legalized;
4308 }
4309
4310 // TODO: We can do better than scalarizing the vector and at least split it
4311 // in half.
4312 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4313 }
4314
4315 MachineMemOperand *LargeMMO =
4316 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4317 MachineMemOperand *SmallMMO =
4318 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4319
4320 LLT PtrTy = MRI.getType(PtrReg);
4321 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4322
4323 LLT AnyExtTy;
4324 LLT OffsetCstRes;
4325 if (EltTy.isPointer()) {
4326 AnyExtTy = LLT::scalar(AnyExtSize);
4327 OffsetCstRes = LLT::scalar(PtrTy.getSizeInBits());
4328 } else {
4329 AnyExtTy = DstTy.changeElementSize(AnyExtSize);
4330 OffsetCstRes = DstTy.changeElementSize(PtrTy.getSizeInBits());
4331 }
4332
4333 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4334 PtrReg, *LargeMMO);
4335
4336 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4337 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4338 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4339 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4340 SmallPtr, *SmallMMO);
4341
4342 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4343 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4344
4345 if (AnyExtTy == DstTy)
4346 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4347 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4348 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4349 MIRBuilder.buildTrunc(DstReg, {Or});
4350 } else {
4351 assert(DstTy.isPointer() && "expected pointer");
4352 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4353
4354 // FIXME: We currently consider this to be illegal for non-integral address
4355 // spaces, but we need still need a way to reinterpret the bits.
4356 MIRBuilder.buildIntToPtr(DstReg, Or);
4357 }
4358
4359 LoadMI.eraseFromParent();
4360 return Legalized;
4361}
4362
4364 // Lower a non-power of 2 store into multiple pow-2 stores.
4365 // E.g. split an i24 store into an i16 store + i8 store.
4366 // We do this by first extending the stored value to the next largest power
4367 // of 2 type, and then using truncating stores to store the components.
4368 // By doing this, likewise with G_LOAD, generate an extend that can be
4369 // artifact-combined away instead of leaving behind extracts.
4370 Register SrcReg = StoreMI.getValueReg();
4371 Register PtrReg = StoreMI.getPointerReg();
4372 LLT SrcTy = MRI.getType(SrcReg);
4373 MachineFunction &MF = MIRBuilder.getMF();
4374 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4375 LLT MemTy = MMO.getMemoryType();
4376
4377 unsigned StoreWidth = MemTy.getSizeInBits();
4378 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4379
4380 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4381 // Promote to a byte-sized store with upper bits zero if not
4382 // storing an integral number of bytes. For example, promote
4383 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4384 LLT WideTy = LLT::integer(StoreSizeInBits);
4385
4386 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4387 // Avoid creating a store with a narrower source than result.
4388 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4389 SrcTy = WideTy;
4390 }
4391
4392 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4393
4394 MachineMemOperand *NewMMO =
4395 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4396 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4397 StoreMI.eraseFromParent();
4398 return Legalized;
4399 }
4400
4401 if (MemTy.isVector()) {
4402 if (MemTy != SrcTy)
4403 return scalarizeVectorBooleanStore(StoreMI);
4404
4405 // TODO: We can do better than scalarizing the vector and at least split it
4406 // in half.
4407 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4408 }
4409
4410 unsigned MemSizeInBits = MemTy.getSizeInBits();
4411 uint64_t LargeSplitSize, SmallSplitSize;
4412
4413 if (!isPowerOf2_32(MemSizeInBits)) {
4414 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4415 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4416 } else {
4417 auto &Ctx = MF.getFunction().getContext();
4418 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4419 return UnableToLegalize; // Don't know what we're being asked to do.
4420
4421 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4422 }
4423
4424 // Extend to the next pow-2. If this store was itself the result of lowering,
4425 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4426 // that's wider than the stored size.
4427 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4428 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4429
4430 if (SrcTy.isPointer()) {
4431 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4432 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4433 }
4434
4435 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4436
4437 // Obtain the smaller value by shifting away the larger value.
4438 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4439 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4440
4441 // Generate the PtrAdd and truncating stores.
4442 LLT PtrTy = MRI.getType(PtrReg);
4443 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4444 LargeSplitSize / 8);
4445 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4446
4447 MachineMemOperand *LargeMMO =
4448 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4449 MachineMemOperand *SmallMMO =
4450 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4451 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4452 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4453 StoreMI.eraseFromParent();
4454 return Legalized;
4455}
4456
4459 Register SrcReg = StoreMI.getValueReg();
4460 Register PtrReg = StoreMI.getPointerReg();
4461 LLT SrcTy = MRI.getType(SrcReg);
4462 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4463 LLT MemTy = MMO.getMemoryType();
4464 LLT MemScalarTy = MemTy.getElementType();
4465 MachineFunction &MF = MIRBuilder.getMF();
4466
4467 assert(SrcTy.isVector() && "Expect a vector store type");
4468
4469 if (!MemScalarTy.isByteSized()) {
4470 // We need to build an integer scalar of the vector bit pattern.
4471 // It's not legal for us to add padding when storing a vector.
4472 unsigned NumBits = MemTy.getSizeInBits();
4473 LLT IntTy = LLT::integer(NumBits);
4474 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4475 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4476
4477 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4478 auto Elt = MIRBuilder.buildExtractVectorElement(
4479 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4480 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4481 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4482 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4483 ? (MemTy.getNumElements() - 1) - I
4484 : I;
4485 auto ShiftAmt = MIRBuilder.buildConstant(
4486 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4487 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4488 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4489 }
4490 auto PtrInfo = MMO.getPointerInfo();
4491 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4492 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4493 StoreMI.eraseFromParent();
4494 return Legalized;
4495 }
4496
4497 // TODO: implement simple scalarization.
4498 return UnableToLegalize;
4499}
4500
4502LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4503 switch (MI.getOpcode()) {
4504 case TargetOpcode::G_LOAD: {
4505 if (TypeIdx != 0)
4506 return UnableToLegalize;
4507 MachineMemOperand &MMO = **MI.memoperands_begin();
4508
4509 // Not sure how to interpret a bitcast of an extending load.
4510 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4511 return UnableToLegalize;
4512
4513 Observer.changingInstr(MI);
4514 bitcastDst(MI, CastTy, 0);
4515 MMO.setType(CastTy);
4516 // The range metadata is no longer valid when reinterpreted as a different
4517 // type.
4518 MMO.clearRanges();
4519 Observer.changedInstr(MI);
4520 return Legalized;
4521 }
4522 case TargetOpcode::G_STORE: {
4523 if (TypeIdx != 0)
4524 return UnableToLegalize;
4525
4526 MachineMemOperand &MMO = **MI.memoperands_begin();
4527
4528 // Not sure how to interpret a bitcast of a truncating store.
4529 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4530 return UnableToLegalize;
4531
4532 Observer.changingInstr(MI);
4533 bitcastSrc(MI, CastTy, 0);
4534 MMO.setType(CastTy);
4535 Observer.changedInstr(MI);
4536 return Legalized;
4537 }
4538 case TargetOpcode::G_SELECT: {
4539 if (TypeIdx != 0)
4540 return UnableToLegalize;
4541
4542 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4543 LLVM_DEBUG(
4544 dbgs() << "bitcast action not implemented for vector select\n");
4545 return UnableToLegalize;
4546 }
4547
4548 Observer.changingInstr(MI);
4549 bitcastSrc(MI, CastTy, 2);
4550 bitcastSrc(MI, CastTy, 3);
4551 bitcastDst(MI, CastTy, 0);
4552 Observer.changedInstr(MI);
4553 return Legalized;
4554 }
4555 case TargetOpcode::G_AND:
4556 case TargetOpcode::G_OR:
4557 case TargetOpcode::G_XOR: {
4558 Observer.changingInstr(MI);
4559 bitcastSrc(MI, CastTy, 1);
4560 bitcastSrc(MI, CastTy, 2);
4561 bitcastDst(MI, CastTy, 0);
4562 Observer.changedInstr(MI);
4563 return Legalized;
4564 }
4565 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4566 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4567 case TargetOpcode::G_INSERT_VECTOR_ELT:
4568 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4569 case TargetOpcode::G_CONCAT_VECTORS:
4570 return bitcastConcatVector(MI, TypeIdx, CastTy);
4571 case TargetOpcode::G_SHUFFLE_VECTOR:
4572 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4573 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4574 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4575 case TargetOpcode::G_INSERT_SUBVECTOR:
4576 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4577 default:
4578 return UnableToLegalize;
4579 }
4580}
4581
4582// Legalize an instruction by changing the opcode in place.
4583void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4585 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4587}
4588
4590LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4591 using namespace TargetOpcode;
4592 switch(MI.getOpcode()) {
4593 default:
4594 return UnableToLegalize;
4595 case TargetOpcode::G_FCONSTANT:
4596 return lowerFConstant(MI);
4597 case TargetOpcode::G_BITCAST:
4598 return lowerBitcast(MI);
4599 case TargetOpcode::G_SREM:
4600 case TargetOpcode::G_UREM: {
4601 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4602 auto Quot =
4603 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4604 {MI.getOperand(1), MI.getOperand(2)});
4605
4606 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4607 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4608 MI.eraseFromParent();
4609 return Legalized;
4610 }
4611 case TargetOpcode::G_SADDO:
4612 case TargetOpcode::G_SSUBO:
4613 return lowerSADDO_SSUBO(MI);
4614 case TargetOpcode::G_SADDE:
4615 return lowerSADDE(MI);
4616 case TargetOpcode::G_SSUBE:
4617 return lowerSSUBE(MI);
4618 case TargetOpcode::G_UMULH:
4619 case TargetOpcode::G_SMULH:
4620 return lowerSMULH_UMULH(MI);
4621 case TargetOpcode::G_SMULO:
4622 case TargetOpcode::G_UMULO: {
4623 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4624 // result.
4625 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4626 LLT Ty = MRI.getType(Res);
4627
4628 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4629 ? TargetOpcode::G_SMULH
4630 : TargetOpcode::G_UMULH;
4631
4632 Observer.changingInstr(MI);
4633 const auto &TII = MIRBuilder.getTII();
4634 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4635 MI.removeOperand(1);
4636 Observer.changedInstr(MI);
4637
4638 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4639 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4640
4641 // Move insert point forward so we can use the Res register if needed.
4642 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4643
4644 // For *signed* multiply, overflow is detected by checking:
4645 // (hi != (lo >> bitwidth-1))
4646 if (Opcode == TargetOpcode::G_SMULH) {
4647 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4648 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4649 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4650 } else {
4651 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4652 }
4653 return Legalized;
4654 }
4655 case TargetOpcode::G_FNEG: {
4656 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4657 LLT TyInt =
4658 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4659 Register CastedSubByReg = SubByReg;
4660
4661 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4662 !SubByRegTy.getScalarType().isInteger()) {
4663 auto BitcastDst = SubByRegTy.changeElementType(
4664 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4665 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4666 }
4667
4668 auto SignMask = MIRBuilder.buildConstant(
4669 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4670
4671 if (ResTy != TyInt) {
4672 Register NewDst =
4673 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4674 MIRBuilder.buildBitcast(Res, NewDst);
4675 } else
4676 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4677
4678 MI.eraseFromParent();
4679 return Legalized;
4680 }
4681 case TargetOpcode::G_FSUB:
4682 case TargetOpcode::G_STRICT_FSUB: {
4683 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4684 LLT Ty = MRI.getType(Res);
4685
4686 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4687 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4688
4689 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4690 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4691 else
4692 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4693
4694 MI.eraseFromParent();
4695 return Legalized;
4696 }
4697 case TargetOpcode::G_FMAD:
4698 return lowerFMad(MI);
4699 case TargetOpcode::G_FFLOOR:
4700 return lowerFFloor(MI);
4701 case TargetOpcode::G_LROUND:
4702 case TargetOpcode::G_LLROUND: {
4703 Register DstReg = MI.getOperand(0).getReg();
4704 Register SrcReg = MI.getOperand(1).getReg();
4705 LLT SrcTy = MRI.getType(SrcReg);
4706 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4707 {SrcReg});
4708 MIRBuilder.buildFPTOSI(DstReg, Round);
4709 MI.eraseFromParent();
4710 return Legalized;
4711 }
4712 case TargetOpcode::G_INTRINSIC_ROUND:
4713 return lowerIntrinsicRound(MI);
4714 case TargetOpcode::G_FRINT: {
4715 // Since round even is the assumed rounding mode for unconstrained FP
4716 // operations, rint and roundeven are the same operation.
4717 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4718 return Legalized;
4719 }
4720 case TargetOpcode::G_INTRINSIC_LRINT:
4721 case TargetOpcode::G_INTRINSIC_LLRINT: {
4722 Register DstReg = MI.getOperand(0).getReg();
4723 Register SrcReg = MI.getOperand(1).getReg();
4724 LLT SrcTy = MRI.getType(SrcReg);
4725 auto Round =
4726 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4727 MIRBuilder.buildFPTOSI(DstReg, Round);
4728 MI.eraseFromParent();
4729 return Legalized;
4730 }
4731 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4732 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4733 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4734 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4735 **MI.memoperands_begin());
4736 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4737 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4738 MI.eraseFromParent();
4739 return Legalized;
4740 }
4741 case TargetOpcode::G_LOAD:
4742 case TargetOpcode::G_SEXTLOAD:
4743 case TargetOpcode::G_ZEXTLOAD:
4744 return lowerLoad(cast<GAnyLoad>(MI));
4745 case TargetOpcode::G_STORE:
4746 return lowerStore(cast<GStore>(MI));
4747 case TargetOpcode::G_CTLZ_ZERO_POISON:
4748 case TargetOpcode::G_CTTZ_ZERO_POISON:
4749 case TargetOpcode::G_CTLZ:
4750 case TargetOpcode::G_CTTZ:
4751 case TargetOpcode::G_CTPOP:
4752 case TargetOpcode::G_CTLS:
4753 return lowerBitCount(MI);
4754 case G_UADDO: {
4755 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4756
4757 Register NewRes = MRI.cloneVirtualRegister(Res);
4758
4759 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4760 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4761
4762 MIRBuilder.buildCopy(Res, NewRes);
4763
4764 MI.eraseFromParent();
4765 return Legalized;
4766 }
4767 case G_UADDE: {
4768 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4769 const LLT CondTy = MRI.getType(CarryOut);
4770 const LLT Ty = MRI.getType(Res);
4771
4772 Register NewRes = MRI.cloneVirtualRegister(Res);
4773
4774 // Initial add of the two operands.
4775 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4776
4777 // Initial check for carry.
4778 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4779
4780 // Add the sum and the carry.
4781 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4782 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4783
4784 // Second check for carry. We can only carry if the initial sum is all 1s
4785 // and the carry is set, resulting in a new sum of 0.
4786 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4787 auto ResEqZero =
4788 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4789 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4790 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4791
4792 MIRBuilder.buildCopy(Res, NewRes);
4793
4794 MI.eraseFromParent();
4795 return Legalized;
4796 }
4797 case G_USUBO: {
4798 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4799
4800 MIRBuilder.buildSub(Res, LHS, RHS);
4801 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4802
4803 MI.eraseFromParent();
4804 return Legalized;
4805 }
4806 case G_USUBE: {
4807 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4808 const LLT CondTy = MRI.getType(BorrowOut);
4809 const LLT Ty = MRI.getType(Res);
4810
4811 // Initial subtract of the two operands.
4812 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4813
4814 // Initial check for borrow.
4815 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4816
4817 // Subtract the borrow from the first subtract.
4818 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4819 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4820
4821 // Second check for borrow. We can only borrow if the initial difference is
4822 // 0 and the borrow is set, resulting in a new difference of all 1s.
4823 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4824 auto TmpResEqZero =
4825 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4826 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4827 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4828
4829 MI.eraseFromParent();
4830 return Legalized;
4831 }
4832 case G_UITOFP:
4833 return lowerUITOFP(MI);
4834 case G_SITOFP:
4835 return lowerSITOFP(MI);
4836 case G_FPTOUI:
4837 return lowerFPTOUI(MI);
4838 case G_FPTOSI:
4839 return lowerFPTOSI(MI);
4840 case G_FPTOUI_SAT:
4841 case G_FPTOSI_SAT:
4842 return lowerFPTOINT_SAT(MI);
4843 case G_FPEXT:
4844 return lowerFPExtAndTruncMem(MI);
4845 case G_FPTRUNC:
4846 return lowerFPTRUNC(MI);
4847 case G_FPOWI:
4848 return lowerFPOWI(MI);
4849 case G_FMODF:
4850 return lowerFMODF(MI);
4851 case G_SMIN:
4852 case G_SMAX:
4853 case G_UMIN:
4854 case G_UMAX:
4855 return lowerMinMax(MI);
4856 case G_SCMP:
4857 case G_UCMP:
4858 return lowerThreewayCompare(MI);
4859 case G_FCOPYSIGN:
4860 return lowerFCopySign(MI);
4861 case G_FMINNUM:
4862 case G_FMAXNUM:
4863 case G_FMINIMUMNUM:
4864 case G_FMAXIMUMNUM:
4865 return lowerFMinNumMaxNum(MI);
4866 case G_FMINIMUM:
4867 case G_FMAXIMUM:
4868 return lowerFMinimumMaximum(MI);
4869 case G_MERGE_VALUES:
4870 return lowerMergeValues(MI);
4871 case G_UNMERGE_VALUES:
4872 return lowerUnmergeValues(MI);
4873 case TargetOpcode::G_SEXT_INREG: {
4874 assert(MI.getOperand(2).isImm() && "Expected immediate");
4875 int64_t SizeInBits = MI.getOperand(2).getImm();
4876
4877 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4878 LLT DstTy = MRI.getType(DstReg);
4879 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4880
4881 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4882 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4883 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4884 MI.eraseFromParent();
4885 return Legalized;
4886 }
4887 case G_EXTRACT_VECTOR_ELT:
4888 case G_INSERT_VECTOR_ELT:
4890 case G_SHUFFLE_VECTOR:
4891 return lowerShuffleVector(MI);
4892 case G_VECTOR_COMPRESS:
4893 return lowerVECTOR_COMPRESS(MI);
4894 case G_DYN_STACKALLOC:
4895 return lowerDynStackAlloc(MI);
4896 case G_INSERT_SUBVECTOR: {
4897 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
4898 MRI.getType(MI.getOperand(2).getReg()).isScalable())
4899 return UnableToLegalize;
4900
4901 // Check that subvector is half size of main vector
4902 Register Vector = MI.getOperand(1).getReg();
4903 Register Subvector = MI.getOperand(2).getReg();
4904 auto InsertionPointImm = MI.getOperand(3).getImm();
4905
4906 LLT VectorTy = MRI.getType(Vector);
4907 LLT SubvectorTy = MRI.getType(Subvector);
4908 // If so, -> concat(subvector, extract(half of vector))
4909 // (Operands can be either way round depending on insertion point
4910 if (VectorTy.getSizeInBits() == SubvectorTy.getSizeInBits() * 2) {
4911 bool InsertInLowHalf = InsertionPointImm == 0;
4912 auto Extract = MIRBuilder.buildExtractSubvector(
4913 SubvectorTy, Vector,
4914 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
4915
4916 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
4917 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
4918
4919 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
4920 {LowHalf, HighHalf});
4921 MI.eraseFromParent();
4922 return Legalized;
4923 }
4924 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
4925 else {
4926 // Extend subvector to same size as vector
4927 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
4928 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
4929
4930 // Calculate mask required for this shuffle
4931 SmallVector<int> Mask;
4932 for (int i = 0; i < VectorTy.getNumElements(); i++) {
4933 // If this index is within bounds, put subvector's index into mask
4934 if (i >= InsertionPointImm &&
4935 i < InsertionPointImm + SubvectorTy.getNumElements())
4936 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
4937 else
4938 Mask.push_back(i);
4939 }
4940
4941 // Build shuffle
4942 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
4943 Mask);
4944 MI.eraseFromParent();
4945 return Legalized;
4946 }
4947 }
4948 case G_STACKSAVE:
4949 return lowerStackSave(MI);
4950 case G_STACKRESTORE:
4951 return lowerStackRestore(MI);
4952 case G_EXTRACT:
4953 return lowerExtract(MI);
4954 case G_INSERT:
4955 return lowerInsert(MI);
4956 case G_BSWAP:
4957 return lowerBswap(MI);
4958 case G_BITREVERSE:
4959 return lowerBitreverse(MI);
4960 case G_READ_REGISTER:
4961 case G_WRITE_REGISTER:
4962 return lowerReadWriteRegister(MI);
4963 case G_UADDSAT:
4964 case G_USUBSAT: {
4965 // Try to make a reasonable guess about which lowering strategy to use. The
4966 // target can override this with custom lowering and calling the
4967 // implementation functions.
4968 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4969 if (LI.isLegalOrCustom({G_UMIN, Ty}))
4970 return lowerAddSubSatToMinMax(MI);
4972 }
4973 case G_SADDSAT:
4974 case G_SSUBSAT: {
4975 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4976
4977 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
4978 // since it's a shorter expansion. However, we would need to figure out the
4979 // preferred boolean type for the carry out for the query.
4980 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
4981 return lowerAddSubSatToMinMax(MI);
4983 }
4984 case G_SSHLSAT:
4985 case G_USHLSAT:
4986 return lowerShlSat(MI);
4987 case G_ABS:
4988 return lowerAbsToAddXor(MI);
4989 case G_ABDS:
4990 case G_ABDU: {
4991 bool IsSigned = MI.getOpcode() == G_ABDS;
4992 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4993 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
4994 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
4995 return lowerAbsDiffToMinMax(MI);
4996 }
4997 return lowerAbsDiffToSelect(MI);
4998 }
4999 case G_FABS:
5000 return lowerFAbs(MI);
5001 case G_SELECT:
5002 return lowerSelect(MI);
5003 case G_IS_FPCLASS:
5004 return lowerISFPCLASS(MI);
5005 case G_SDIVREM:
5006 case G_UDIVREM:
5007 return lowerDIVREM(MI);
5008 case G_FSHL:
5009 case G_FSHR:
5010 return lowerFunnelShift(MI);
5011 case G_ROTL:
5012 case G_ROTR:
5013 return lowerRotate(MI);
5014 case G_MEMSET:
5015 case G_MEMCPY:
5016 case G_MEMMOVE:
5017 case G_MEMCPY_INLINE:
5018 case G_MEMSET_INLINE:
5019 return lowerMemCpyFamily(MI);
5020 case G_ZEXT:
5021 case G_SEXT:
5022 case G_ANYEXT:
5023 return lowerEXT(MI);
5024 case G_TRUNC:
5025 return lowerTRUNC(MI);
5027 return lowerVectorReduction(MI);
5028 case G_VAARG:
5029 return lowerVAArg(MI);
5030 case G_ATOMICRMW_SUB: {
5031 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5032 const LLT ValTy = MRI.getType(Val);
5033 MachineMemOperand *MMO = *MI.memoperands_begin();
5034
5035 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5036 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5037 MI.eraseFromParent();
5038 return Legalized;
5039 }
5040 case G_SMULFIX:
5041 case G_UMULFIX:
5042 return lowerMulfix(MI);
5043 }
5044}
5045
5047 Align MinAlign) const {
5048 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5049 // datalayout for the preferred alignment. Also there should be a target hook
5050 // for this to allow targets to reduce the alignment and ignore the
5051 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5052 // the type.
5053 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5054}
5055
5058 MachinePointerInfo &PtrInfo) {
5059 MachineFunction &MF = MIRBuilder.getMF();
5060 const DataLayout &DL = MIRBuilder.getDataLayout();
5061 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5062
5063 unsigned AddrSpace = DL.getAllocaAddrSpace();
5064 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5065
5066 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5067 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5068}
5069
5071 const SrcOp &Val) {
5072 LLT SrcTy = Val.getLLTTy(MRI);
5073 Align StackTypeAlign =
5074 std::max(getStackTemporaryAlignment(SrcTy),
5076 MachinePointerInfo PtrInfo;
5077 auto StackTemp =
5078 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5079
5080 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5081 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5082}
5083
5085 LLT VecTy) {
5086 LLT IdxTy = B.getMRI()->getType(IdxReg);
5087 unsigned NElts = VecTy.getNumElements();
5088
5089 int64_t IdxVal;
5090 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5091 if (IdxVal < VecTy.getNumElements())
5092 return IdxReg;
5093 // If a constant index would be out of bounds, clamp it as well.
5094 }
5095
5096 if (isPowerOf2_32(NElts)) {
5097 APInt Imm = APInt::getLowBitsSet(IdxTy.getSizeInBits(), Log2_32(NElts));
5098 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5099 }
5100
5101 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5102 .getReg(0);
5103}
5104
5106 Register Index) {
5107 LLT EltTy = VecTy.getElementType();
5108
5109 // Calculate the element offset and add it to the pointer.
5110 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5111 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5112 "Converting bits to bytes lost precision");
5113
5114 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5115
5116 // Convert index to the correct size for the address space.
5117 const DataLayout &DL = MIRBuilder.getDataLayout();
5118 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5119 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5120 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5121 if (IdxTy != MRI.getType(Index))
5122 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5123
5124 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5125 MIRBuilder.buildConstant(IdxTy, EltSize));
5126
5127 LLT PtrTy = MRI.getType(VecPtr);
5128 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5129}
5130
5131#ifndef NDEBUG
5132/// Check that all vector operands have same number of elements. Other operands
5133/// should be listed in NonVecOp.
5136 std::initializer_list<unsigned> NonVecOpIndices) {
5137 if (MI.getNumMemOperands() != 0)
5138 return false;
5139
5140 LLT VecTy = MRI.getType(MI.getReg(0));
5141 if (!VecTy.isVector())
5142 return false;
5143 unsigned NumElts = VecTy.getNumElements();
5144
5145 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5146 MachineOperand &Op = MI.getOperand(OpIdx);
5147 if (!Op.isReg()) {
5148 if (!is_contained(NonVecOpIndices, OpIdx))
5149 return false;
5150 continue;
5151 }
5152
5153 LLT Ty = MRI.getType(Op.getReg());
5154 if (!Ty.isVector()) {
5155 if (!is_contained(NonVecOpIndices, OpIdx))
5156 return false;
5157 continue;
5158 }
5159
5160 if (Ty.getNumElements() != NumElts)
5161 return false;
5162 }
5163
5164 return true;
5165}
5166#endif
5167
5168/// Fill \p DstOps with DstOps that have same number of elements combined as
5169/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5170/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5171/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5172static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5173 unsigned NumElts) {
5174 LLT LeftoverTy;
5175 assert(Ty.isVector() && "Expected vector type");
5176 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5177 int NumParts, NumLeftover;
5178 std::tie(NumParts, NumLeftover) =
5179 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5180
5181 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5182 for (int i = 0; i < NumParts; ++i) {
5183 DstOps.push_back(NarrowTy);
5184 }
5185
5186 if (LeftoverTy.isValid()) {
5187 assert(NumLeftover == 1 && "expected exactly one leftover");
5188 DstOps.push_back(LeftoverTy);
5189 }
5190}
5191
5192/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5193/// made from \p Op depending on operand type.
5195 MachineOperand &Op) {
5196 for (unsigned i = 0; i < N; ++i) {
5197 if (Op.isReg())
5198 Ops.push_back(Op.getReg());
5199 else if (Op.isImm())
5200 Ops.push_back(Op.getImm());
5201 else if (Op.isPredicate())
5202 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5203 else
5204 llvm_unreachable("Unsupported type");
5205 }
5206}
5207
5208// Handle splitting vector operations which need to have the same number of
5209// elements in each type index, but each type index may have a different element
5210// type.
5211//
5212// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5213// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5214// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5215//
5216// Also handles some irregular breakdown cases, e.g.
5217// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5218// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5219// s64 = G_SHL s64, s32
5222 GenericMachineInstr &MI, unsigned NumElts,
5223 std::initializer_list<unsigned> NonVecOpIndices) {
5224 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5225 "Non-compatible opcode or not specified non-vector operands");
5226 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5227
5228 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5229 unsigned NumDefs = MI.getNumDefs();
5230
5231 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5232 // Build instructions with DstOps to use instruction found by CSE directly.
5233 // CSE copies found instruction into given vreg when building with vreg dest.
5234 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5235 // Output registers will be taken from created instructions.
5236 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5237 for (unsigned i = 0; i < NumDefs; ++i) {
5238 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5239 }
5240
5241 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5242 // Operands listed in NonVecOpIndices will be used as is without splitting;
5243 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5244 // scalar condition (op 1), immediate in sext_inreg (op 2).
5245 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5246 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5247 ++UseIdx, ++UseNo) {
5248 if (is_contained(NonVecOpIndices, UseIdx)) {
5249 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5250 MI.getOperand(UseIdx));
5251 } else {
5252 SmallVector<Register, 8> SplitPieces;
5253 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5254 MRI);
5255 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5256 }
5257 }
5258
5259 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5260
5261 // Take i-th piece of each input operand split and build sub-vector/scalar
5262 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5263 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5265 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5266 Defs.push_back(OutputOpsPieces[DstNo][i]);
5267
5269 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5270 Uses.push_back(InputOpsPieces[InputNo][i]);
5271
5272 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5273 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5274 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5275 }
5276
5277 // Merge small outputs into MI's output for each def operand.
5278 if (NumLeftovers) {
5279 for (unsigned i = 0; i < NumDefs; ++i)
5280 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5281 } else {
5282 for (unsigned i = 0; i < NumDefs; ++i)
5283 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5284 }
5285
5286 MI.eraseFromParent();
5287 return Legalized;
5288}
5289
5292 unsigned NumElts) {
5293 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5294
5295 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5296 unsigned NumDefs = MI.getNumDefs();
5297
5298 SmallVector<DstOp, 8> OutputOpsPieces;
5299 SmallVector<Register, 8> OutputRegs;
5300 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5301
5302 // Instructions that perform register split will be inserted in basic block
5303 // where register is defined (basic block is in the next operand).
5304 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5305 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5306 UseIdx += 2, ++UseNo) {
5307 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5308 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5309 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5310 MIRBuilder, MRI);
5311 }
5312
5313 // Build PHIs with fewer elements.
5314 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5315 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5316 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5317 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5318 Phi.addDef(
5319 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5320 OutputRegs.push_back(Phi.getReg(0));
5321
5322 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5323 Phi.addUse(InputOpsPieces[j][i]);
5324 Phi.add(MI.getOperand(1 + j * 2 + 1));
5325 }
5326 }
5327
5328 // Set the insert point after the existing PHIs
5329 MachineBasicBlock &MBB = *MI.getParent();
5330 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5331
5332 // Merge small outputs into MI's def.
5333 if (NumLeftovers) {
5334 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5335 } else {
5336 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5337 }
5338
5339 MI.eraseFromParent();
5340 return Legalized;
5341}
5342
5345 unsigned TypeIdx,
5346 LLT NarrowTy) {
5347 const int NumDst = MI.getNumOperands() - 1;
5348 const Register SrcReg = MI.getOperand(NumDst).getReg();
5349 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5350 LLT SrcTy = MRI.getType(SrcReg);
5351
5352 if (TypeIdx != 1 || NarrowTy == DstTy)
5353 return UnableToLegalize;
5354
5355 // Requires compatible types. Otherwise SrcReg should have been defined by
5356 // merge-like instruction that would get artifact combined. Most likely
5357 // instruction that defines SrcReg has to perform more/fewer elements
5358 // legalization compatible with NarrowTy.
5359 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5360 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5361
5362 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5363 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5364 return UnableToLegalize;
5365
5366 // This is most likely DstTy (smaller then register size) packed in SrcTy
5367 // (larger then register size) and since unmerge was not combined it will be
5368 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5369 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5370
5371 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5372 //
5373 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5374 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5375 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5376 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5377 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5378 const int PartsPerUnmerge = NumDst / NumUnmerge;
5379
5380 for (int I = 0; I != NumUnmerge; ++I) {
5381 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5382
5383 for (int J = 0; J != PartsPerUnmerge; ++J)
5384 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5385 MIB.addUse(Unmerge.getReg(I));
5386 }
5387
5388 MI.eraseFromParent();
5389 return Legalized;
5390}
5391
5394 LLT NarrowTy) {
5395 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5396 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5397 // that should have been artifact combined. Most likely instruction that uses
5398 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5399 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5400 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5401 if (NarrowTy == SrcTy)
5402 return UnableToLegalize;
5403
5404 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5405 // is for old mir tests. Since the changes to more/fewer elements it should no
5406 // longer be possible to generate MIR like this when starting from llvm-ir
5407 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5408 if (TypeIdx == 1) {
5409 assert(SrcTy.isVector() && "Expected vector types");
5410 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5411 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5412 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5413 return UnableToLegalize;
5414 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5415 //
5416 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5417 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5418 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5419 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5420 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5421 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5422
5424 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5425 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5426 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5427 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5428 Elts.push_back(Unmerge.getReg(j));
5429 }
5430
5431 SmallVector<Register, 8> NarrowTyElts;
5432 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5433 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5434 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5435 ++i, Offset += NumNarrowTyElts) {
5436 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5437 NarrowTyElts.push_back(
5438 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5439 }
5440
5441 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5442 MI.eraseFromParent();
5443 return Legalized;
5444 }
5445
5446 assert(TypeIdx == 0 && "Bad type index");
5447 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5448 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5449 return UnableToLegalize;
5450
5451 // This is most likely SrcTy (smaller then register size) packed in DstTy
5452 // (larger then register size) and since merge was not combined it will be
5453 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5454 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5455
5456 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5457 //
5458 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5459 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5460 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5461 SmallVector<Register, 8> NarrowTyElts;
5462 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5463 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5464 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5465 for (unsigned i = 0; i < NumParts; ++i) {
5467 for (unsigned j = 0; j < NumElts; ++j)
5468 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5469 NarrowTyElts.push_back(
5470 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5471 }
5472
5473 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5474 MI.eraseFromParent();
5475 return Legalized;
5476}
5477
5480 unsigned TypeIdx,
5481 LLT NarrowVecTy) {
5482 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5483 Register InsertVal;
5484 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5485
5486 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5487 if (IsInsert)
5488 InsertVal = MI.getOperand(2).getReg();
5489
5490 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5491 LLT VecTy = MRI.getType(SrcVec);
5492
5493 // If the index is a constant, we can really break this down as you would
5494 // expect, and index into the target size pieces.
5495 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5496 if (MaybeCst) {
5497 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5498 // Avoid out of bounds indexing the pieces.
5499 if (IdxVal >= VecTy.getNumElements()) {
5500 MIRBuilder.buildUndef(DstReg);
5501 MI.eraseFromParent();
5502 return Legalized;
5503 }
5504
5505 if (!NarrowVecTy.isVector()) {
5506 SmallVector<Register, 8> SplitPieces;
5507 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5508 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5509 if (IsInsert) {
5510 SplitPieces[IdxVal] = InsertVal;
5511 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5512 } else {
5513 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5514 }
5515 } else {
5516 SmallVector<Register, 8> VecParts;
5517 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5518
5519 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5520 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5521 TargetOpcode::G_ANYEXT);
5522
5523 unsigned NewNumElts = NarrowVecTy.getNumElements();
5524
5525 LLT IdxTy = MRI.getType(Idx);
5526 int64_t PartIdx = IdxVal / NewNumElts;
5527 auto NewIdx =
5528 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5529
5530 if (IsInsert) {
5531 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5532
5533 // Use the adjusted index to insert into one of the subvectors.
5534 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5535 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5536 VecParts[PartIdx] = InsertPart.getReg(0);
5537
5538 // Recombine the inserted subvector with the others to reform the result
5539 // vector.
5540 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5541 } else {
5542 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5543 }
5544 }
5545
5546 MI.eraseFromParent();
5547 return Legalized;
5548 }
5549
5550 // With a variable index, we can't perform the operation in a smaller type, so
5551 // we're forced to expand this.
5552 //
5553 // TODO: We could emit a chain of compare/select to figure out which piece to
5554 // index.
5556}
5557
5560 LLT NarrowTy) {
5561 // FIXME: Don't know how to handle secondary types yet.
5562 if (TypeIdx != 0)
5563 return UnableToLegalize;
5564
5565 if (!NarrowTy.isByteSized()) {
5566 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5567 return UnableToLegalize;
5568 }
5569
5570 // This implementation doesn't work for atomics. Give up instead of doing
5571 // something invalid.
5572 if (LdStMI.isAtomic())
5573 return UnableToLegalize;
5574
5575 bool IsLoad = isa<GLoad>(LdStMI);
5576 Register ValReg = LdStMI.getReg(0);
5577 Register AddrReg = LdStMI.getPointerReg();
5578 LLT ValTy = MRI.getType(ValReg);
5579
5580 // FIXME: Do we need a distinct NarrowMemory legalize action?
5581 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5582 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5583 return UnableToLegalize;
5584 }
5585
5586 int NumParts = -1;
5587 int NumLeftover = -1;
5588 LLT LeftoverTy;
5589 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5590 if (IsLoad) {
5591 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5592 } else {
5593 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5594 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5595 NumParts = NarrowRegs.size();
5596 NumLeftover = NarrowLeftoverRegs.size();
5597 }
5598 }
5599
5600 if (NumParts == -1)
5601 return UnableToLegalize;
5602
5603 LLT PtrTy = MRI.getType(AddrReg);
5604 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5605
5606 unsigned TotalSize = ValTy.getSizeInBits();
5607
5608 // Split the load/store into PartTy sized pieces starting at Offset. If this
5609 // is a load, return the new registers in ValRegs. For a store, each elements
5610 // of ValRegs should be PartTy. Returns the next offset that needs to be
5611 // handled.
5612 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5613 auto MMO = LdStMI.getMMO();
5614 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5615 unsigned NumParts, unsigned Offset) -> unsigned {
5616 MachineFunction &MF = MIRBuilder.getMF();
5617 unsigned PartSize = PartTy.getSizeInBits();
5618 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5619 ++Idx) {
5620 unsigned ByteOffset = Offset / 8;
5621 Register NewAddrReg;
5622
5623 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5624 ByteOffset);
5625
5626 MachineMemOperand *NewMMO =
5627 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5628
5629 if (IsLoad) {
5630 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5631 ValRegs.push_back(Dst);
5632 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5633 } else {
5634 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5635 }
5636 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5637 }
5638
5639 return Offset;
5640 };
5641
5642 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5643 unsigned HandledOffset =
5644 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5645
5646 // Handle the rest of the register if this isn't an even type breakdown.
5647 if (LeftoverTy.isValid())
5648 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5649
5650 if (IsLoad) {
5651 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5652 LeftoverTy, NarrowLeftoverRegs);
5653 }
5654
5655 LdStMI.eraseFromParent();
5656 return Legalized;
5657}
5658
5661 LLT NarrowTy) {
5662 using namespace TargetOpcode;
5664 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5665
5666 switch (MI.getOpcode()) {
5667 case G_IMPLICIT_DEF:
5668 case G_TRUNC:
5669 case G_AND:
5670 case G_OR:
5671 case G_XOR:
5672 case G_ADD:
5673 case G_SUB:
5674 case G_MUL:
5675 case G_PTR_ADD:
5676 case G_SMULH:
5677 case G_UMULH:
5678 case G_FADD:
5679 case G_FMUL:
5680 case G_FSUB:
5681 case G_FNEG:
5682 case G_FABS:
5683 case G_FCANONICALIZE:
5684 case G_FDIV:
5685 case G_FREM:
5686 case G_FMA:
5687 case G_FMAD:
5688 case G_FPOW:
5689 case G_FEXP:
5690 case G_FEXP2:
5691 case G_FEXP10:
5692 case G_FLOG:
5693 case G_FLOG2:
5694 case G_FLOG10:
5695 case G_FLDEXP:
5696 case G_FNEARBYINT:
5697 case G_FCEIL:
5698 case G_FFLOOR:
5699 case G_FRINT:
5700 case G_INTRINSIC_LRINT:
5701 case G_INTRINSIC_LLRINT:
5702 case G_INTRINSIC_ROUND:
5703 case G_INTRINSIC_ROUNDEVEN:
5704 case G_LROUND:
5705 case G_LLROUND:
5706 case G_INTRINSIC_TRUNC:
5707 case G_FMODF:
5708 case G_FCOS:
5709 case G_FSIN:
5710 case G_FTAN:
5711 case G_FACOS:
5712 case G_FASIN:
5713 case G_FATAN:
5714 case G_FATAN2:
5715 case G_FCOSH:
5716 case G_FSINH:
5717 case G_FTANH:
5718 case G_FSQRT:
5719 case G_BSWAP:
5720 case G_BITREVERSE:
5721 case G_SDIV:
5722 case G_UDIV:
5723 case G_SREM:
5724 case G_UREM:
5725 case G_SDIVREM:
5726 case G_UDIVREM:
5727 case G_SMIN:
5728 case G_SMAX:
5729 case G_UMIN:
5730 case G_UMAX:
5731 case G_ABS:
5732 case G_FMINNUM:
5733 case G_FMAXNUM:
5734 case G_FMINNUM_IEEE:
5735 case G_FMAXNUM_IEEE:
5736 case G_FMINIMUM:
5737 case G_FMAXIMUM:
5738 case G_FMINIMUMNUM:
5739 case G_FMAXIMUMNUM:
5740 case G_FSHL:
5741 case G_FSHR:
5742 case G_ROTL:
5743 case G_ROTR:
5744 case G_FREEZE:
5745 case G_SADDSAT:
5746 case G_SSUBSAT:
5747 case G_UADDSAT:
5748 case G_USUBSAT:
5749 case G_UMULO:
5750 case G_SMULO:
5751 case G_SHL:
5752 case G_LSHR:
5753 case G_ASHR:
5754 case G_SSHLSAT:
5755 case G_USHLSAT:
5756 case G_CTLZ:
5757 case G_CTLZ_ZERO_POISON:
5758 case G_CTTZ:
5759 case G_CTTZ_ZERO_POISON:
5760 case G_CTPOP:
5761 case G_CTLS:
5762 case G_FCOPYSIGN:
5763 case G_ZEXT:
5764 case G_SEXT:
5765 case G_ANYEXT:
5766 case G_FPEXT:
5767 case G_FPTRUNC:
5768 case G_SITOFP:
5769 case G_UITOFP:
5770 case G_FPTOSI:
5771 case G_FPTOUI:
5772 case G_FPTOSI_SAT:
5773 case G_FPTOUI_SAT:
5774 case G_INTTOPTR:
5775 case G_PTRTOINT:
5776 case G_ADDRSPACE_CAST:
5777 case G_UADDO:
5778 case G_USUBO:
5779 case G_UADDE:
5780 case G_USUBE:
5781 case G_SADDO:
5782 case G_SSUBO:
5783 case G_SADDE:
5784 case G_SSUBE:
5785 case G_STRICT_FADD:
5786 case G_STRICT_FSUB:
5787 case G_STRICT_FMUL:
5788 case G_STRICT_FMA:
5789 case G_STRICT_FLDEXP:
5790 case G_FFREXP:
5791 case G_TRUNC_SSAT_S:
5792 case G_TRUNC_SSAT_U:
5793 case G_TRUNC_USAT_U:
5794 return fewerElementsVectorMultiEltType(GMI, NumElts);
5795 case G_ICMP:
5796 case G_FCMP:
5797 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5798 case G_IS_FPCLASS:
5799 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5800 case G_SELECT:
5801 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5802 return fewerElementsVectorMultiEltType(GMI, NumElts);
5803 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5804 case G_PHI:
5805 return fewerElementsVectorPhi(GMI, NumElts);
5806 case G_UNMERGE_VALUES:
5807 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5808 case G_BUILD_VECTOR:
5809 assert(TypeIdx == 0 && "not a vector type index");
5810 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5811 case G_CONCAT_VECTORS:
5812 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5813 return UnableToLegalize;
5814 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5815 case G_EXTRACT_VECTOR_ELT:
5816 case G_INSERT_VECTOR_ELT:
5817 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5818 case G_LOAD:
5819 case G_STORE:
5820 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5821 case G_SEXT_INREG:
5822 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5824 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5825 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5826 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5827 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5828 case G_SHUFFLE_VECTOR:
5829 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5830 case G_FPOWI:
5831 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5832 case G_BITCAST:
5833 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5834 case G_INTRINSIC_FPTRUNC_ROUND:
5835 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5836 default:
5837 return UnableToLegalize;
5838 }
5839}
5840
5843 LLT NarrowTy) {
5844 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5845 "Not a bitcast operation");
5846
5847 if (TypeIdx != 0)
5848 return UnableToLegalize;
5849
5850 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5851
5852 unsigned NewElemCount =
5853 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5854 SmallVector<Register> SrcVRegs, BitcastVRegs;
5855 if (NewElemCount == 1) {
5856 LLT SrcNarrowTy = SrcTy.getElementType();
5857
5858 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
5859 getUnmergeResults(SrcVRegs, *Unmerge);
5860 } else {
5861 LLT SrcNarrowTy =
5863
5864 // Split the Src and Dst Reg into smaller registers
5865 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5866 return UnableToLegalize;
5867 }
5868
5869 // Build new smaller bitcast instructions
5870 // Not supporting Leftover types for now but will have to
5871 for (Register Reg : SrcVRegs)
5872 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
5873
5874 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5875 MI.eraseFromParent();
5876 return Legalized;
5877}
5878
5880 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5881 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5882 if (TypeIdx != 0)
5883 return UnableToLegalize;
5884
5885 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
5886 MI.getFirst3RegLLTs();
5887 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5888 // The shuffle should be canonicalized by now.
5889 if (DstTy != Src1Ty)
5890 return UnableToLegalize;
5891 if (DstTy != Src2Ty)
5892 return UnableToLegalize;
5893
5894 if (!isPowerOf2_32(DstTy.getNumElements()))
5895 return UnableToLegalize;
5896
5897 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
5898 // Further legalization attempts will be needed to do split further.
5899 NarrowTy =
5900 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
5901 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5902
5903 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
5904 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
5905 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
5906 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
5907 SplitSrc2Regs[1]};
5908
5909 Register Hi, Lo;
5910
5911 // If Lo or Hi uses elements from at most two of the four input vectors, then
5912 // express it as a vector shuffle of those two inputs. Otherwise extract the
5913 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
5915 for (unsigned High = 0; High < 2; ++High) {
5916 Register &Output = High ? Hi : Lo;
5917
5918 // Build a shuffle mask for the output, discovering on the fly which
5919 // input vectors to use as shuffle operands (recorded in InputUsed).
5920 // If building a suitable shuffle vector proves too hard, then bail
5921 // out with useBuildVector set.
5922 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
5923 unsigned FirstMaskIdx = High * NewElts;
5924 bool UseBuildVector = false;
5925 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5926 // The mask element. This indexes into the input.
5927 int Idx = Mask[FirstMaskIdx + MaskOffset];
5928
5929 // The input vector this mask element indexes into.
5930 unsigned Input = (unsigned)Idx / NewElts;
5931
5932 if (Input >= std::size(Inputs)) {
5933 // The mask element does not index into any input vector.
5934 Ops.push_back(-1);
5935 continue;
5936 }
5937
5938 // Turn the index into an offset from the start of the input vector.
5939 Idx -= Input * NewElts;
5940
5941 // Find or create a shuffle vector operand to hold this input.
5942 unsigned OpNo;
5943 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
5944 if (InputUsed[OpNo] == Input) {
5945 // This input vector is already an operand.
5946 break;
5947 } else if (InputUsed[OpNo] == -1U) {
5948 // Create a new operand for this input vector.
5949 InputUsed[OpNo] = Input;
5950 break;
5951 }
5952 }
5953
5954 if (OpNo >= std::size(InputUsed)) {
5955 // More than two input vectors used! Give up on trying to create a
5956 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
5957 UseBuildVector = true;
5958 break;
5959 }
5960
5961 // Add the mask index for the new shuffle vector.
5962 Ops.push_back(Idx + OpNo * NewElts);
5963 }
5964
5965 if (UseBuildVector) {
5966 LLT EltTy = NarrowTy.getElementType();
5968
5969 // Extract the input elements by hand.
5970 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5971 // The mask element. This indexes into the input.
5972 int Idx = Mask[FirstMaskIdx + MaskOffset];
5973
5974 // The input vector this mask element indexes into.
5975 unsigned Input = (unsigned)Idx / NewElts;
5976
5977 if (Input >= std::size(Inputs)) {
5978 // The mask element is "undef" or indexes off the end of the input.
5979 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
5980 continue;
5981 }
5982
5983 // Turn the index into an offset from the start of the input vector.
5984 Idx -= Input * NewElts;
5985
5986 // Extract the vector element by hand.
5987 SVOps.push_back(MIRBuilder
5988 .buildExtractVectorElement(
5989 EltTy, Inputs[Input],
5990 MIRBuilder.buildConstant(LLT::scalar(32), Idx))
5991 .getReg(0));
5992 }
5993
5994 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
5995 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
5996 } else if (InputUsed[0] == -1U) {
5997 // No input vectors were used! The result is undefined.
5998 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
5999 } else if (NewElts == 1) {
6000 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6001 } else {
6002 Register Op0 = Inputs[InputUsed[0]];
6003 // If only one input was used, use an undefined vector for the other.
6004 Register Op1 = InputUsed[1] == -1U
6005 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6006 : Inputs[InputUsed[1]];
6007 // At least one input vector was used. Create a new shuffle vector.
6008 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6009 }
6010
6011 Ops.clear();
6012 }
6013
6014 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6015 MI.eraseFromParent();
6016 return Legalized;
6017}
6018
6020 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6021 auto &RdxMI = cast<GVecReduce>(MI);
6022
6023 if (TypeIdx != 1)
6024 return UnableToLegalize;
6025
6026 // The semantics of the normal non-sequential reductions allow us to freely
6027 // re-associate the operation.
6028 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6029
6030 if (NarrowTy.isVector() &&
6031 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6032 return UnableToLegalize;
6033
6034 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6035 SmallVector<Register> SplitSrcs;
6036 // If NarrowTy is a scalar then we're being asked to scalarize.
6037 const unsigned NumParts =
6038 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6039 : SrcTy.getNumElements();
6040
6041 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6042 if (NarrowTy.isScalar()) {
6043 if (DstTy != NarrowTy)
6044 return UnableToLegalize; // FIXME: handle implicit extensions.
6045
6046 if (isPowerOf2_32(NumParts)) {
6047 // Generate a tree of scalar operations to reduce the critical path.
6048 SmallVector<Register> PartialResults;
6049 unsigned NumPartsLeft = NumParts;
6050 while (NumPartsLeft > 1) {
6051 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6052 PartialResults.emplace_back(
6054 .buildInstr(ScalarOpc, {NarrowTy},
6055 {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
6056 .getReg(0));
6057 }
6058 SplitSrcs = PartialResults;
6059 PartialResults.clear();
6060 NumPartsLeft = SplitSrcs.size();
6061 }
6062 assert(SplitSrcs.size() == 1);
6063 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6064 MI.eraseFromParent();
6065 return Legalized;
6066 }
6067 // If we can't generate a tree, then just do sequential operations.
6068 Register Acc = SplitSrcs[0];
6069 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6070 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
6071 .getReg(0);
6072 MIRBuilder.buildCopy(DstReg, Acc);
6073 MI.eraseFromParent();
6074 return Legalized;
6075 }
6076 SmallVector<Register> PartialReductions;
6077 for (unsigned Part = 0; Part < NumParts; ++Part) {
6078 PartialReductions.push_back(
6079 MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
6080 .getReg(0));
6081 }
6082
6083 // If the types involved are powers of 2, we can generate intermediate vector
6084 // ops, before generating a final reduction operation.
6085 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6086 isPowerOf2_32(NarrowTy.getNumElements())) {
6087 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6088 }
6089
6090 Register Acc = PartialReductions[0];
6091 for (unsigned Part = 1; Part < NumParts; ++Part) {
6092 if (Part == NumParts - 1) {
6093 MIRBuilder.buildInstr(ScalarOpc, {DstReg},
6094 {Acc, PartialReductions[Part]});
6095 } else {
6096 Acc = MIRBuilder
6097 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
6098 .getReg(0);
6099 }
6100 }
6101 MI.eraseFromParent();
6102 return Legalized;
6103}
6104
6107 unsigned int TypeIdx,
6108 LLT NarrowTy) {
6109 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6110 MI.getFirst3RegLLTs();
6111 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6112 DstTy != NarrowTy)
6113 return UnableToLegalize;
6114
6115 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6116 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6117 "Unexpected vecreduce opcode");
6118 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6119 ? TargetOpcode::G_FADD
6120 : TargetOpcode::G_FMUL;
6121
6122 SmallVector<Register> SplitSrcs;
6123 unsigned NumParts = SrcTy.getNumElements();
6124 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6125 Register Acc = ScalarReg;
6126 for (unsigned i = 0; i < NumParts; i++)
6127 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
6128 .getReg(0);
6129
6130 MIRBuilder.buildCopy(DstReg, Acc);
6131 MI.eraseFromParent();
6132 return Legalized;
6133}
6134
6136LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6137 LLT SrcTy, LLT NarrowTy,
6138 unsigned ScalarOpc) {
6139 SmallVector<Register> SplitSrcs;
6140 // Split the sources into NarrowTy size pieces.
6141 extractParts(SrcReg, NarrowTy,
6142 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6143 MIRBuilder, MRI);
6144 // We're going to do a tree reduction using vector operations until we have
6145 // one NarrowTy size value left.
6146 while (SplitSrcs.size() > 1) {
6147 SmallVector<Register> PartialRdxs;
6148 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6149 Register LHS = SplitSrcs[Idx];
6150 Register RHS = SplitSrcs[Idx + 1];
6151 // Create the intermediate vector op.
6152 Register Res =
6153 MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
6154 PartialRdxs.push_back(Res);
6155 }
6156 SplitSrcs = std::move(PartialRdxs);
6157 }
6158 // Finally generate the requested NarrowTy based reduction.
6159 Observer.changingInstr(MI);
6160 MI.getOperand(1).setReg(SplitSrcs[0]);
6161 Observer.changedInstr(MI);
6162 return Legalized;
6163}
6164
6167 const LLT HalfTy, const LLT AmtTy) {
6168
6169 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6170 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6171 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6172
6173 if (Amt.isZero()) {
6174 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6175 MI.eraseFromParent();
6176 return Legalized;
6177 }
6178
6179 LLT NVT = HalfTy;
6180 unsigned NVTBits = HalfTy.getSizeInBits();
6181 unsigned VTBits = 2 * NVTBits;
6182
6183 SrcOp Lo(Register(0)), Hi(Register(0));
6184 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6185 if (Amt.ugt(VTBits)) {
6186 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6187 } else if (Amt.ugt(NVTBits)) {
6188 Lo = MIRBuilder.buildConstant(NVT, 0);
6189 Hi = MIRBuilder.buildShl(NVT, InL,
6190 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6191 } else if (Amt == NVTBits) {
6192 Lo = MIRBuilder.buildConstant(NVT, 0);
6193 Hi = InL;
6194 } else {
6195 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6196 auto OrLHS =
6197 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6198 auto OrRHS = MIRBuilder.buildLShr(
6199 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6200 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6201 }
6202 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6203 if (Amt.ugt(VTBits)) {
6204 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6205 } else if (Amt.ugt(NVTBits)) {
6206 Lo = MIRBuilder.buildLShr(NVT, InH,
6207 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6208 Hi = MIRBuilder.buildConstant(NVT, 0);
6209 } else if (Amt == NVTBits) {
6210 Lo = InH;
6211 Hi = MIRBuilder.buildConstant(NVT, 0);
6212 } else {
6213 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6214
6215 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6216 auto OrRHS = MIRBuilder.buildShl(
6217 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6218
6219 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6220 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6221 }
6222 } else {
6223 if (Amt.ugt(VTBits)) {
6224 Hi = Lo = MIRBuilder.buildAShr(
6225 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6226 } else if (Amt.ugt(NVTBits)) {
6227 Lo = MIRBuilder.buildAShr(NVT, InH,
6228 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6229 Hi = MIRBuilder.buildAShr(NVT, InH,
6230 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6231 } else if (Amt == NVTBits) {
6232 Lo = InH;
6233 Hi = MIRBuilder.buildAShr(NVT, InH,
6234 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6235 } else {
6236 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6237
6238 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6239 auto OrRHS = MIRBuilder.buildShl(
6240 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6241
6242 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6243 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6244 }
6245 }
6246
6247 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6248 MI.eraseFromParent();
6249
6250 return Legalized;
6251}
6252
6255 LLT RequestedTy) {
6256 if (TypeIdx == 1) {
6257 Observer.changingInstr(MI);
6258 narrowScalarSrc(MI, RequestedTy, 2);
6259 Observer.changedInstr(MI);
6260 return Legalized;
6261 }
6262
6263 Register DstReg = MI.getOperand(0).getReg();
6264 LLT DstTy = MRI.getType(DstReg);
6265 if (DstTy.isVector())
6266 return UnableToLegalize;
6267
6268 Register Amt = MI.getOperand(2).getReg();
6269 LLT ShiftAmtTy = MRI.getType(Amt);
6270 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6271 if (DstEltSize % 2 != 0)
6272 return UnableToLegalize;
6273
6274 // Check if we should use multi-way splitting instead of recursive binary
6275 // splitting.
6276 //
6277 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6278 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6279 // and dependency chains created by usual binary splitting approach
6280 // (128->64->32).
6281 //
6282 // The >= 8 parts threshold ensures we only use this optimization when binary
6283 // splitting would require multiple recursive passes, avoiding overhead for
6284 // simple 2-way splits where binary approach is sufficient.
6285 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6286 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6287 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6288 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6289 // steps).
6290 if (NumParts >= 8)
6291 return narrowScalarShiftMultiway(MI, RequestedTy);
6292 }
6293
6294 // Fall back to binary splitting:
6295 // Ignore the input type. We can only go to exactly half the size of the
6296 // input. If that isn't small enough, the resulting pieces will be further
6297 // legalized.
6298 const unsigned NewBitSize = DstEltSize / 2;
6299 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6300 const LLT CondTy = LLT::integer(1);
6301
6302 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6303 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6304 ShiftAmtTy);
6305 }
6306
6307 // TODO: Expand with known bits.
6308
6309 // Handle the fully general expansion by an unknown amount.
6310 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6311
6312 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6313 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6314 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6315
6316 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6317 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6318
6319 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6320 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6321 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6322
6323 Register ResultRegs[2];
6324 switch (MI.getOpcode()) {
6325 case TargetOpcode::G_SHL: {
6326 // Short: ShAmt < NewBitSize
6327 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6328
6329 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6330 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6331 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6332
6333 // Long: ShAmt >= NewBitSize
6334 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6335 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6336
6337 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6338 auto Hi = MIRBuilder.buildSelect(
6339 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6340
6341 ResultRegs[0] = Lo.getReg(0);
6342 ResultRegs[1] = Hi.getReg(0);
6343 break;
6344 }
6345 case TargetOpcode::G_LSHR:
6346 case TargetOpcode::G_ASHR: {
6347 // Short: ShAmt < NewBitSize
6348 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6349
6350 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6351 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6352 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6353
6354 // Long: ShAmt >= NewBitSize
6356 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6357 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6358 } else {
6359 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6360 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6361 }
6362 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6363 {InH, AmtExcess}); // Lo from Hi part.
6364
6365 auto Lo = MIRBuilder.buildSelect(
6366 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6367
6368 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6369
6370 ResultRegs[0] = Lo.getReg(0);
6371 ResultRegs[1] = Hi.getReg(0);
6372 break;
6373 }
6374 default:
6375 llvm_unreachable("not a shift");
6376 }
6377
6378 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6379 MI.eraseFromParent();
6380 return Legalized;
6381}
6382
6384 unsigned PartIdx,
6385 unsigned NumParts,
6386 ArrayRef<Register> SrcParts,
6387 const ShiftParams &Params,
6388 LLT TargetTy, LLT ShiftAmtTy) {
6389 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6390 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6391 assert(WordShiftConst && BitShiftConst && "Expected constants");
6392
6393 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6394 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6395 const bool NeedsInterWordShift = ShiftBits != 0;
6396
6397 switch (Opcode) {
6398 case TargetOpcode::G_SHL: {
6399 // Data moves from lower indices to higher indices
6400 // If this part would come from a source beyond our range, it's zero
6401 if (PartIdx < ShiftWords)
6402 return Params.Zero;
6403
6404 unsigned SrcIdx = PartIdx - ShiftWords;
6405 if (!NeedsInterWordShift)
6406 return SrcParts[SrcIdx];
6407
6408 // Combine shifted main part with carry from previous part
6409 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6410 if (SrcIdx > 0) {
6411 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6412 Params.InvBitShift);
6413 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6414 }
6415 return Hi.getReg(0);
6416 }
6417
6418 case TargetOpcode::G_LSHR: {
6419 unsigned SrcIdx = PartIdx + ShiftWords;
6420 if (SrcIdx >= NumParts)
6421 return Params.Zero;
6422 if (!NeedsInterWordShift)
6423 return SrcParts[SrcIdx];
6424
6425 // Combine shifted main part with carry from next part
6426 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6427 if (SrcIdx + 1 < NumParts) {
6428 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6429 Params.InvBitShift);
6430 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6431 }
6432 return Lo.getReg(0);
6433 }
6434
6435 case TargetOpcode::G_ASHR: {
6436 // Like LSHR but preserves sign bit
6437 unsigned SrcIdx = PartIdx + ShiftWords;
6438 if (SrcIdx >= NumParts)
6439 return Params.SignBit;
6440 if (!NeedsInterWordShift)
6441 return SrcParts[SrcIdx];
6442
6443 // Only the original MSB part uses arithmetic shift to preserve sign. All
6444 // other parts use logical shift since they're just moving data bits.
6445 auto Lo =
6446 (SrcIdx == NumParts - 1)
6447 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6448 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6449 Register HiSrc =
6450 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6451 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6452 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6453 }
6454
6455 default:
6456 llvm_unreachable("not a shift");
6457 }
6458}
6459
6461 Register MainOperand,
6462 Register ShiftAmt,
6463 LLT TargetTy,
6464 Register CarryOperand) {
6465 // This helper generates a single output part for variable shifts by combining
6466 // the main operand (shifted by BitShift) with carry bits from an adjacent
6467 // part.
6468
6469 // For G_ASHR, individual parts don't have their own sign bit, only the
6470 // complete value does. So we use LSHR for the main operand shift in ASHR
6471 // context.
6472 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6473 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6474 : Opcode;
6475
6476 // Perform the primary shift on the main operand
6477 Register MainShifted =
6478 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6479 .getReg(0);
6480
6481 // No carry operand available
6482 if (!CarryOperand.isValid())
6483 return MainShifted;
6484
6485 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6486 // so carry bits aren't needed.
6487 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6488 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6489 LLT BoolTy = LLT::scalar(1);
6490 auto IsZeroBitShift =
6491 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6492
6493 // Extract bits from the adjacent part that will "carry over" into this part.
6494 // The carry direction is opposite to the main shift direction, so we can
6495 // align the two shifted values before combining them with OR.
6496
6497 // Determine the carry shift opcode (opposite direction)
6498 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6499 : TargetOpcode::G_SHL;
6500
6501 // Calculate inverse shift amount: BitWidth - ShiftAmt
6502 auto TargetBitsConst =
6503 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6504 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6505
6506 // Shift the carry operand
6507 Register CarryBits =
6509 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6510 .getReg(0);
6511
6512 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6513 // TargetBits which would be poison for the individual carry shift operation).
6514 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6515 Register SafeCarryBits =
6516 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6517 .getReg(0);
6518
6519 // Combine the main shifted part with the carry bits
6520 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6521}
6522
6525 const APInt &Amt,
6526 LLT TargetTy,
6527 LLT ShiftAmtTy) {
6528 // Any wide shift can be decomposed into WordShift + BitShift components.
6529 // When shift amount is known constant, directly compute the decomposition
6530 // values and generate constant registers.
6531 Register DstReg = MI.getOperand(0).getReg();
6532 Register SrcReg = MI.getOperand(1).getReg();
6533 LLT DstTy = MRI.getType(DstReg);
6534
6535 const unsigned DstBits = DstTy.getScalarSizeInBits();
6536 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6537 const unsigned NumParts = DstBits / TargetBits;
6538
6539 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6540
6541 // When the shift amount is known at compile time, we just calculate which
6542 // source parts contribute to each output part.
6543
6544 SmallVector<Register, 8> SrcParts;
6545 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6546
6547 if (Amt.isZero()) {
6548 // No shift needed, just copy
6549 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6550 MI.eraseFromParent();
6551 return Legalized;
6552 }
6553
6554 ShiftParams Params;
6555 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6556 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6557
6558 // Generate constants and values needed by all shift types
6559 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6560 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6561 Params.InvBitShift =
6562 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6563 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6564
6565 // For ASHR, we need the sign-extended value to fill shifted-out positions
6566 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6567 Params.SignBit =
6569 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6570 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6571 .getReg(0);
6572
6573 SmallVector<Register, 8> DstParts(NumParts);
6574 for (unsigned I = 0; I < NumParts; ++I)
6575 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6576 Params, TargetTy, ShiftAmtTy);
6577
6578 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6579 MI.eraseFromParent();
6580 return Legalized;
6581}
6582
6585 Register DstReg = MI.getOperand(0).getReg();
6586 Register SrcReg = MI.getOperand(1).getReg();
6587 Register AmtReg = MI.getOperand(2).getReg();
6588 LLT DstTy = MRI.getType(DstReg);
6589 LLT ShiftAmtTy = MRI.getType(AmtReg);
6590
6591 const unsigned DstBits = DstTy.getScalarSizeInBits();
6592 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6593 const unsigned NumParts = DstBits / TargetBits;
6594
6595 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6596 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6597
6598 // If the shift amount is known at compile time, we can use direct indexing
6599 // instead of generating select chains in the general case.
6600 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6601 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6602 ShiftAmtTy);
6603
6604 // For runtime-variable shift amounts, we must generate a more complex
6605 // sequence that handles all possible shift values using select chains.
6606
6607 // Split the input into target-sized pieces
6608 SmallVector<Register, 8> SrcParts;
6609 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6610
6611 // Shifting by zero should be a no-op.
6612 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6613 LLT BoolTy = LLT::scalar(1);
6614 auto IsZeroShift =
6615 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6616
6617 // Any wide shift can be decomposed into two components:
6618 // 1. WordShift: number of complete target-sized words to shift
6619 // 2. BitShift: number of bits to shift within each word
6620 //
6621 // Example: 128-bit >> 50 with 32-bit target:
6622 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6623 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6624 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6625 auto TargetBitsLog2Const =
6626 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6627 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6628
6629 Register WordShift =
6630 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6631 Register BitShift =
6632 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6633
6634 // Fill values:
6635 // - SHL/LSHR: fill with zeros
6636 // - ASHR: fill with sign-extended MSB
6637 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6638
6639 Register FillValue;
6640 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6641 auto TargetBitsMinusOneConst =
6642 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6643 FillValue = MIRBuilder
6644 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6645 TargetBitsMinusOneConst)
6646 .getReg(0);
6647 } else {
6648 FillValue = ZeroReg;
6649 }
6650
6651 SmallVector<Register, 8> DstParts(NumParts);
6652
6653 // For each output part, generate a select chain that chooses the correct
6654 // result based on the runtime WordShift value. This handles all possible
6655 // word shift amounts by pre-calculating what each would produce.
6656 for (unsigned I = 0; I < NumParts; ++I) {
6657 // Initialize with appropriate default value for this shift type
6658 Register InBoundsResult = FillValue;
6659
6660 // clang-format off
6661 // Build a branchless select chain by pre-computing results for all possible
6662 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6663 //
6664 // K=0: select(WordShift==0, result0, FillValue)
6665 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6666 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6667 // clang-format on
6668 for (unsigned K = 0; K < NumParts; ++K) {
6669 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6670 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6671 WordShift, WordShiftKConst);
6672
6673 // Calculate source indices for this word shift
6674 //
6675 // For 4-part 128-bit value with K=1 word shift:
6676 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6677 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6678 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6679 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6680 int MainSrcIdx;
6681 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6682
6683 switch (MI.getOpcode()) {
6684 case TargetOpcode::G_SHL:
6685 MainSrcIdx = (int)I - (int)K;
6686 CarrySrcIdx = MainSrcIdx - 1;
6687 break;
6688 case TargetOpcode::G_LSHR:
6689 case TargetOpcode::G_ASHR:
6690 MainSrcIdx = (int)I + (int)K;
6691 CarrySrcIdx = MainSrcIdx + 1;
6692 break;
6693 default:
6694 llvm_unreachable("Not a shift");
6695 }
6696
6697 // Check bounds and build the result for this word shift
6698 Register ResultForK;
6699 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6700 Register MainOp = SrcParts[MainSrcIdx];
6701 Register CarryOp;
6702
6703 // Determine carry operand with bounds checking
6704 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6705 CarryOp = SrcParts[CarrySrcIdx];
6706 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6707 CarrySrcIdx >= (int)NumParts)
6708 CarryOp = FillValue; // Use sign extension
6709
6710 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6711 TargetTy, CarryOp);
6712 } else {
6713 // Out of bounds - use fill value for this k
6714 ResultForK = FillValue;
6715 }
6716
6717 // Select this result if WordShift equals k
6718 InBoundsResult =
6720 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6721 .getReg(0);
6722 }
6723
6724 // Handle zero-shift special case: if shift is 0, use original input
6725 DstParts[I] =
6727 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6728 .getReg(0);
6729 }
6730
6731 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6732 MI.eraseFromParent();
6733 return Legalized;
6734}
6735
6738 LLT MoreTy) {
6739 assert(TypeIdx == 0 && "Expecting only Idx 0");
6740
6741 Observer.changingInstr(MI);
6742 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6743 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6744 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6745 moreElementsVectorSrc(MI, MoreTy, I);
6746 }
6747
6748 MachineBasicBlock &MBB = *MI.getParent();
6749 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6750 moreElementsVectorDst(MI, MoreTy, 0);
6751 Observer.changedInstr(MI);
6752 return Legalized;
6753}
6754
6755MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6756 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6757 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6758
6759 switch (Opcode) {
6760 default:
6762 "getNeutralElementForVecReduce called with invalid opcode!");
6763 case TargetOpcode::G_VECREDUCE_ADD:
6764 case TargetOpcode::G_VECREDUCE_OR:
6765 case TargetOpcode::G_VECREDUCE_XOR:
6766 case TargetOpcode::G_VECREDUCE_UMAX:
6767 return MIRBuilder.buildConstant(Ty, 0);
6768 case TargetOpcode::G_VECREDUCE_MUL:
6769 return MIRBuilder.buildConstant(Ty, 1);
6770 case TargetOpcode::G_VECREDUCE_AND:
6771 case TargetOpcode::G_VECREDUCE_UMIN:
6773 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6774 case TargetOpcode::G_VECREDUCE_SMAX:
6776 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6777 case TargetOpcode::G_VECREDUCE_SMIN:
6779 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6780 case TargetOpcode::G_VECREDUCE_FADD:
6781 return MIRBuilder.buildFConstant(Ty, -0.0);
6782 case TargetOpcode::G_VECREDUCE_FMUL:
6783 return MIRBuilder.buildFConstant(Ty, 1.0);
6784 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6785 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6786 assert(false && "getNeutralElementForVecReduce unimplemented for "
6787 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6788 }
6789 llvm_unreachable("switch expected to return!");
6790}
6791
6794 LLT MoreTy) {
6795 unsigned Opc = MI.getOpcode();
6796 switch (Opc) {
6797 case TargetOpcode::G_IMPLICIT_DEF:
6798 case TargetOpcode::G_LOAD: {
6799 if (TypeIdx != 0)
6800 return UnableToLegalize;
6801 Observer.changingInstr(MI);
6802 moreElementsVectorDst(MI, MoreTy, 0);
6803 Observer.changedInstr(MI);
6804 return Legalized;
6805 }
6806 case TargetOpcode::G_STORE:
6807 if (TypeIdx != 0)
6808 return UnableToLegalize;
6809 Observer.changingInstr(MI);
6810 moreElementsVectorSrc(MI, MoreTy, 0);
6811 Observer.changedInstr(MI);
6812 return Legalized;
6813 case TargetOpcode::G_AND:
6814 case TargetOpcode::G_OR:
6815 case TargetOpcode::G_XOR:
6816 case TargetOpcode::G_ADD:
6817 case TargetOpcode::G_SUB:
6818 case TargetOpcode::G_MUL:
6819 case TargetOpcode::G_FADD:
6820 case TargetOpcode::G_FSUB:
6821 case TargetOpcode::G_FMUL:
6822 case TargetOpcode::G_FDIV:
6823 case TargetOpcode::G_FCOPYSIGN:
6824 case TargetOpcode::G_UADDSAT:
6825 case TargetOpcode::G_USUBSAT:
6826 case TargetOpcode::G_SADDSAT:
6827 case TargetOpcode::G_SSUBSAT:
6828 case TargetOpcode::G_SMIN:
6829 case TargetOpcode::G_SMAX:
6830 case TargetOpcode::G_UMIN:
6831 case TargetOpcode::G_UMAX:
6832 case TargetOpcode::G_FMINNUM:
6833 case TargetOpcode::G_FMAXNUM:
6834 case TargetOpcode::G_FMINNUM_IEEE:
6835 case TargetOpcode::G_FMAXNUM_IEEE:
6836 case TargetOpcode::G_FMINIMUM:
6837 case TargetOpcode::G_FMAXIMUM:
6838 case TargetOpcode::G_FMINIMUMNUM:
6839 case TargetOpcode::G_FMAXIMUMNUM:
6840 case TargetOpcode::G_STRICT_FADD:
6841 case TargetOpcode::G_STRICT_FSUB:
6842 case TargetOpcode::G_STRICT_FMUL: {
6843 Observer.changingInstr(MI);
6844 moreElementsVectorSrc(MI, MoreTy, 1);
6845 moreElementsVectorSrc(MI, MoreTy, 2);
6846 moreElementsVectorDst(MI, MoreTy, 0);
6847 Observer.changedInstr(MI);
6848 return Legalized;
6849 }
6850 case TargetOpcode::G_SHL:
6851 case TargetOpcode::G_ASHR:
6852 case TargetOpcode::G_LSHR: {
6853 Observer.changingInstr(MI);
6854 moreElementsVectorSrc(MI, MoreTy, 1);
6855 // The shift operand may have a different scalar type from the source and
6856 // destination operands.
6857 LLT ShiftMoreTy = MoreTy.changeElementType(
6858 MRI.getType(MI.getOperand(2).getReg()).getElementType());
6859 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
6860 moreElementsVectorDst(MI, MoreTy, 0);
6861 Observer.changedInstr(MI);
6862 return Legalized;
6863 }
6864 case TargetOpcode::G_FMA:
6865 case TargetOpcode::G_STRICT_FMA:
6866 case TargetOpcode::G_FSHR:
6867 case TargetOpcode::G_FSHL: {
6868 Observer.changingInstr(MI);
6869 moreElementsVectorSrc(MI, MoreTy, 1);
6870 moreElementsVectorSrc(MI, MoreTy, 2);
6871 moreElementsVectorSrc(MI, MoreTy, 3);
6872 moreElementsVectorDst(MI, MoreTy, 0);
6873 Observer.changedInstr(MI);
6874 return Legalized;
6875 }
6876 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
6877 case TargetOpcode::G_EXTRACT:
6878 if (TypeIdx != 1)
6879 return UnableToLegalize;
6880 Observer.changingInstr(MI);
6881 moreElementsVectorSrc(MI, MoreTy, 1);
6882 Observer.changedInstr(MI);
6883 return Legalized;
6884 case TargetOpcode::G_INSERT:
6885 case TargetOpcode::G_INSERT_VECTOR_ELT:
6886 case TargetOpcode::G_FREEZE:
6887 case TargetOpcode::G_FNEG:
6888 case TargetOpcode::G_FABS:
6889 case TargetOpcode::G_FSQRT:
6890 case TargetOpcode::G_FCEIL:
6891 case TargetOpcode::G_FFLOOR:
6892 case TargetOpcode::G_FNEARBYINT:
6893 case TargetOpcode::G_FRINT:
6894 case TargetOpcode::G_INTRINSIC_ROUND:
6895 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
6896 case TargetOpcode::G_INTRINSIC_TRUNC:
6897 case TargetOpcode::G_BITREVERSE:
6898 case TargetOpcode::G_BSWAP:
6899 case TargetOpcode::G_FCANONICALIZE:
6900 case TargetOpcode::G_SEXT_INREG:
6901 case TargetOpcode::G_ABS:
6902 case TargetOpcode::G_CTLZ:
6903 case TargetOpcode::G_CTPOP:
6904 if (TypeIdx != 0)
6905 return UnableToLegalize;
6906 Observer.changingInstr(MI);
6907 moreElementsVectorSrc(MI, MoreTy, 1);
6908 moreElementsVectorDst(MI, MoreTy, 0);
6909 Observer.changedInstr(MI);
6910 return Legalized;
6911 case TargetOpcode::G_SELECT: {
6912 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
6913 if (TypeIdx == 1) {
6914 if (!CondTy.isScalar() ||
6915 DstTy.getElementCount() != MoreTy.getElementCount())
6916 return UnableToLegalize;
6917
6918 // This is turning a scalar select of vectors into a vector
6919 // select. Broadcast the select condition.
6920 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
6921 Observer.changingInstr(MI);
6922 MI.getOperand(1).setReg(ShufSplat.getReg(0));
6923 Observer.changedInstr(MI);
6924 return Legalized;
6925 }
6926
6927 if (CondTy.isVector())
6928 return UnableToLegalize;
6929
6930 Observer.changingInstr(MI);
6931 moreElementsVectorSrc(MI, MoreTy, 2);
6932 moreElementsVectorSrc(MI, MoreTy, 3);
6933 moreElementsVectorDst(MI, MoreTy, 0);
6934 Observer.changedInstr(MI);
6935 return Legalized;
6936 }
6937 case TargetOpcode::G_UNMERGE_VALUES:
6938 return UnableToLegalize;
6939 case TargetOpcode::G_PHI:
6940 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
6941 case TargetOpcode::G_SHUFFLE_VECTOR:
6942 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
6943 case TargetOpcode::G_BUILD_VECTOR: {
6945 for (auto Op : MI.uses()) {
6946 Elts.push_back(Op.getReg());
6947 }
6948
6949 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
6950 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
6951 }
6952
6953 MIRBuilder.buildDeleteTrailingVectorElements(
6954 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
6955 MI.eraseFromParent();
6956 return Legalized;
6957 }
6958 case TargetOpcode::G_SEXT:
6959 case TargetOpcode::G_ZEXT:
6960 case TargetOpcode::G_ANYEXT:
6961 case TargetOpcode::G_TRUNC:
6962 case TargetOpcode::G_FPTRUNC:
6963 case TargetOpcode::G_FPEXT:
6964 case TargetOpcode::G_FPTOSI:
6965 case TargetOpcode::G_FPTOUI:
6966 case TargetOpcode::G_FPTOSI_SAT:
6967 case TargetOpcode::G_FPTOUI_SAT:
6968 case TargetOpcode::G_SITOFP:
6969 case TargetOpcode::G_UITOFP: {
6970 Observer.changingInstr(MI);
6971 LLT SrcExtTy;
6972 LLT DstExtTy;
6973 if (TypeIdx == 0) {
6974 DstExtTy = MoreTy;
6975 SrcExtTy = MoreTy.changeElementType(
6976 MRI.getType(MI.getOperand(1).getReg()).getElementType());
6977 } else {
6978 DstExtTy = MoreTy.changeElementType(
6979 MRI.getType(MI.getOperand(0).getReg()).getElementType());
6980 SrcExtTy = MoreTy;
6981 }
6982 moreElementsVectorSrc(MI, SrcExtTy, 1);
6983 moreElementsVectorDst(MI, DstExtTy, 0);
6984 Observer.changedInstr(MI);
6985 return Legalized;
6986 }
6987 case TargetOpcode::G_ICMP:
6988 case TargetOpcode::G_FCMP: {
6989 if (TypeIdx != 1)
6990 return UnableToLegalize;
6991
6992 Observer.changingInstr(MI);
6993 moreElementsVectorSrc(MI, MoreTy, 2);
6994 moreElementsVectorSrc(MI, MoreTy, 3);
6995 LLT CondTy = MoreTy.changeVectorElementType(
6996 MRI.getType(MI.getOperand(0).getReg()).getElementType());
6997 moreElementsVectorDst(MI, CondTy, 0);
6998 Observer.changedInstr(MI);
6999 return Legalized;
7000 }
7001 case TargetOpcode::G_BITCAST: {
7002 if (TypeIdx != 0)
7003 return UnableToLegalize;
7004
7005 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7006 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7007
7008 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7009 if (coefficient % DstTy.getNumElements() != 0)
7010 return UnableToLegalize;
7011
7012 coefficient = coefficient / DstTy.getNumElements();
7013
7014 LLT NewTy = SrcTy.changeElementCount(
7015 ElementCount::get(coefficient, MoreTy.isScalable()));
7016 Observer.changingInstr(MI);
7017 moreElementsVectorSrc(MI, NewTy, 1);
7018 moreElementsVectorDst(MI, MoreTy, 0);
7019 Observer.changedInstr(MI);
7020 return Legalized;
7021 }
7022 case TargetOpcode::G_VECREDUCE_FADD:
7023 case TargetOpcode::G_VECREDUCE_FMUL:
7024 case TargetOpcode::G_VECREDUCE_ADD:
7025 case TargetOpcode::G_VECREDUCE_MUL:
7026 case TargetOpcode::G_VECREDUCE_AND:
7027 case TargetOpcode::G_VECREDUCE_OR:
7028 case TargetOpcode::G_VECREDUCE_XOR:
7029 case TargetOpcode::G_VECREDUCE_SMAX:
7030 case TargetOpcode::G_VECREDUCE_SMIN:
7031 case TargetOpcode::G_VECREDUCE_UMAX:
7032 case TargetOpcode::G_VECREDUCE_UMIN: {
7033 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7034 MachineOperand &MO = MI.getOperand(1);
7035 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7036 auto NeutralElement = getNeutralElementForVecReduce(
7037 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7038
7039 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7040 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7041 i != e; i++) {
7042 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7043 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7044 NeutralElement, Idx);
7045 }
7046
7047 Observer.changingInstr(MI);
7048 MO.setReg(NewVec.getReg(0));
7049 Observer.changedInstr(MI);
7050 return Legalized;
7051 }
7052
7053 default:
7054 return UnableToLegalize;
7055 }
7056}
7057
7060 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7061 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7062 unsigned MaskNumElts = Mask.size();
7063 unsigned SrcNumElts = SrcTy.getNumElements();
7064 LLT DestEltTy = DstTy.getElementType();
7065
7066 if (MaskNumElts == SrcNumElts)
7067 return Legalized;
7068
7069 if (MaskNumElts < SrcNumElts) {
7070 // Extend mask to match new destination vector size with
7071 // undef values.
7072 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7073 llvm::copy(Mask, NewMask.begin());
7074
7075 moreElementsVectorDst(MI, SrcTy, 0);
7076 MIRBuilder.setInstrAndDebugLoc(MI);
7077 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7078 MI.getOperand(1).getReg(),
7079 MI.getOperand(2).getReg(), NewMask);
7080 MI.eraseFromParent();
7081
7082 return Legalized;
7083 }
7084
7085 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7086 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7087 LLT PaddedTy =
7088 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7089
7090 // Create new source vectors by concatenating the initial
7091 // source vectors with undefined vectors of the same size.
7092 auto Undef = MIRBuilder.buildUndef(SrcTy);
7093 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7094 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7095 MOps1[0] = MI.getOperand(1).getReg();
7096 MOps2[0] = MI.getOperand(2).getReg();
7097
7098 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7099 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7100
7101 // Readjust mask for new input vector length.
7102 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7103 for (unsigned I = 0; I != MaskNumElts; ++I) {
7104 int Idx = Mask[I];
7105 if (Idx >= static_cast<int>(SrcNumElts))
7106 Idx += PaddedMaskNumElts - SrcNumElts;
7107 MappedOps[I] = Idx;
7108 }
7109
7110 // If we got more elements than required, extract subvector.
7111 if (MaskNumElts != PaddedMaskNumElts) {
7112 auto Shuffle =
7113 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7114
7115 SmallVector<Register, 16> Elts(MaskNumElts);
7116 for (unsigned I = 0; I < MaskNumElts; ++I) {
7117 Elts[I] =
7118 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7119 .getReg(0);
7120 }
7121 MIRBuilder.buildBuildVector(DstReg, Elts);
7122 } else {
7123 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7124 }
7125
7126 MI.eraseFromParent();
7128}
7129
7132 unsigned int TypeIdx, LLT MoreTy) {
7133 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7134 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7135 unsigned NumElts = DstTy.getNumElements();
7136 unsigned WidenNumElts = MoreTy.getNumElements();
7137
7138 if (DstTy.isVector() && Src1Ty.isVector() &&
7139 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7141 }
7142
7143 if (TypeIdx != 0)
7144 return UnableToLegalize;
7145
7146 // Expect a canonicalized shuffle.
7147 if (DstTy != Src1Ty || DstTy != Src2Ty)
7148 return UnableToLegalize;
7149
7150 moreElementsVectorSrc(MI, MoreTy, 1);
7151 moreElementsVectorSrc(MI, MoreTy, 2);
7152
7153 // Adjust mask based on new input vector length.
7154 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7155 for (unsigned I = 0; I != NumElts; ++I) {
7156 int Idx = Mask[I];
7157 if (Idx < static_cast<int>(NumElts))
7158 NewMask[I] = Idx;
7159 else
7160 NewMask[I] = Idx - NumElts + WidenNumElts;
7161 }
7162 moreElementsVectorDst(MI, MoreTy, 0);
7163 MIRBuilder.setInstrAndDebugLoc(MI);
7164 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7165 MI.getOperand(1).getReg(),
7166 MI.getOperand(2).getReg(), NewMask);
7167 MI.eraseFromParent();
7168 return Legalized;
7169}
7170
7171void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7172 ArrayRef<Register> Src1Regs,
7173 ArrayRef<Register> Src2Regs,
7174 LLT NarrowTy) {
7176 unsigned SrcParts = Src1Regs.size();
7177 unsigned DstParts = DstRegs.size();
7178
7179 unsigned DstIdx = 0; // Low bits of the result.
7180 Register FactorSum =
7181 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7182 DstRegs[DstIdx] = FactorSum;
7183
7184 Register CarrySumPrevDstIdx;
7186
7187 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7188 // Collect high parts of muls from previous DstIdx.
7189 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7190 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7191 MachineInstrBuilder Umulh =
7192 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7193 Factors.push_back(Umulh.getReg(0));
7194 }
7195 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7196 // the low Src1 part, so multiply-add selectors can use it as the first
7197 // accumulated cross product.
7198 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7199 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7200 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7201 unsigned i = RevI - 1;
7203 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7204 Factors.push_back(Mul.getReg(0));
7205 }
7206 // Add CarrySum from additions calculated for previous DstIdx.
7207 if (DstIdx != 1) {
7208 Factors.push_back(CarrySumPrevDstIdx);
7209 }
7210
7211 Register CarrySum;
7212 // Add all factors and accumulate all carries into CarrySum.
7213 if (DstIdx != DstParts - 1) {
7214 MachineInstrBuilder Uaddo =
7215 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7216 FactorSum = Uaddo.getReg(0);
7217 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7218 for (unsigned i = 2; i < Factors.size(); ++i) {
7219 MachineInstrBuilder Uaddo =
7220 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7221 FactorSum = Uaddo.getReg(0);
7222 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7223 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7224 }
7225 } else {
7226 // Since value for the next index is not calculated, neither is CarrySum.
7227 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7228 for (unsigned i = 2; i < Factors.size(); ++i)
7229 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7230 }
7231
7232 CarrySumPrevDstIdx = CarrySum;
7233 DstRegs[DstIdx] = FactorSum;
7234 Factors.clear();
7235 }
7236}
7237
7240 LLT NarrowTy) {
7241 if (TypeIdx != 0)
7242 return UnableToLegalize;
7243
7244 Register DstReg = MI.getOperand(0).getReg();
7245 LLT DstType = MRI.getType(DstReg);
7246 // FIXME: add support for vector types
7247 if (DstType.isVector())
7248 return UnableToLegalize;
7249
7250 unsigned Opcode = MI.getOpcode();
7251 unsigned OpO, OpE, OpF;
7252 switch (Opcode) {
7253 case TargetOpcode::G_SADDO:
7254 case TargetOpcode::G_SADDE:
7255 case TargetOpcode::G_UADDO:
7256 case TargetOpcode::G_UADDE:
7257 case TargetOpcode::G_ADD:
7258 OpO = TargetOpcode::G_UADDO;
7259 OpE = TargetOpcode::G_UADDE;
7260 OpF = TargetOpcode::G_UADDE;
7261 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7262 OpF = TargetOpcode::G_SADDE;
7263 break;
7264 case TargetOpcode::G_SSUBO:
7265 case TargetOpcode::G_SSUBE:
7266 case TargetOpcode::G_USUBO:
7267 case TargetOpcode::G_USUBE:
7268 case TargetOpcode::G_SUB:
7269 OpO = TargetOpcode::G_USUBO;
7270 OpE = TargetOpcode::G_USUBE;
7271 OpF = TargetOpcode::G_USUBE;
7272 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7273 OpF = TargetOpcode::G_SSUBE;
7274 break;
7275 default:
7276 llvm_unreachable("Unexpected add/sub opcode!");
7277 }
7278
7279 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7280 unsigned NumDefs = MI.getNumExplicitDefs();
7281 Register Src1 = MI.getOperand(NumDefs).getReg();
7282 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7283 Register CarryDst, CarryIn;
7284 if (NumDefs == 2)
7285 CarryDst = MI.getOperand(1).getReg();
7286 if (MI.getNumOperands() == NumDefs + 3)
7287 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7288
7289 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7290 LLT LeftoverTy, DummyTy;
7291 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7292 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7293 MIRBuilder, MRI);
7294 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7295 MRI);
7296
7297 int NarrowParts = Src1Regs.size();
7298 Src1Regs.append(Src1Left);
7299 Src2Regs.append(Src2Left);
7300 DstRegs.reserve(Src1Regs.size());
7301
7302 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7303 Register DstReg =
7304 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7305 Register CarryOut;
7306 // Forward the final carry-out to the destination register
7307 if (i == e - 1 && CarryDst)
7308 CarryOut = CarryDst;
7309 else
7310 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7311
7312 if (!CarryIn) {
7313 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7314 {Src1Regs[i], Src2Regs[i]});
7315 } else if (i == e - 1) {
7316 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7317 {Src1Regs[i], Src2Regs[i], CarryIn});
7318 } else {
7319 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7320 {Src1Regs[i], Src2Regs[i], CarryIn});
7321 }
7322
7323 DstRegs.push_back(DstReg);
7324 CarryIn = CarryOut;
7325 }
7326 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7327 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7328 ArrayRef(DstRegs).drop_front(NarrowParts));
7329
7330 MI.eraseFromParent();
7331 return Legalized;
7332}
7333
7336 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7337
7338 LLT Ty = MRI.getType(DstReg);
7339 if (Ty.isVector())
7340 return UnableToLegalize;
7341
7342 unsigned Size = Ty.getSizeInBits();
7343 unsigned NarrowSize = NarrowTy.getSizeInBits();
7344 if (Size % NarrowSize != 0)
7345 return UnableToLegalize;
7346
7347 unsigned NumParts = Size / NarrowSize;
7348 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
7349 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7350
7351 SmallVector<Register, 2> Src1Parts, Src2Parts;
7352 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7353 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7354 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7355 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7356
7357 // Take only high half of registers if this is high mul.
7358 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7359 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7360 MI.eraseFromParent();
7361 return Legalized;
7362}
7363
7366 LLT NarrowTy) {
7367 if (TypeIdx != 0)
7368 return UnableToLegalize;
7369
7370 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7371
7372 Register Src = MI.getOperand(1).getReg();
7373 LLT SrcTy = MRI.getType(Src);
7374
7375 // If all finite floats fit into the narrowed integer type, we can just swap
7376 // out the result type. This is practically only useful for conversions from
7377 // half to at least 16-bits, so just handle the one case.
7378 if (SrcTy.getScalarType() != LLT::scalar(16) ||
7379 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7380 return UnableToLegalize;
7381
7382 Observer.changingInstr(MI);
7383 narrowScalarDst(MI, NarrowTy, 0,
7384 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7385 Observer.changedInstr(MI);
7386 return Legalized;
7387}
7388
7391 LLT NarrowTy) {
7392 if (TypeIdx != 1)
7393 return UnableToLegalize;
7394
7395 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7396
7397 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7398 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7399 // NarrowSize.
7400 if (SizeOp1 % NarrowSize != 0)
7401 return UnableToLegalize;
7402 int NumParts = SizeOp1 / NarrowSize;
7403
7404 SmallVector<Register, 2> SrcRegs, DstRegs;
7405 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7406 MIRBuilder, MRI);
7407
7408 Register OpReg = MI.getOperand(0).getReg();
7409 uint64_t OpStart = MI.getOperand(2).getImm();
7410 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7411 for (int i = 0; i < NumParts; ++i) {
7412 unsigned SrcStart = i * NarrowSize;
7413
7414 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7415 // No part of the extract uses this subregister, ignore it.
7416 continue;
7417 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7418 // The entire subregister is extracted, forward the value.
7419 DstRegs.push_back(SrcRegs[i]);
7420 continue;
7421 }
7422
7423 // OpSegStart is where this destination segment would start in OpReg if it
7424 // extended infinitely in both directions.
7425 int64_t ExtractOffset;
7426 uint64_t SegSize;
7427 if (OpStart < SrcStart) {
7428 ExtractOffset = 0;
7429 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7430 } else {
7431 ExtractOffset = OpStart - SrcStart;
7432 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7433 }
7434
7435 Register SegReg = SrcRegs[i];
7436 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7437 // A genuine extract is needed.
7438 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7439 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7440 }
7441
7442 DstRegs.push_back(SegReg);
7443 }
7444
7445 Register DstReg = MI.getOperand(0).getReg();
7446 if (MRI.getType(DstReg).isVector())
7447 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7448 else if (DstRegs.size() > 1)
7449 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7450 else
7451 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7452 MI.eraseFromParent();
7453 return Legalized;
7454}
7455
7458 LLT NarrowTy) {
7459 // FIXME: Don't know how to handle secondary types yet.
7460 if (TypeIdx != 0)
7461 return UnableToLegalize;
7462
7463 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7464 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7465 LLT LeftoverTy;
7466 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7467 LeftoverRegs, MIRBuilder, MRI);
7468
7469 SrcRegs.append(LeftoverRegs);
7470
7471 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7472 Register OpReg = MI.getOperand(2).getReg();
7473 uint64_t OpStart = MI.getOperand(3).getImm();
7474 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7475 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7476 unsigned DstStart = I * NarrowSize;
7477
7478 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7479 // The entire subregister is defined by this insert, forward the new
7480 // value.
7481 DstRegs.push_back(OpReg);
7482 continue;
7483 }
7484
7485 Register SrcReg = SrcRegs[I];
7486 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7487 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7488 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7489 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7490 }
7491
7492 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7493 // No part of the insert affects this subregister, forward the original.
7494 DstRegs.push_back(SrcReg);
7495 continue;
7496 }
7497
7498 // OpSegStart is where this destination segment would start in OpReg if it
7499 // extended infinitely in both directions.
7500 int64_t ExtractOffset, InsertOffset;
7501 uint64_t SegSize;
7502 if (OpStart < DstStart) {
7503 InsertOffset = 0;
7504 ExtractOffset = DstStart - OpStart;
7505 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7506 } else {
7507 InsertOffset = OpStart - DstStart;
7508 ExtractOffset = 0;
7509 SegSize =
7510 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
7511 }
7512
7513 Register SegReg = OpReg;
7514 if (ExtractOffset != 0 || SegSize != OpSize) {
7515 // A genuine extract is needed.
7516 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7517 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7518 }
7519
7520 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7521 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7522 DstRegs.push_back(DstReg);
7523 }
7524
7525 uint64_t WideSize = DstRegs.size() * NarrowSize;
7526 Register DstReg = MI.getOperand(0).getReg();
7527 if (WideSize > RegTy.getSizeInBits()) {
7528 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7529 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7530 MIRBuilder.buildTrunc(DstReg, MergeReg);
7531 } else
7532 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7533
7534 MI.eraseFromParent();
7535 return Legalized;
7536}
7537
7540 LLT NarrowTy) {
7541 Register DstReg = MI.getOperand(0).getReg();
7542 LLT DstTy = MRI.getType(DstReg);
7543
7544 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7545
7546 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7547 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7548 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7549 LLT LeftoverTy;
7550 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7551 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7552 return UnableToLegalize;
7553
7554 LLT Unused;
7555 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7556 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7557 llvm_unreachable("inconsistent extractParts result");
7558
7559 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7560 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7561 {Src0Regs[I], Src1Regs[I]});
7562 DstRegs.push_back(Inst.getReg(0));
7563 }
7564
7565 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7566 auto Inst = MIRBuilder.buildInstr(
7567 MI.getOpcode(),
7568 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7569 DstLeftoverRegs.push_back(Inst.getReg(0));
7570 }
7571
7572 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7573 LeftoverTy, DstLeftoverRegs);
7574
7575 MI.eraseFromParent();
7576 return Legalized;
7577}
7578
7581 LLT NarrowTy) {
7582 if (TypeIdx != 0)
7583 return UnableToLegalize;
7584
7585 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7586
7587 LLT DstTy = MRI.getType(DstReg);
7588 if (DstTy.isVector())
7589 return UnableToLegalize;
7590
7592 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7593 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7594 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7595
7596 MI.eraseFromParent();
7597 return Legalized;
7598}
7599
7602 LLT NarrowTy) {
7603 if (TypeIdx != 0)
7604 return UnableToLegalize;
7605
7606 Register CondReg = MI.getOperand(1).getReg();
7607 LLT CondTy = MRI.getType(CondReg);
7608 if (CondTy.isVector()) // TODO: Handle vselect
7609 return UnableToLegalize;
7610
7611 Register DstReg = MI.getOperand(0).getReg();
7612 LLT DstTy = MRI.getType(DstReg);
7613
7614 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7615 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7616 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7617 LLT LeftoverTy;
7618 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7619 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7620 return UnableToLegalize;
7621
7622 LLT Unused;
7623 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7624 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7625 llvm_unreachable("inconsistent extractParts result");
7626
7627 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7628 auto Select = MIRBuilder.buildSelect(NarrowTy,
7629 CondReg, Src1Regs[I], Src2Regs[I]);
7630 DstRegs.push_back(Select.getReg(0));
7631 }
7632
7633 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7634 auto Select = MIRBuilder.buildSelect(
7635 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7636 DstLeftoverRegs.push_back(Select.getReg(0));
7637 }
7638
7639 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7640 LeftoverTy, DstLeftoverRegs);
7641
7642 MI.eraseFromParent();
7643 return Legalized;
7644}
7645
7648 LLT NarrowTy) {
7649 if (TypeIdx != 1)
7650 return UnableToLegalize;
7651
7652 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7653 unsigned NarrowSize = NarrowTy.getSizeInBits();
7654
7655 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7656 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7657
7659 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7660 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7661 auto C_0 = B.buildConstant(NarrowTy, 0);
7662 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7663 UnmergeSrc.getReg(1), C_0);
7664 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7665 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7666 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7667 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7668 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7669 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7670
7671 MI.eraseFromParent();
7672 return Legalized;
7673 }
7674
7675 return UnableToLegalize;
7676}
7677
7680 LLT NarrowTy) {
7681 if (TypeIdx != 1)
7682 return UnableToLegalize;
7683
7684 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7685 unsigned NarrowSize = NarrowTy.getSizeInBits();
7686
7687 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7688 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7689
7691 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7692 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7693 auto C_0 = B.buildConstant(NarrowTy, 0);
7694 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
7695 UnmergeSrc.getReg(0), C_0);
7696 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7697 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7698 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7699 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7700 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7701 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7702
7703 MI.eraseFromParent();
7704 return Legalized;
7705 }
7706
7707 return UnableToLegalize;
7708}
7709
7712 LLT NarrowTy) {
7713 if (TypeIdx != 1)
7714 return UnableToLegalize;
7715
7716 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7717 unsigned NarrowSize = NarrowTy.getSizeInBits();
7718
7719 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7720 return UnableToLegalize;
7721
7723
7724 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7725 Register Lo = UnmergeSrc.getReg(0);
7726 Register Hi = UnmergeSrc.getReg(1);
7727
7728 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7729 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7730
7731 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7732
7733 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7734 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7735 // Otherwise the leading zeros represent additional sign bits of the original
7736 // value.
7737 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7738 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7739
7740 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7741 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7742 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7743
7744 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7745
7746 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7747
7748 MI.eraseFromParent();
7749 return Legalized;
7750}
7751
7754 LLT NarrowTy) {
7755 if (TypeIdx != 1)
7756 return UnableToLegalize;
7757
7758 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7759 unsigned NarrowSize = NarrowTy.getSizeInBits();
7760
7761 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7762 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
7763
7764 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
7765 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
7766 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
7767
7768 MI.eraseFromParent();
7769 return Legalized;
7770 }
7771
7772 return UnableToLegalize;
7773}
7774
7777 LLT NarrowTy) {
7778 if (TypeIdx != 1)
7779 return UnableToLegalize;
7780
7782 Register ExpReg = MI.getOperand(2).getReg();
7783 LLT ExpTy = MRI.getType(ExpReg);
7784
7785 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
7786
7787 // Clamp the exponent to the range of the target type.
7788 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
7789 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
7790 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
7791 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
7792
7793 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
7794 Observer.changingInstr(MI);
7795 MI.getOperand(2).setReg(Trunc.getReg(0));
7796 Observer.changedInstr(MI);
7797 return Legalized;
7798}
7799
7802 unsigned Opc = MI.getOpcode();
7803 const auto &TII = MIRBuilder.getTII();
7804 auto isSupported = [this](const LegalityQuery &Q) {
7805 auto QAction = LI.getAction(Q).Action;
7806 return QAction == Legal || QAction == Libcall || QAction == Custom;
7807 };
7808 switch (Opc) {
7809 default:
7810 return UnableToLegalize;
7811 case TargetOpcode::G_CTLZ_ZERO_POISON: {
7812 // This trivially expands to CTLZ.
7813 Observer.changingInstr(MI);
7814 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
7815 Observer.changedInstr(MI);
7816 return Legalized;
7817 }
7818 case TargetOpcode::G_CTLZ: {
7819 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7820 unsigned Len = SrcTy.getScalarSizeInBits();
7821
7822 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
7823 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
7824 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
7825 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
7826 auto ICmp = MIRBuilder.buildICmp(
7827 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
7828 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7829 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
7830 MI.eraseFromParent();
7831 return Legalized;
7832 }
7833 // for now, we do this:
7834 // NewLen = NextPowerOf2(Len);
7835 // x = x | (x >> 1);
7836 // x = x | (x >> 2);
7837 // ...
7838 // x = x | (x >>16);
7839 // x = x | (x >>32); // for 64-bit input
7840 // Upto NewLen/2
7841 // return Len - popcount(x);
7842 //
7843 // Ref: "Hacker's Delight" by Henry Warren
7844 Register Op = SrcReg;
7845 unsigned NewLen = PowerOf2Ceil(Len);
7846 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
7847 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
7848 auto MIBOp = MIRBuilder.buildOr(
7849 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
7850 Op = MIBOp.getReg(0);
7851 }
7852 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
7853 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
7854 MIBPop);
7855 MI.eraseFromParent();
7856 return Legalized;
7857 }
7858 case TargetOpcode::G_CTTZ_ZERO_POISON: {
7859 // This trivially expands to CTTZ.
7860 Observer.changingInstr(MI);
7861 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
7862 Observer.changedInstr(MI);
7863 return Legalized;
7864 }
7865 case TargetOpcode::G_CTTZ: {
7866 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7867
7868 unsigned Len = SrcTy.getScalarSizeInBits();
7869 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
7870 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
7871 // zero.
7872 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
7873 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
7874 auto ICmp = MIRBuilder.buildICmp(
7875 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
7876 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7877 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
7878 MI.eraseFromParent();
7879 return Legalized;
7880 }
7881 // for now, we use: { return popcount(~x & (x - 1)); }
7882 // unless the target has ctlz but not ctpop, in which case we use:
7883 // { return 32 - nlz(~x & (x-1)); }
7884 // Ref: "Hacker's Delight" by Henry Warren
7885 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
7886 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
7887 auto MIBTmp = MIRBuilder.buildAnd(
7888 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
7889 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
7890 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
7891 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
7892 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
7893 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
7894 MI.eraseFromParent();
7895 return Legalized;
7896 }
7897 Observer.changingInstr(MI);
7898 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
7899 MI.getOperand(1).setReg(MIBTmp.getReg(0));
7900 Observer.changedInstr(MI);
7901 return Legalized;
7902 }
7903 case TargetOpcode::G_CTPOP: {
7904 Register SrcReg = MI.getOperand(1).getReg();
7905 LLT Ty = MRI.getType(SrcReg);
7906 unsigned Size = Ty.getScalarSizeInBits();
7908
7909 // Bail out on irregular type lengths.
7910 if (Size > 128 || Size % 8 != 0)
7911 return UnableToLegalize;
7912
7913 // Count set bits in blocks of 2 bits. Default approach would be
7914 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
7915 // We use following formula instead:
7916 // B2Count = val - { (val >> 1) & 0x55555555 }
7917 // since it gives same result in blocks of 2 with one instruction less.
7918 auto C_1 = B.buildConstant(Ty, 1);
7919 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
7920 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
7921 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
7922 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
7923 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
7924
7925 // In order to get count in blocks of 4 add values from adjacent block of 2.
7926 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
7927 auto C_2 = B.buildConstant(Ty, 2);
7928 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
7929 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
7930 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
7931 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
7932 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
7933 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
7934
7935 // For count in blocks of 8 bits we don't have to mask high 4 bits before
7936 // addition since count value sits in range {0,...,8} and 4 bits are enough
7937 // to hold such binary values. After addition high 4 bits still hold count
7938 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
7939 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
7940 auto C_4 = B.buildConstant(Ty, 4);
7941 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
7942 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
7943 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
7944 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
7945 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
7946
7947 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
7948
7949 // Avoid the multiply when shift-add is cheaper.
7950 if (Size == 16 && !Ty.isVector()) {
7951 // v = (v + (v >> 8)) & 0xFF;
7952 auto C_8 = B.buildConstant(Ty, 8);
7953 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
7954 auto Res = B.buildAdd(Ty, B8Count, HighSum);
7955 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
7956 MI.eraseFromParent();
7957 return Legalized;
7958 }
7959
7960 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
7961 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
7962 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
7963
7964 // Shift count result from 8 high bits to low bits.
7965 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
7966
7967 auto IsMulSupported = [this](const LLT Ty) {
7968 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
7969 return Action == Legal || Action == WidenScalar || Action == Custom;
7970 };
7971 if (IsMulSupported(Ty)) {
7972 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
7973 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
7974 } else {
7975 auto ResTmp = B8Count;
7976 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
7977 auto ShiftC = B.buildConstant(Ty, Shift);
7978 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
7979 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
7980 }
7981 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
7982 }
7983 MI.eraseFromParent();
7984 return Legalized;
7985 }
7986 case TargetOpcode::G_CTLS: {
7987 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7988
7989 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
7990 auto SignIdxC =
7991 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
7992 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
7993
7994 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
7995
7996 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
7997 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
7998
7999 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8000 MI.eraseFromParent();
8001 return Legalized;
8002 }
8003 }
8004}
8005
8006// Check that (every element of) Reg is undef or not an exact multiple of BW.
8008 Register Reg, unsigned BW) {
8009 return matchUnaryPredicate(
8010 MRI, Reg,
8011 [=](const Constant *C) {
8012 // Null constant here means an undef.
8014 return !CI || CI->getValue().urem(BW) != 0;
8015 },
8016 /*AllowUndefs*/ true);
8017}
8018
8021 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8022 LLT Ty = MRI.getType(Dst);
8023 LLT ShTy = MRI.getType(Z);
8024
8025 unsigned BW = Ty.getScalarSizeInBits();
8026
8027 if (!isPowerOf2_32(BW))
8028 return UnableToLegalize;
8029
8030 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8031 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8032
8033 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8034 // fshl X, Y, Z -> fshr X, Y, -Z
8035 // fshr X, Y, Z -> fshl X, Y, -Z
8036 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8037 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8038 } else {
8039 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8040 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8041 auto One = MIRBuilder.buildConstant(ShTy, 1);
8042 if (IsFSHL) {
8043 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8044 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8045 } else {
8046 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8047 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8048 }
8049
8050 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8051 }
8052
8053 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8054 MI.eraseFromParent();
8055 return Legalized;
8056}
8057
8060 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8061 LLT Ty = MRI.getType(Dst);
8062 LLT ShTy = MRI.getType(Z);
8063
8064 const unsigned BW = Ty.getScalarSizeInBits();
8065 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8066
8067 Register ShX, ShY;
8068 Register ShAmt, InvShAmt;
8069
8070 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8071 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8072 // fshl: X << C | Y >> (BW - C)
8073 // fshr: X << (BW - C) | Y >> C
8074 // where C = Z % BW is not zero
8075 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8076 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8077 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8078 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8079 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8080 } else {
8081 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8082 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8083 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8084 if (isPowerOf2_32(BW)) {
8085 // Z % BW -> Z & (BW - 1)
8086 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8087 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8088 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8089 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8090 } else {
8091 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8092 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8093 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8094 }
8095
8096 auto One = MIRBuilder.buildConstant(ShTy, 1);
8097 if (IsFSHL) {
8098 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8099 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8100 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8101 } else {
8102 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8103 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8104 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8105 }
8106 }
8107
8108 MIRBuilder.buildOr(Dst, ShX, ShY, MachineInstr::Disjoint);
8109 MI.eraseFromParent();
8110 return Legalized;
8111}
8112
8115 // These operations approximately do the following (while avoiding undefined
8116 // shifts by BW):
8117 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8118 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8119 Register Dst = MI.getOperand(0).getReg();
8120 LLT Ty = MRI.getType(Dst);
8121 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8122
8123 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8124 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8125
8126 // TODO: Use smarter heuristic that accounts for vector legalization.
8127 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8128 return lowerFunnelShiftAsShifts(MI);
8129
8130 // This only works for powers of 2, fallback to shifts if it fails.
8131 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8132 if (Result == UnableToLegalize)
8133 return lowerFunnelShiftAsShifts(MI);
8134 return Result;
8135}
8136
8138 auto [Dst, Src] = MI.getFirst2Regs();
8139 LLT DstTy = MRI.getType(Dst);
8140 LLT SrcTy = MRI.getType(Src);
8141
8142 uint32_t DstTySize = DstTy.getSizeInBits();
8143 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8144 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8145
8146 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8147 !isPowerOf2_32(SrcTyScalarSize))
8148 return UnableToLegalize;
8149
8150 // The step between extend is too large, split it by creating an intermediate
8151 // extend instruction
8152 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8153 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8154 // If the destination type is illegal, split it into multiple statements
8155 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8156 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8157 // Unmerge the vector
8158 LLT EltTy = MidTy.changeElementCount(
8160 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8161
8162 // ZExt the vectors
8163 LLT ZExtResTy = DstTy.changeElementCount(
8165 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8166 {UnmergeSrc.getReg(0)});
8167 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8168 {UnmergeSrc.getReg(1)});
8169
8170 // Merge the ending vectors
8171 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8172
8173 MI.eraseFromParent();
8174 return Legalized;
8175 }
8176 return UnableToLegalize;
8177}
8178
8180 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8181 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8182 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8183 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8184 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8185 // %lo16(<4 x s16>) = G_TRUNC %inlo
8186 // %hi16(<4 x s16>) = G_TRUNC %inhi
8187 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8188 // %res(<8 x s8>) = G_TRUNC %in16
8189
8190 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8191
8192 Register DstReg = MI.getOperand(0).getReg();
8193 Register SrcReg = MI.getOperand(1).getReg();
8194 LLT DstTy = MRI.getType(DstReg);
8195 LLT SrcTy = MRI.getType(SrcReg);
8196
8197 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8199 isPowerOf2_32(SrcTy.getNumElements()) &&
8200 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8201 // Split input type.
8202 LLT SplitSrcTy = SrcTy.changeElementCount(
8203 SrcTy.getElementCount().divideCoefficientBy(2));
8204
8205 // First, split the source into two smaller vectors.
8206 SmallVector<Register, 2> SplitSrcs;
8207 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8208
8209 // Truncate the splits into intermediate narrower elements.
8210 LLT InterTy;
8211 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8212 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8213 else
8214 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8215 for (Register &Src : SplitSrcs)
8216 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8217
8218 // Combine the new truncates into one vector
8219 auto Merge = MIRBuilder.buildMergeLikeInstr(
8220 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8221
8222 // Truncate the new vector to the final result type
8223 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8224 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8225 else
8226 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8227
8228 MI.eraseFromParent();
8229
8230 return Legalized;
8231 }
8232 return UnableToLegalize;
8233}
8234
8237 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8238 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8239 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8240 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8241 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8242 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8243 MI.eraseFromParent();
8244 return Legalized;
8245}
8246
8248 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8249
8250 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8251 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8252
8253 MIRBuilder.setInstrAndDebugLoc(MI);
8254
8255 // If a rotate in the other direction is supported, use it.
8256 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8257 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8258 isPowerOf2_32(EltSizeInBits))
8259 return lowerRotateWithReverseRotate(MI);
8260
8261 // If a funnel shift is supported, use it.
8262 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8263 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8264 bool IsFShLegal = false;
8265 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8266 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8267 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8268 Register R3) {
8269 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8270 MI.eraseFromParent();
8271 return Legalized;
8272 };
8273 // If a funnel shift in the other direction is supported, use it.
8274 if (IsFShLegal) {
8275 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8276 } else if (isPowerOf2_32(EltSizeInBits)) {
8277 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8278 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8279 }
8280 }
8281
8282 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8283 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8284 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8285 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8286 Register ShVal;
8287 Register RevShiftVal;
8288 if (isPowerOf2_32(EltSizeInBits)) {
8289 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8290 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8291 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8292 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8293 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8294 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8295 RevShiftVal =
8296 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8297 } else {
8298 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8299 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8300 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8301 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8302 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8303 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8304 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8305 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8306 RevShiftVal =
8307 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8308 }
8309 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, MachineInstr::Disjoint);
8310 MI.eraseFromParent();
8311 return Legalized;
8312}
8313
8314// Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
8315// representation.
8318 auto [Dst, Src] = MI.getFirst2Regs();
8319 const LLT S64 = LLT::scalar(64);
8320 const LLT S32 = LLT::scalar(32);
8321 const LLT S1 = LLT::scalar(1);
8322
8323 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8324
8325 // unsigned cul2f(ulong u) {
8326 // uint lz = clz(u);
8327 // uint e = (u != 0) ? 127U + 63U - lz : 0;
8328 // u = (u << lz) & 0x7fffffffffffffffUL;
8329 // ulong t = u & 0xffffffffffUL;
8330 // uint v = (e << 23) | (uint)(u >> 40);
8331 // uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
8332 // return as_float(v + r);
8333 // }
8334
8335 auto Zero32 = MIRBuilder.buildConstant(S32, 0);
8336 auto Zero64 = MIRBuilder.buildConstant(S64, 0);
8337
8338 auto LZ = MIRBuilder.buildCTLZ_ZERO_POISON(S32, Src);
8339
8340 auto K = MIRBuilder.buildConstant(S32, 127U + 63U);
8341 auto Sub = MIRBuilder.buildSub(S32, K, LZ);
8342
8343 auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);
8344 auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);
8345
8346 auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);
8347 auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);
8348
8349 auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);
8350
8351 auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);
8352 auto T = MIRBuilder.buildAnd(S64, U, Mask1);
8353
8354 auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));
8355 auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));
8356 auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));
8357
8358 auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);
8359 auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);
8360 auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);
8361 auto One = MIRBuilder.buildConstant(S32, 1);
8362
8363 auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);
8364 auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);
8365 auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);
8366 MIRBuilder.buildAdd(Dst, V, R);
8367
8368 MI.eraseFromParent();
8369 return Legalized;
8370}
8371
8372// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8373// operations and G_SITOFP
8376 auto [Dst, Src] = MI.getFirst2Regs();
8377 const LLT S64 = LLT::scalar(64);
8378 const LLT S32 = LLT::scalar(32);
8379 const LLT S1 = LLT::scalar(1);
8380
8381 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8382
8383 // For i64 < INT_MAX we simply reuse SITOFP.
8384 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8385 // saved before division, convert to float by SITOFP, multiply the result
8386 // by 2.
8387 auto One = MIRBuilder.buildConstant(S64, 1);
8388 auto Zero = MIRBuilder.buildConstant(S64, 0);
8389 // Result if Src < INT_MAX
8390 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8391 // Result if Src >= INT_MAX
8392 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8393 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8394 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8395 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8396 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8397 // Check if the original value is larger than INT_MAX by comparing with
8398 // zero to pick one of the two conversions.
8399 auto IsLarge =
8400 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
8401 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8402
8403 MI.eraseFromParent();
8404 return Legalized;
8405}
8406
8407// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8408// IEEE double representation.
8411 auto [Dst, Src] = MI.getFirst2Regs();
8412 const LLT S64 = LLT::scalar(64);
8413 const LLT S32 = LLT::scalar(32);
8414
8415 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8416
8417 // We create double value from 32 bit parts with 32 exponent difference.
8418 // Note that + and - are float operations that adjust the implicit leading
8419 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8420 //
8421 // X = 2^52 * 1.0...LowBits
8422 // Y = 2^84 * 1.0...HighBits
8423 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8424 // = - 2^52 * 1.0...HighBits
8425 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8426 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8427 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8428 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8429 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8430 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8431
8432 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8433 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8434 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8435 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8436 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8437 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8438 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8439
8440 MI.eraseFromParent();
8441 return Legalized;
8442}
8443
8444/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8445/// convert fpround f64->f16 without double-rounding, so we manually perform the
8446/// lowering here where we know it is valid.
8449 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8450 auto DstFpTy =
8451 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8452 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8453 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8454 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8455 LLT F32Ty = DstFpTy.changeElementSize(32);
8456 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8457 MIRBuilder.buildFPTrunc(Dst, M2);
8458 MI.eraseFromParent();
8460}
8461
8463 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8464
8465 if (SrcTy == LLT::scalar(1)) {
8466 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8467 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8468 MIRBuilder.buildSelect(Dst, Src, True, False);
8469 MI.eraseFromParent();
8470 return Legalized;
8471 }
8472
8473 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8474 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8475
8476 if (SrcTy != LLT::scalar(64))
8477 return UnableToLegalize;
8478
8479 if (DstTy == LLT::scalar(32))
8480 // TODO: SelectionDAG has several alternative expansions to port which may
8481 // be more reasonable depending on the available instructions. We also need
8482 // a more advanced mechanism to choose an optimal version depending on
8483 // target features such as sitofp or CTLZ availability.
8485
8486 if (DstTy == LLT::scalar(64))
8488
8489 return UnableToLegalize;
8490}
8491
8493 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8494
8495 const LLT I64 = LLT::integer(64);
8496 const LLT I32 = LLT::integer(32);
8497 const LLT I1 = LLT::integer(1);
8498
8499 if (SrcTy == I1) {
8500 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8501 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8502 MIRBuilder.buildSelect(Dst, Src, True, False);
8503 MI.eraseFromParent();
8504 return Legalized;
8505 }
8506
8507 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8508 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8509
8510 if (SrcTy != I64)
8511 return UnableToLegalize;
8512
8513 if (DstTy.getScalarSizeInBits() == 32) {
8514 // signed cl2f(long l) {
8515 // long s = l >> 63;
8516 // float r = cul2f((l + s) ^ s);
8517 // return s ? -r : r;
8518 // }
8519 Register L = Src;
8520 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8521 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8522
8523 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8524 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8525 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8526
8527 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8528 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8529 MIRBuilder.buildConstant(I64, 0));
8530 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8531 MI.eraseFromParent();
8532 return Legalized;
8533 }
8534
8535 return UnableToLegalize;
8536}
8537
8539 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8540 const LLT S64 = LLT::scalar(64);
8541 const LLT S32 = LLT::scalar(32);
8542
8543 if (SrcTy != S64 && SrcTy != S32)
8544 return UnableToLegalize;
8545 if (DstTy != S32 && DstTy != S64)
8546 return UnableToLegalize;
8547
8548 // FPTOSI gives same result as FPTOUI for positive signed integers.
8549 // FPTOUI needs to deal with fp values that convert to unsigned integers
8550 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8551
8552 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8553 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8555 APInt::getZero(SrcTy.getSizeInBits()));
8556 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8557
8558 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8559
8560 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8561 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8562 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8563 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8564 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8565 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8566 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8567
8568 const LLT S1 = LLT::scalar(1);
8569
8570 MachineInstrBuilder FCMP =
8571 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8572 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8573
8574 MI.eraseFromParent();
8575 return Legalized;
8576}
8577
8579 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8580 const LLT S64 = LLT::scalar(64);
8581 const LLT S32 = LLT::scalar(32);
8582
8583 // FIXME: Only f32 to i64 conversions are supported.
8584 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8585 return UnableToLegalize;
8586
8587 // Expand f32 -> i64 conversion
8588 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8589 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8590
8591 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8592
8593 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8594 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8595
8596 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8597 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8598
8599 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8600 APInt::getSignMask(SrcEltBits));
8601 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8602 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8603 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8604 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8605
8606 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8607 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8608 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8609
8610 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8611 R = MIRBuilder.buildZExt(DstTy, R);
8612
8613 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8614 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8615 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8616 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8617
8618 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8619 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8620
8621 const LLT S1 = LLT::scalar(1);
8622 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8623 S1, Exponent, ExponentLoBit);
8624
8625 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8626
8627 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8628 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8629
8630 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8631
8632 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8633 S1, Exponent, ZeroSrcTy);
8634
8635 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8636 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8637
8638 MI.eraseFromParent();
8639 return Legalized;
8640}
8641
8644 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8645
8646 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8647 unsigned SatWidth = DstTy.getScalarSizeInBits();
8648
8649 // Determine minimum and maximum integer values and their corresponding
8650 // floating-point values.
8651 APInt MinInt, MaxInt;
8652 if (IsSigned) {
8653 MinInt = APInt::getSignedMinValue(SatWidth);
8654 MaxInt = APInt::getSignedMaxValue(SatWidth);
8655 } else {
8656 MinInt = APInt::getMinValue(SatWidth);
8657 MaxInt = APInt::getMaxValue(SatWidth);
8658 }
8659
8660 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8661 APFloat MinFloat(Semantics);
8662 APFloat MaxFloat(Semantics);
8663
8664 APFloat::opStatus MinStatus =
8665 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8666 APFloat::opStatus MaxStatus =
8667 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8668 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8669 !(MaxStatus & APFloat::opStatus::opInexact);
8670
8671 // If the integer bounds are exactly representable as floats, emit a
8672 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8673 // and selects.
8674 if (AreExactFloatBounds) {
8675 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8676 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8677 auto MaxP =
8678 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8679 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8680 // Clamp by MaxFloat from above. NaN cannot occur.
8681 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8682 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8684 auto Min =
8685 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8686 // Convert clamped value to integer. In the unsigned case we're done,
8687 // because we mapped NaN to MinFloat, which will cast to zero.
8688 if (!IsSigned) {
8689 MIRBuilder.buildFPTOUI(Dst, Min);
8690 MI.eraseFromParent();
8691 return Legalized;
8692 }
8693
8694 // Otherwise, select 0 if Src is NaN.
8695 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8696 auto IsZero =
8697 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8698 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8699 FpToInt);
8700 MI.eraseFromParent();
8701 return Legalized;
8702 }
8703
8704 // Result of direct conversion. The assumption here is that the operation is
8705 // non-trapping and it's fine to apply it to an out-of-range value if we
8706 // select it away later.
8707 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8708 : MIRBuilder.buildFPTOUI(DstTy, Src);
8709
8710 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8711 // MinInt if Src is NaN.
8712 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8713 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8714 auto Max = MIRBuilder.buildSelect(
8715 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8716 // If Src OGT MaxFloat, select MaxInt.
8717 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8718 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8719
8720 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8721 // is already zero.
8722 if (!IsSigned) {
8723 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8724 Max);
8725 MI.eraseFromParent();
8726 return Legalized;
8727 }
8728
8729 // Otherwise, select 0 if Src is NaN.
8730 auto Min = MIRBuilder.buildSelect(
8731 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8732 auto IsZero =
8733 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8734 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8735 MI.eraseFromParent();
8736 return Legalized;
8737}
8738
8739// Floating-point conversions using truncating and extending loads and stores.
8742 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8743 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8744 "Only G_FPEXT and G_FPTRUNC are expected");
8745
8746 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8747 MachinePointerInfo PtrInfo;
8748 unsigned StoreOpc;
8749 unsigned LoadOpc;
8750 LLT StackTy;
8751 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8752 StackTy = SrcTy;
8753 StoreOpc = TargetOpcode::G_STORE;
8754 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8755 } else {
8756 StackTy = DstTy;
8757 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8758 LoadOpc = TargetOpcode::G_LOAD;
8759 }
8760
8761 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8762 auto StackTemp =
8763 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8764
8765 MachineFunction &MF = MIRBuilder.getMF();
8766 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8767 StackTy, StackTyAlign);
8768 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8769
8770 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8771 StackTy, StackTyAlign);
8772 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8773
8774 MI.eraseFromParent();
8775 return Legalized;
8776}
8777
8778// f64 -> f16 conversion using round-to-nearest-even rounding mode.
8781 const LLT S1 = LLT::scalar(1);
8782 const LLT S32 = LLT::scalar(32);
8783
8784 auto [Dst, Src] = MI.getFirst2Regs();
8785 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
8786 MRI.getType(Src).getScalarType() == LLT::float64());
8787
8788 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
8789 return UnableToLegalize;
8790
8791 if (MI.getFlag(MachineInstr::FmAfn)) {
8792 unsigned Flags = MI.getFlags();
8793 auto Src32 = MIRBuilder.buildFPTrunc(S32, Src, Flags);
8794 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
8795 MI.eraseFromParent();
8796 return Legalized;
8797 }
8798
8799 const unsigned ExpMask = 0x7ff;
8800 const unsigned ExpBiasf64 = 1023;
8801 const unsigned ExpBiasf16 = 15;
8802
8803 auto Unmerge = MIRBuilder.buildUnmerge(S32, Src);
8804 Register U = Unmerge.getReg(0);
8805 Register UH = Unmerge.getReg(1);
8806
8807 auto E = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 20));
8808 E = MIRBuilder.buildAnd(S32, E, MIRBuilder.buildConstant(S32, ExpMask));
8809
8810 // Subtract the fp64 exponent bias (1023) to get the real exponent and
8811 // add the f16 bias (15) to get the biased exponent for the f16 format.
8812 E = MIRBuilder.buildAdd(
8813 S32, E, MIRBuilder.buildConstant(S32, -ExpBiasf64 + ExpBiasf16));
8814
8815 auto M = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 8));
8816 M = MIRBuilder.buildAnd(S32, M, MIRBuilder.buildConstant(S32, 0xffe));
8817
8818 auto MaskedSig = MIRBuilder.buildAnd(S32, UH,
8819 MIRBuilder.buildConstant(S32, 0x1ff));
8820 MaskedSig = MIRBuilder.buildOr(S32, MaskedSig, U);
8821
8822 auto Zero = MIRBuilder.buildConstant(S32, 0);
8823 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
8824 auto Lo40Set = MIRBuilder.buildZExt(S32, SigCmpNE0);
8825 M = MIRBuilder.buildOr(S32, M, Lo40Set);
8826
8827 // (M != 0 ? 0x0200 : 0) | 0x7c00;
8828 auto Bits0x200 = MIRBuilder.buildConstant(S32, 0x0200);
8829 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
8830 auto SelectCC = MIRBuilder.buildSelect(S32, CmpM_NE0, Bits0x200, Zero);
8831
8832 auto Bits0x7c00 = MIRBuilder.buildConstant(S32, 0x7c00);
8833 auto I = MIRBuilder.buildOr(S32, SelectCC, Bits0x7c00);
8834
8835 // N = M | (E << 12);
8836 auto EShl12 = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 12));
8837 auto N = MIRBuilder.buildOr(S32, M, EShl12);
8838
8839 // B = clamp(1-E, 0, 13);
8840 auto One = MIRBuilder.buildConstant(S32, 1);
8841 auto OneSubExp = MIRBuilder.buildSub(S32, One, E);
8842 auto B = MIRBuilder.buildSMax(S32, OneSubExp, Zero);
8843 B = MIRBuilder.buildSMin(S32, B, MIRBuilder.buildConstant(S32, 13));
8844
8845 auto SigSetHigh = MIRBuilder.buildOr(S32, M,
8846 MIRBuilder.buildConstant(S32, 0x1000));
8847
8848 auto D = MIRBuilder.buildLShr(S32, SigSetHigh, B);
8849 auto D0 = MIRBuilder.buildShl(S32, D, B);
8850
8851 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
8852 D0, SigSetHigh);
8853 auto D1 = MIRBuilder.buildZExt(S32, D0_NE_SigSetHigh);
8854 D = MIRBuilder.buildOr(S32, D, D1);
8855
8856 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
8857 auto V = MIRBuilder.buildSelect(S32, CmpELtOne, D, N);
8858
8859 auto VLow3 = MIRBuilder.buildAnd(S32, V, MIRBuilder.buildConstant(S32, 7));
8860 V = MIRBuilder.buildLShr(S32, V, MIRBuilder.buildConstant(S32, 2));
8861
8862 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
8863 MIRBuilder.buildConstant(S32, 3));
8864 auto V0 = MIRBuilder.buildZExt(S32, VLow3Eq3);
8865
8866 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
8867 MIRBuilder.buildConstant(S32, 5));
8868 auto V1 = MIRBuilder.buildZExt(S32, VLow3Gt5);
8869
8870 V1 = MIRBuilder.buildOr(S32, V0, V1);
8871 V = MIRBuilder.buildAdd(S32, V, V1);
8872
8873 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1,
8874 E, MIRBuilder.buildConstant(S32, 30));
8875 V = MIRBuilder.buildSelect(S32, CmpEGt30,
8876 MIRBuilder.buildConstant(S32, 0x7c00), V);
8877
8878 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1,
8879 E, MIRBuilder.buildConstant(S32, 1039));
8880 V = MIRBuilder.buildSelect(S32, CmpEGt1039, I, V);
8881
8882 // Extract the sign bit.
8883 auto Sign = MIRBuilder.buildLShr(S32, UH, MIRBuilder.buildConstant(S32, 16));
8884 Sign = MIRBuilder.buildAnd(S32, Sign, MIRBuilder.buildConstant(S32, 0x8000));
8885
8886 // Insert the sign bit
8887 V = MIRBuilder.buildOr(S32, Sign, V);
8888
8889 MIRBuilder.buildTrunc(Dst, V);
8890 MI.eraseFromParent();
8891 return Legalized;
8892}
8893
8894// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
8897 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8898 assert(DstTy.getScalarType() == LLT::bfloat16() &&
8899 SrcTy.getScalarType() == LLT::float32());
8900
8901 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
8902 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8903 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8904
8905 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
8906
8907 // Conversions should set NaN's quiet bit. This also prevents NaNs from
8908 // turning into infinities.
8909 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
8910 MIRBuilder.buildConstant(I32Ty, 0x400000));
8911
8912 // Factor in the contribution of the low 16 bits.
8913 auto Lsb =
8914 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8915 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
8916 auto RoundingBias =
8917 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
8918 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
8919
8920 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
8921 // 0x80000000.
8922 if (!MI.getFlag(MachineInstr::FmNoNans)) {
8923 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
8924 MIRBuilder.buildFConstant(SrcTy, 0));
8925 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
8926 }
8927
8928 // Now that we have rounded, shift the bits into position.
8929 auto Srl =
8930 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
8931 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
8932 MIRBuilder.buildBitcast(DstReg, Trunc);
8933 MI.eraseFromParent();
8934 return Legalized;
8935}
8936
8939 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
8940 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
8942
8943 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
8945
8946 return lowerFPExtAndTruncMem(MI);
8947}
8948
8950 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
8951 LLT Ty = MRI.getType(Dst);
8952
8953 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
8954 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
8955 MI.eraseFromParent();
8956 return Legalized;
8957}
8958
8960 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
8961 LLT Ty = MRI.getType(Src);
8962 auto Flags = MI.getFlags();
8963 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
8964
8965 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
8966 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
8967
8968 Register FracToUse;
8969 if (MI.getFlag(MachineInstr::FmNoInfs)) {
8970 FracToUse = FracPart.getReg(0);
8971 } else {
8972 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
8973 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
8974 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
8975 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
8976 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
8977 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
8978 FracToUse = Select.getReg(0);
8979 }
8980
8981 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
8982 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
8983
8984 MI.eraseFromParent();
8985 return Legalized;
8986}
8987
8989 switch (Opc) {
8990 case TargetOpcode::G_SMIN:
8991 return CmpInst::ICMP_SLT;
8992 case TargetOpcode::G_SMAX:
8993 return CmpInst::ICMP_SGT;
8994 case TargetOpcode::G_UMIN:
8995 return CmpInst::ICMP_ULT;
8996 case TargetOpcode::G_UMAX:
8997 return CmpInst::ICMP_UGT;
8998 default:
8999 llvm_unreachable("not in integer min/max");
9000 }
9001}
9002
9004 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9005
9006 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9007 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9008
9009 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9010 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9011
9012 MI.eraseFromParent();
9013 return Legalized;
9014}
9015
9018 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9019
9020 Register Dst = Cmp->getReg(0);
9021 LLT DstTy = MRI.getType(Dst);
9022 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9023 LLT CmpTy = DstTy.changeElementSize(1);
9024
9025 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9028 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9031
9032 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9033 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9034 Cmp->getRHSReg());
9035 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9036 Cmp->getRHSReg());
9037
9038 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9039 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9040 if (TLI.preferSelectsOverBooleanArithmetic(
9041 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9043 auto One = MIRBuilder.buildConstant(DstTy, 1);
9044 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9045
9046 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9047 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9048 } else {
9050 std::swap(IsGT, IsLT);
9051 // Extend boolean results to DstTy, which is at least i2, before subtracting
9052 // them.
9053 unsigned BoolExtOp =
9054 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9055 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9056 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9057 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9058 }
9059
9060 MI.eraseFromParent();
9061 return Legalized;
9062}
9063
9066 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9067 const int Src0Size = Src0Ty.getScalarSizeInBits();
9068 const int Src1Size = Src1Ty.getScalarSizeInBits();
9069
9070 LLT DstIntTy =
9071 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9072 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9073 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9074
9075 Register Src0Int = Src0;
9076 Register Src1Int = Src1;
9077
9078 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9079 Src0Ty.getScalarType().isInteger()))
9080 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9081
9082 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9083 Src1Ty.getScalarType().isInteger()))
9084 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9085
9086 auto SignBitMask =
9087 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9088
9089 auto NotSignBitMask = MIRBuilder.buildConstant(
9090 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9091
9092 Register And0 =
9093 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9094 Register And1;
9095 if (Src0Ty == Src1Ty) {
9096 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9097 } else if (Src0Size > Src1Size) {
9098 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9099 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9100 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9101 And1 = MIRBuilder.buildAnd(Src0Ty, Shift, SignBitMask).getReg(0);
9102 } else {
9103 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9104 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9105 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9106 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9107 }
9108
9109 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9110 // constants are a nan and -0.0, but the final result should preserve
9111 // everything.
9112 unsigned Flags = MI.getFlags();
9113
9114 // We masked the sign bit and the not-sign bit, so these are disjoint.
9115 Flags |= MachineInstr::Disjoint;
9116
9117 if (DstTy == DstIntTy)
9118 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9119 else {
9120 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9121 MIRBuilder.buildBitcast(Dst, NewDst);
9122 }
9123
9124 MI.eraseFromParent();
9125 return Legalized;
9126}
9127
9130 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9131 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9132 // depend on fminnum/fmaxnum.
9133
9134 unsigned NewOp;
9135 switch (MI.getOpcode()) {
9136 case TargetOpcode::G_FMINNUM:
9137 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9138 break;
9139 case TargetOpcode::G_FMINIMUMNUM:
9140 NewOp = TargetOpcode::G_FMINNUM;
9141 break;
9142 case TargetOpcode::G_FMAXNUM:
9143 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9144 break;
9145 case TargetOpcode::G_FMAXIMUMNUM:
9146 NewOp = TargetOpcode::G_FMAXNUM;
9147 break;
9148 default:
9149 llvm_unreachable("unexpected min/max opcode");
9150 }
9151
9152 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9153 LLT Ty = MRI.getType(Dst);
9154
9155 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9156 // Insert canonicalizes if it's possible we need to quiet to get correct
9157 // sNaN behavior.
9158
9159 // Note this must be done here, and not as an optimization combine in the
9160 // absence of a dedicate quiet-snan instruction as we're using an
9161 // omni-purpose G_FCANONICALIZE.
9162 if (!VT->isKnownNeverSNaN(Src0))
9163 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9164
9165 if (!VT->isKnownNeverSNaN(Src1))
9166 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9167 }
9168
9169 // If there are no nans, it's safe to simply replace this with the non-IEEE
9170 // version.
9171 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9172 MI.eraseFromParent();
9173 return Legalized;
9174}
9175
9178 unsigned Opc = MI.getOpcode();
9179 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9180 LLT Ty = MRI.getType(Dst);
9181 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9182
9183 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9184 unsigned OpcIeee =
9185 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9186 unsigned OpcNonIeee =
9187 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9188 bool MinMaxMustRespectOrderedZero = false;
9189 Register Res;
9190
9191 // IEEE variants don't need canonicalization
9192 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9193 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9194 MinMaxMustRespectOrderedZero = true;
9195 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9196 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9197 } else {
9198 auto Compare = MIRBuilder.buildFCmp(
9199 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9200 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9201 }
9202
9203 // Propagate any NaN of both operands
9204 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9205 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9206 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9207
9208 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9209 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9210 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9211 if (Ty.isVector())
9212 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9213
9214 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9215 }
9216
9217 // fminimum/fmaximum requires -0.0 less than +0.0
9218 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9219 GISelValueTracking VT(MIRBuilder.getMF());
9220 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9221 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9222
9223 if (!Src0Info.isKnownNeverZero() && !Src1Info.isKnownNeverZero()) {
9224 const unsigned Flags = MI.getFlags();
9225 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9226 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9227
9228 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9229
9230 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9231 auto LHSSelect =
9232 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9233
9234 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9235 auto RHSSelect =
9236 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9237
9238 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9239 }
9240 }
9241
9242 MIRBuilder.buildCopy(Dst, Res);
9243 MI.eraseFromParent();
9244 return Legalized;
9245}
9246
9248 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9249 Register DstReg = MI.getOperand(0).getReg();
9250 LLT Ty = MRI.getType(DstReg);
9251 unsigned Flags = MI.getFlags();
9252
9253 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9254 Flags);
9255 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9256 MI.eraseFromParent();
9257 return Legalized;
9258}
9259
9262 auto [DstReg, X] = MI.getFirst2Regs();
9263 const unsigned Flags = MI.getFlags();
9264 const LLT Ty = MRI.getType(DstReg);
9265 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9266
9267 // round(x) =>
9268 // t = trunc(x);
9269 // d = fabs(x - t);
9270 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9271 // return t + o;
9272
9273 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9274
9275 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9276 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9277
9278 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9279 auto Cmp =
9280 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9281
9282 // Could emit G_UITOFP instead
9283 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9284 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9285 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9286 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9287
9288 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9289
9290 MI.eraseFromParent();
9291 return Legalized;
9292}
9293
9295 auto [DstReg, SrcReg] = MI.getFirst2Regs();
9296 unsigned Flags = MI.getFlags();
9297 LLT Ty = MRI.getType(DstReg);
9298 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9299
9300 // result = trunc(src);
9301 // if (src < 0.0 && src != result)
9302 // result += -1.0.
9303
9304 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
9305 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9306
9307 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
9308 SrcReg, Zero, Flags);
9309 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
9310 SrcReg, Trunc, Flags);
9311 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
9312 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
9313
9314 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
9315 MI.eraseFromParent();
9316 return Legalized;
9317}
9318
9321 const unsigned NumOps = MI.getNumOperands();
9322 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
9323 unsigned PartSize = Src0Ty.getSizeInBits();
9324
9325 LLT WideTy = LLT::scalar(DstTy.getSizeInBits());
9326 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
9327
9328 for (unsigned I = 2; I != NumOps; ++I) {
9329 const unsigned Offset = (I - 1) * PartSize;
9330
9331 Register SrcReg = MI.getOperand(I).getReg();
9332 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
9333
9334 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
9335 MRI.createGenericVirtualRegister(WideTy);
9336
9337 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
9338 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
9339 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
9340 ResultReg = NextResult;
9341 }
9342
9343 if (DstTy.isPointer()) {
9344 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
9345 DstTy.getAddressSpace())) {
9346 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
9347 return UnableToLegalize;
9348 }
9349
9350 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9351 }
9352
9353 MI.eraseFromParent();
9354 return Legalized;
9355}
9356
9359 const unsigned NumDst = MI.getNumOperands() - 1;
9360 Register SrcReg = MI.getOperand(NumDst).getReg();
9361 Register Dst0Reg = MI.getOperand(0).getReg();
9362 LLT DstTy = MRI.getType(Dst0Reg);
9363 if (DstTy.isPointer())
9364 return UnableToLegalize; // TODO
9365
9366 SrcReg = coerceToScalar(SrcReg);
9367 if (!SrcReg)
9368 return UnableToLegalize;
9369
9370 // Expand scalarizing unmerge as bitcast to integer and shift.
9371 LLT IntTy = MRI.getType(SrcReg);
9372
9373 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
9374
9375 const unsigned DstSize = DstTy.getSizeInBits();
9376 unsigned Offset = DstSize;
9377 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
9378 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
9379 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
9380 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
9381 }
9382
9383 MI.eraseFromParent();
9384 return Legalized;
9385}
9386
9387/// Lower a vector extract or insert by writing the vector to a stack temporary
9388/// and reloading the element or vector.
9389///
9390/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
9391/// =>
9392/// %stack_temp = G_FRAME_INDEX
9393/// G_STORE %vec, %stack_temp
9394/// %idx = clamp(%idx, %vec.getNumElements())
9395/// %element_ptr = G_PTR_ADD %stack_temp, %idx
9396/// %dst = G_LOAD %element_ptr
9399 Register DstReg = MI.getOperand(0).getReg();
9400 Register SrcVec = MI.getOperand(1).getReg();
9401 Register InsertVal;
9402 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
9403 InsertVal = MI.getOperand(2).getReg();
9404
9405 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
9406
9407 LLT VecTy = MRI.getType(SrcVec);
9408 LLT EltTy = VecTy.getElementType();
9409 unsigned NumElts = VecTy.getNumElements();
9410
9411 int64_t IdxVal;
9412 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
9414 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
9415
9416 if (InsertVal) {
9417 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
9418 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
9419 } else {
9420 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
9421 }
9422
9423 MI.eraseFromParent();
9424 return Legalized;
9425 }
9426
9427 if (!EltTy.isByteSized()) { // Not implemented.
9428 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
9429 return UnableToLegalize;
9430 }
9431
9432 unsigned EltBytes = EltTy.getSizeInBytes();
9433 Align VecAlign = getStackTemporaryAlignment(VecTy);
9434 Align EltAlign;
9435
9436 MachinePointerInfo PtrInfo;
9437 auto StackTemp = createStackTemporary(
9438 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
9439 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
9440
9441 // Get the pointer to the element, and be sure not to hit undefined behavior
9442 // if the index is out of bounds.
9443 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
9444
9445 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
9446 int64_t Offset = IdxVal * EltBytes;
9447 PtrInfo = PtrInfo.getWithOffset(Offset);
9448 EltAlign = commonAlignment(VecAlign, Offset);
9449 } else {
9450 // We lose information with a variable offset.
9451 EltAlign = getStackTemporaryAlignment(EltTy);
9452 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
9453 }
9454
9455 if (InsertVal) {
9456 // Write the inserted element
9457 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
9458
9459 // Reload the whole vector.
9460 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
9461 } else {
9462 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
9463 }
9464
9465 MI.eraseFromParent();
9466 return Legalized;
9467}
9468
9471 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
9472 MI.getFirst3RegLLTs();
9473 LLT IdxTy = LLT::scalar(32);
9474
9475 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
9478 LLT EltTy = DstTy.getScalarType();
9479
9480 DenseMap<unsigned, Register> CachedExtract;
9481
9482 for (int Idx : Mask) {
9483 if (Idx < 0) {
9484 if (!Undef.isValid())
9485 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
9486 BuildVec.push_back(Undef);
9487 continue;
9488 }
9489
9490 assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");
9491
9492 int NumElts = Src0Ty.getNumElements();
9493 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
9494 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
9495 auto [It, Inserted] = CachedExtract.try_emplace(Idx);
9496 if (Inserted) {
9497 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
9498 It->second =
9499 MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);
9500 }
9501 BuildVec.push_back(It->second);
9502 }
9503
9504 assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");
9505 MIRBuilder.buildBuildVector(DstReg, BuildVec);
9506 MI.eraseFromParent();
9507 return Legalized;
9508}
9509
9512 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
9513 MI.getFirst4RegLLTs();
9514
9515 if (VecTy.isScalableVector())
9516 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
9517
9518 Align VecAlign = getStackTemporaryAlignment(VecTy);
9519 MachinePointerInfo PtrInfo;
9520 Register StackPtr =
9521 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
9522 PtrInfo)
9523 .getReg(0);
9524 MachinePointerInfo ValPtrInfo =
9526
9527 LLT IdxTy = LLT::scalar(32);
9528 LLT ValTy = VecTy.getElementType();
9529 Align ValAlign = getStackTemporaryAlignment(ValTy);
9530
9531 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
9532
9533 bool HasPassthru =
9534 MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;
9535
9536 if (HasPassthru)
9537 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
9538
9539 Register LastWriteVal;
9540 std::optional<APInt> PassthruSplatVal =
9541 isConstantOrConstantSplatVector(*MRI.getVRegDef(Passthru), MRI);
9542
9543 if (PassthruSplatVal.has_value()) {
9544 LastWriteVal =
9545 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
9546 } else if (HasPassthru) {
9547 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
9548 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
9549 {LLT::scalar(32)}, {Popcount});
9550
9551 Register LastElmtPtr =
9552 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
9553 LastWriteVal =
9554 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
9555 .getReg(0);
9556 }
9557
9558 unsigned NumElmts = VecTy.getNumElements();
9559 for (unsigned I = 0; I < NumElmts; ++I) {
9560 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
9561 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
9562 Register ElmtPtr =
9563 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9564 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
9565
9566 LLT MaskITy = MaskTy.getElementType();
9567 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
9568 if (MaskITy.getSizeInBits() > 1)
9569 MaskI = MIRBuilder.buildTrunc(LLT::scalar(1), MaskI);
9570
9571 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
9572 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
9573
9574 if (HasPassthru && I == NumElmts - 1) {
9575 auto EndOfVector =
9576 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
9577 auto AllLanesSelected = MIRBuilder.buildICmp(
9578 CmpInst::ICMP_UGT, LLT::scalar(1), OutPos, EndOfVector);
9579 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
9580 {OutPos, EndOfVector});
9581 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9582
9583 LastWriteVal =
9584 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
9585 .getReg(0);
9586 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
9587 }
9588 }
9589
9590 // TODO: Use StackPtr's FrameIndex alignment.
9591 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
9592
9593 MI.eraseFromParent();
9594 return Legalized;
9595}
9596
9598 Register AllocSize,
9599 Align Alignment,
9600 LLT PtrTy) {
9602
9603 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
9604 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
9605
9606 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
9607 // have to generate an extra instruction to negate the alloc and then use
9608 // G_PTR_ADD to add the negative offset.
9609 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
9610 if (Alignment > Align(1)) {
9611 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
9612 AlignMask.negate();
9613 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
9614 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
9615 }
9616
9617 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
9618}
9619
9622 const auto &MF = *MI.getMF();
9623 const auto &TFI = *MF.getSubtarget().getFrameLowering();
9624 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
9625 return UnableToLegalize;
9626
9627 Register Dst = MI.getOperand(0).getReg();
9628 Register AllocSize = MI.getOperand(1).getReg();
9629 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
9630
9631 LLT PtrTy = MRI.getType(Dst);
9632 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
9633 Register SPTmp =
9634 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
9635
9636 MIRBuilder.buildCopy(SPReg, SPTmp);
9637 MIRBuilder.buildCopy(Dst, SPTmp);
9638
9639 MI.eraseFromParent();
9640 return Legalized;
9641}
9642
9645 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9646 if (!StackPtr)
9647 return UnableToLegalize;
9648
9649 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
9650 MI.eraseFromParent();
9651 return Legalized;
9652}
9653
9656 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9657 if (!StackPtr)
9658 return UnableToLegalize;
9659
9660 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
9661 MI.eraseFromParent();
9662 return Legalized;
9663}
9664
9667 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9668 unsigned Offset = MI.getOperand(2).getImm();
9669
9670 // Extract sub-vector or one element
9671 if (SrcTy.isVector()) {
9672 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
9673 unsigned DstSize = DstTy.getSizeInBits();
9674
9675 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
9676 (Offset + DstSize <= SrcTy.getSizeInBits())) {
9677 // Unmerge and allow access to each Src element for the artifact combiner.
9678 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
9679
9680 // Take element(s) we need to extract and copy it (merge them).
9681 SmallVector<Register, 8> SubVectorElts;
9682 for (unsigned Idx = Offset / SrcEltSize;
9683 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
9684 SubVectorElts.push_back(Unmerge.getReg(Idx));
9685 }
9686 if (SubVectorElts.size() == 1)
9687 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
9688 else
9689 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
9690
9691 MI.eraseFromParent();
9692 return Legalized;
9693 }
9694 }
9695
9696 const DataLayout &DL = MIRBuilder.getDataLayout();
9697 if ((SrcTy.isPointer() &&
9698 DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) ||
9699 (DstTy.isPointer() &&
9700 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace()))) {
9701 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9702 return UnableToLegalize;
9703 }
9704
9705 if ((DstTy.isScalar() || DstTy.isPointer()) &&
9706 (SrcTy.isScalar() || SrcTy.isPointer() ||
9707 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
9708 LLT SrcIntTy = SrcTy;
9709 if (!SrcTy.isScalar()) {
9710 SrcIntTy = LLT::scalar(SrcTy.getSizeInBits());
9711 SrcReg = MIRBuilder.buildCast(SrcIntTy, SrcReg).getReg(0);
9712 }
9713
9714 Register ResultReg = DstReg;
9715 if (DstTy.isPointer())
9716 ResultReg =
9717 MRI.createGenericVirtualRegister(LLT::scalar(DstTy.getSizeInBits()));
9718
9719 if (Offset == 0)
9720 MIRBuilder.buildTrunc(ResultReg, SrcReg);
9721 else {
9722 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
9723 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
9724 MIRBuilder.buildTrunc(ResultReg, Shr);
9725 }
9726
9727 if (DstTy.isPointer())
9728 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9729
9730 MI.eraseFromParent();
9731 return Legalized;
9732 }
9733
9734 return UnableToLegalize;
9735}
9736
9738 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
9739 uint64_t Offset = MI.getOperand(3).getImm();
9740
9741 LLT DstTy = MRI.getType(Src);
9742 LLT InsertTy = MRI.getType(InsertSrc);
9743
9744 const DataLayout &DL = MIRBuilder.getDataLayout();
9745 bool IsNonIntegralInsert =
9746 InsertTy.isPointerOrPointerVector() &&
9747 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace());
9748 bool IsNonIntegralDst = DstTy.isPointerOrPointerVector() &&
9749 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace());
9750
9751 // Insert sub-vector or one element
9752 if (DstTy.isVector()) {
9753 LLT EltTy = DstTy.getElementType();
9754
9755 if ((IsNonIntegralInsert || IsNonIntegralDst) && InsertTy != EltTy) {
9756 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9757 return UnableToLegalize;
9758 }
9759
9760 unsigned EltSize = EltTy.getSizeInBits();
9761 unsigned InsertSize = InsertTy.getSizeInBits();
9762
9763 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
9764 (Offset + InsertSize <= DstTy.getSizeInBits())) {
9765 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
9767 unsigned Idx = 0;
9768 // Elements from Src before insert start Offset
9769 for (; Idx < Offset / EltSize; ++Idx) {
9770 DstElts.push_back(UnmergeSrc.getReg(Idx));
9771 }
9772
9773 // Replace elements in Src with elements from InsertSrc
9774 if (InsertTy.getSizeInBits() > EltSize) {
9775 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
9776 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
9777 ++Idx, ++i) {
9778 DstElts.push_back(UnmergeInsertSrc.getReg(i));
9779 }
9780 } else {
9781 if (InsertTy.isPointer() && !EltTy.isPointer())
9782 InsertSrc = MIRBuilder.buildPtrToInt(EltTy, InsertSrc).getReg(0);
9783 else if (!InsertTy.isPointer() && EltTy.isPointer())
9784 InsertSrc = MIRBuilder.buildIntToPtr(EltTy, InsertSrc).getReg(0);
9785 DstElts.push_back(InsertSrc);
9786 ++Idx;
9787 }
9788
9789 // Remaining elements from Src after insert
9790 for (; Idx < DstTy.getNumElements(); ++Idx) {
9791 DstElts.push_back(UnmergeSrc.getReg(Idx));
9792 }
9793
9794 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
9795 MI.eraseFromParent();
9796 return Legalized;
9797 }
9798 }
9799
9800 if (InsertTy.isVector() ||
9801 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
9802 return UnableToLegalize;
9803
9804 if (IsNonIntegralDst || IsNonIntegralInsert) {
9805 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9806 return UnableToLegalize;
9807 }
9808
9809 LLT IntDstTy = DstTy;
9810
9811 if (!DstTy.isScalar()) {
9812 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
9813 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
9814 }
9815
9816 if (!InsertTy.isScalar()) {
9817 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
9818 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
9819 }
9820
9821 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
9822 if (Offset != 0) {
9823 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
9824 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
9825 }
9826
9828 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
9829
9830 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
9831 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
9832 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
9833
9834 MIRBuilder.buildCast(Dst, Or);
9835 MI.eraseFromParent();
9836 return Legalized;
9837}
9838
9841 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
9842 MI.getFirst4RegLLTs();
9843 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
9844
9845 LLT Ty = Dst0Ty;
9846 LLT BoolTy = Dst1Ty;
9847
9848 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
9849
9850 if (IsAdd)
9851 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
9852 else
9853 MIRBuilder.buildSub(NewDst0, LHS, RHS);
9854
9855 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
9856
9857 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9858
9859 if (IsAdd) {
9860 // For an addition, the result should be less than one of the operands (LHS)
9861 // if and only if the other operand (RHS) is negative, otherwise there will
9862 // be overflow.
9863 auto ResultLowerThanLHS =
9864 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
9865 auto RHSNegative =
9866 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
9867 MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
9868 } else {
9869 // For subtraction, overflow occurs when the signed comparison of operands
9870 // doesn't match the sign of the result.
9871 auto LHSLessThanRHS =
9872 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
9873 auto ResultNegative =
9874 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
9875 MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
9876 }
9877
9878 MIRBuilder.buildCopy(Dst0, NewDst0);
9879 MI.eraseFromParent();
9880
9881 return Legalized;
9882}
9883
9885 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
9886 const LLT Ty = MRI.getType(Res);
9887
9888 // sum = LHS + RHS + zext(CarryIn)
9889 auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);
9890 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
9891 auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);
9892 MIRBuilder.buildCopy(Res, Sum);
9893
9894 // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 0
9895 auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);
9896 auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);
9897 auto T = MIRBuilder.buildAnd(Ty, AX, BX);
9898
9899 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9900 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
9901
9902 MI.eraseFromParent();
9903 return Legalized;
9904}
9905
9907 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
9908 const LLT Ty = MRI.getType(Res);
9909
9910 // Diff = LHS - (RHS + zext(CarryIn))
9911 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
9912 auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
9913 auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);
9914 MIRBuilder.buildCopy(Res, Diff);
9915
9916 // ov = msb((LHS ^ RHS) & (LHS ^ Diff))
9917 auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);
9918 auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);
9919 auto T = MIRBuilder.buildAnd(Ty, X1, X2);
9920 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9921 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
9922
9923 MI.eraseFromParent();
9924 return Legalized;
9925}
9926
9929 auto [Res, LHS, RHS] = MI.getFirst3Regs();
9930 LLT Ty = MRI.getType(Res);
9931 bool IsSigned;
9932 bool IsAdd;
9933 unsigned BaseOp;
9934 switch (MI.getOpcode()) {
9935 default:
9936 llvm_unreachable("unexpected addsat/subsat opcode");
9937 case TargetOpcode::G_UADDSAT:
9938 IsSigned = false;
9939 IsAdd = true;
9940 BaseOp = TargetOpcode::G_ADD;
9941 break;
9942 case TargetOpcode::G_SADDSAT:
9943 IsSigned = true;
9944 IsAdd = true;
9945 BaseOp = TargetOpcode::G_ADD;
9946 break;
9947 case TargetOpcode::G_USUBSAT:
9948 IsSigned = false;
9949 IsAdd = false;
9950 BaseOp = TargetOpcode::G_SUB;
9951 break;
9952 case TargetOpcode::G_SSUBSAT:
9953 IsSigned = true;
9954 IsAdd = false;
9955 BaseOp = TargetOpcode::G_SUB;
9956 break;
9957 }
9958
9959 if (IsSigned) {
9960 // sadd.sat(a, b) ->
9961 // hi = 0x7fffffff - smax(a, 0)
9962 // lo = 0x80000000 - smin(a, 0)
9963 // a + smin(smax(lo, b), hi)
9964 // ssub.sat(a, b) ->
9965 // lo = smax(a, -1) - 0x7fffffff
9966 // hi = smin(a, -1) - 0x80000000
9967 // a - smin(smax(lo, b), hi)
9968 // TODO: AMDGPU can use a "median of 3" instruction here:
9969 // a +/- med3(lo, b, hi)
9970 uint64_t NumBits = Ty.getScalarSizeInBits();
9971 auto MaxVal =
9972 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
9973 auto MinVal =
9974 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
9976 if (IsAdd) {
9977 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9978 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
9979 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
9980 } else {
9981 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
9982 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
9983 MaxVal);
9984 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
9985 MinVal);
9986 }
9987 auto RHSClamped =
9988 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
9989 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
9990 } else {
9991 // uadd.sat(a, b) -> a + umin(~a, b)
9992 // usub.sat(a, b) -> a - umin(a, b)
9993 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
9994 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
9995 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
9996 }
9997
9998 MI.eraseFromParent();
9999 return Legalized;
10000}
10001
10004 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10005 LLT Ty = MRI.getType(Res);
10006 LLT BoolTy = Ty.changeElementSize(1);
10007 bool IsSigned;
10008 bool IsAdd;
10009 unsigned OverflowOp;
10010 switch (MI.getOpcode()) {
10011 default:
10012 llvm_unreachable("unexpected addsat/subsat opcode");
10013 case TargetOpcode::G_UADDSAT:
10014 IsSigned = false;
10015 IsAdd = true;
10016 OverflowOp = TargetOpcode::G_UADDO;
10017 break;
10018 case TargetOpcode::G_SADDSAT:
10019 IsSigned = true;
10020 IsAdd = true;
10021 OverflowOp = TargetOpcode::G_SADDO;
10022 break;
10023 case TargetOpcode::G_USUBSAT:
10024 IsSigned = false;
10025 IsAdd = false;
10026 OverflowOp = TargetOpcode::G_USUBO;
10027 break;
10028 case TargetOpcode::G_SSUBSAT:
10029 IsSigned = true;
10030 IsAdd = false;
10031 OverflowOp = TargetOpcode::G_SSUBO;
10032 break;
10033 }
10034
10035 auto OverflowRes =
10036 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
10037 Register Tmp = OverflowRes.getReg(0);
10038 Register Ov = OverflowRes.getReg(1);
10039 MachineInstrBuilder Clamp;
10040 if (IsSigned) {
10041 // sadd.sat(a, b) ->
10042 // {tmp, ov} = saddo(a, b)
10043 // ov ? (tmp >>s 31) + 0x80000000 : r
10044 // ssub.sat(a, b) ->
10045 // {tmp, ov} = ssubo(a, b)
10046 // ov ? (tmp >>s 31) + 0x80000000 : r
10047 uint64_t NumBits = Ty.getScalarSizeInBits();
10048 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
10049 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
10050 auto MinVal =
10051 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10052 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
10053 } else {
10054 // uadd.sat(a, b) ->
10055 // {tmp, ov} = uaddo(a, b)
10056 // ov ? 0xffffffff : tmp
10057 // usub.sat(a, b) ->
10058 // {tmp, ov} = usubo(a, b)
10059 // ov ? 0 : tmp
10060 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
10061 }
10062 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
10063
10064 MI.eraseFromParent();
10065 return Legalized;
10066}
10067
10070 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
10071 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
10072 "Expected shlsat opcode!");
10073 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
10074 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10075 LLT Ty = MRI.getType(Res);
10076 LLT BoolTy = Ty.changeElementSize(1);
10077
10078 unsigned BW = Ty.getScalarSizeInBits();
10079 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
10080 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
10081 : MIRBuilder.buildLShr(Ty, Result, RHS);
10082
10083 MachineInstrBuilder SatVal;
10084 if (IsSigned) {
10085 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
10086 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
10087 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
10088 MIRBuilder.buildConstant(Ty, 0));
10089 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
10090 } else {
10091 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
10092 }
10093 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
10094 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
10095
10096 MI.eraseFromParent();
10097 return Legalized;
10098}
10099
10101 auto [Dst, Src] = MI.getFirst2Regs();
10102 const LLT Ty = MRI.getType(Src);
10103 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
10104 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
10105
10106 // Swap most and least significant byte, set remaining bytes in Res to zero.
10107 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
10108 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
10109 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10110 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
10111
10112 // Set i-th high/low byte in Res to i-th low/high byte from Src.
10113 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
10114 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
10115 APInt APMask = APInt::getBitsSet(SizeInBytes * 8, i * 8, i * 8 + 8);
10116 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
10117 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
10118 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
10119 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
10120 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
10121 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
10122 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
10123 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10124 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
10125 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
10126 }
10127 Res.getInstr()->getOperand(0).setReg(Dst);
10128
10129 MI.eraseFromParent();
10130 return Legalized;
10131}
10132
10133//{ (Src & Mask) >> N } | { (Src << N) & Mask }
10135 MachineInstrBuilder Src, const APInt &Mask) {
10136 const LLT Ty = Dst.getLLTTy(*B.getMRI());
10137 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
10138 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
10139 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
10140 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
10141 return B.buildOr(Dst, LHS, RHS);
10142}
10143
10146 auto [Dst, Src] = MI.getFirst2Regs();
10147 const LLT SrcTy = MRI.getType(Src);
10148 unsigned Size = SrcTy.getScalarSizeInBits();
10149 unsigned VSize = SrcTy.getSizeInBits();
10150
10151 if (Size >= 8) {
10152 if (SrcTy.isVector() && (VSize % 8 == 0) &&
10153 (LI.isLegal({TargetOpcode::G_BITREVERSE,
10154 {LLT::fixed_vector(VSize / 8, LLT::integer(8)),
10155 LLT::fixed_vector(VSize / 8, LLT::integer(8))}}))) {
10156 // If bitreverse is legal for i8 vector of the same size, then cast
10157 // to i8 vector type.
10158 // e.g. v4s32 -> v16s8
10159 LLT VTy = LLT::fixed_vector(VSize / 8, LLT::integer(8));
10160 auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);
10161 auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);
10162 auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);
10163 MIRBuilder.buildBitcast(Dst, RBIT);
10164 } else {
10165 MachineInstrBuilder BSWAP =
10166 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});
10167
10168 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
10169 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
10170 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
10171 MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,
10172 APInt::getSplat(Size, APInt(8, 0xF0)));
10173
10174 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
10175 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
10176 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
10177 MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,
10178 APInt::getSplat(Size, APInt(8, 0xCC)));
10179
10180 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
10181 // 6|7
10182 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
10183 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
10184 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
10185 }
10186 } else {
10187 // Expand bitreverse for types smaller than 8 bits.
10189 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
10191 if (I < J) {
10192 auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);
10193 Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);
10194 } else {
10195 auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);
10196 Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);
10197 }
10198
10199 auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);
10200 Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);
10201 if (I == 0)
10202 Tmp = Tmp2;
10203 else
10204 Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);
10205 }
10206 MIRBuilder.buildCopy(Dst, Tmp);
10207 }
10208
10209 MI.eraseFromParent();
10210 return Legalized;
10211}
10212
10215 MachineFunction &MF = MIRBuilder.getMF();
10216
10217 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
10218 int NameOpIdx = IsRead ? 1 : 0;
10219 int ValRegIndex = IsRead ? 0 : 1;
10220
10221 Register ValReg = MI.getOperand(ValRegIndex).getReg();
10222 const LLT Ty = MRI.getType(ValReg);
10223 const MDString *RegStr = cast<MDString>(
10224 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
10225
10226 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
10227 if (!PhysReg) {
10228 const Function &Fn = MF.getFunction();
10230 "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +
10231 (IsRead ? "llvm.read_register" : "llvm.write_register"),
10232 Fn, MI.getDebugLoc()));
10233 if (IsRead)
10234 MIRBuilder.buildUndef(ValReg);
10235
10236 MI.eraseFromParent();
10237 return Legalized;
10238 }
10239
10240 if (IsRead)
10241 MIRBuilder.buildCopy(ValReg, PhysReg);
10242 else
10243 MIRBuilder.buildCopy(PhysReg, ValReg);
10244
10245 MI.eraseFromParent();
10246 return Legalized;
10247}
10248
10251 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
10252 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
10253 Register Result = MI.getOperand(0).getReg();
10254 LLT OrigTy = MRI.getType(Result);
10255 auto SizeInBits = OrigTy.getScalarSizeInBits();
10256 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
10257
10258 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
10259 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
10260 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
10261 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
10262
10263 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
10264 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
10265 MIRBuilder.buildTrunc(Result, Shifted);
10266
10267 MI.eraseFromParent();
10268 return Legalized;
10269}
10270
10273 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10274 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
10275
10276 if (Mask == fcNone) {
10277 MIRBuilder.buildConstant(DstReg, 0);
10278 MI.eraseFromParent();
10279 return Legalized;
10280 }
10281 if (Mask == fcAllFlags) {
10282 MIRBuilder.buildConstant(DstReg, 1);
10283 MI.eraseFromParent();
10284 return Legalized;
10285 }
10286
10287 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
10288 // version
10289
10290 unsigned BitSize = SrcTy.getScalarSizeInBits();
10291 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
10292
10293 LLT IntTy = SrcTy.changeElementType(LLT::integer(BitSize));
10294 auto AsInt = SrcTy == IntTy ? MIRBuilder.buildCopy(IntTy, SrcReg)
10295 : MIRBuilder.buildBitcast(IntTy, SrcReg);
10296
10297 // Various masks.
10298 APInt SignBit = APInt::getSignMask(BitSize);
10299 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
10300 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
10301 APInt ExpMask = Inf;
10302 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
10303 APInt QNaNBitMask =
10304 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
10305 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
10306
10307 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
10308 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
10309 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
10310 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
10311 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
10312
10313 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
10314 auto Sign =
10315 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
10316
10317 auto Res = MIRBuilder.buildConstant(DstTy, 0);
10318 // Clang doesn't support capture of structured bindings:
10319 LLT DstTyCopy = DstTy;
10320 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
10321 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
10322 };
10323
10324 // Tests that involve more than one class should be processed first.
10325 if ((Mask & fcFinite) == fcFinite) {
10326 // finite(V) ==> abs(V) u< exp_mask
10327 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10328 ExpMaskC));
10329 Mask &= ~fcFinite;
10330 } else if ((Mask & fcFinite) == fcPosFinite) {
10331 // finite(V) && V > 0 ==> V u< exp_mask
10332 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
10333 ExpMaskC));
10334 Mask &= ~fcPosFinite;
10335 } else if ((Mask & fcFinite) == fcNegFinite) {
10336 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
10337 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10338 ExpMaskC);
10339 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
10340 appendToRes(And);
10341 Mask &= ~fcNegFinite;
10342 }
10343
10344 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
10345 // fcZero | fcSubnormal => test all exponent bits are 0
10346 // TODO: Handle sign bit specific cases
10347 // TODO: Handle inverted case
10348 if (PartialCheck == (fcZero | fcSubnormal)) {
10349 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
10350 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10351 ExpBits, ZeroC));
10352 Mask &= ~PartialCheck;
10353 }
10354 }
10355
10356 // Check for individual classes.
10357 if (FPClassTest PartialCheck = Mask & fcZero) {
10358 if (PartialCheck == fcPosZero)
10359 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10360 AsInt, ZeroC));
10361 else if (PartialCheck == fcZero)
10362 appendToRes(
10363 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
10364 else // fcNegZero
10365 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10366 AsInt, SignBitC));
10367 }
10368
10369 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
10370 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
10371 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
10372 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
10373 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
10374 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
10375 auto SubnormalRes =
10376 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
10377 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
10378 if (PartialCheck == fcNegSubnormal)
10379 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
10380 appendToRes(SubnormalRes);
10381 }
10382
10383 if (FPClassTest PartialCheck = Mask & fcInf) {
10384 if (PartialCheck == fcPosInf)
10385 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10386 AsInt, InfC));
10387 else if (PartialCheck == fcInf)
10388 appendToRes(
10389 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
10390 else { // fcNegInf
10391 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
10392 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
10393 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10394 AsInt, NegInfC));
10395 }
10396 }
10397
10398 if (FPClassTest PartialCheck = Mask & fcNan) {
10399 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
10400 if (PartialCheck == fcNan) {
10401 // isnan(V) ==> abs(V) u> int(inf)
10402 appendToRes(
10403 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
10404 } else if (PartialCheck == fcQNan) {
10405 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
10406 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
10407 InfWithQnanBitC));
10408 } else { // fcSNan
10409 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
10410 // abs(V) u< (unsigned(Inf) | quiet_bit)
10411 auto IsNan =
10412 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
10413 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
10414 Abs, InfWithQnanBitC);
10415 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
10416 }
10417 }
10418
10419 if (FPClassTest PartialCheck = Mask & fcNormal) {
10420 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
10421 // (max_exp-1))
10422 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
10423 auto ExpMinusOne = MIRBuilder.buildSub(
10424 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
10425 APInt MaxExpMinusOne = ExpMask - ExpLSB;
10426 auto NormalRes =
10427 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
10428 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
10429 if (PartialCheck == fcNegNormal)
10430 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
10431 else if (PartialCheck == fcPosNormal) {
10432 auto PosSign = MIRBuilder.buildXor(
10433 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));
10434 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
10435 }
10436 appendToRes(NormalRes);
10437 }
10438
10439 MIRBuilder.buildCopy(DstReg, Res);
10440 MI.eraseFromParent();
10441 return Legalized;
10442}
10443
10445 // Implement G_SELECT in terms of XOR, AND, OR.
10446 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
10447 MI.getFirst4RegLLTs();
10448
10449 LLT Op1TyInt =
10450 Op1Ty.changeElementType(LLT::integer(Op1Ty.getScalarSizeInBits()));
10451
10452 bool IsEltPtr = DstTy.isPointerOrPointerVector();
10453 if (IsEltPtr) {
10454 LLT ScalarPtrTy = LLT::integer(DstTy.getScalarSizeInBits());
10455 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
10456 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
10457 Op1Ty = MRI.getType(Op1Reg);
10458 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
10459 Op2Ty = MRI.getType(Op2Reg);
10460 DstTy = NewTy;
10461 }
10462
10463 if (MaskTy.isScalar()) {
10464 // Turn the scalar condition into a vector condition mask if needed.
10465
10466 Register MaskElt = MaskReg;
10467
10468 // The condition was potentially zero extended before, but we want a sign
10469 // extended boolean.
10470 if (MaskTy != LLT::scalar(1))
10471 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
10472
10473 // Continue the sign extension (or truncate) to match the data type.
10474 MaskTy = DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10475 MaskElt =
10476 MIRBuilder.buildSExtOrTrunc(MaskTy.getScalarType(), MaskElt).getReg(0);
10477
10478 if (DstTy.isVector()) {
10479 // Generate a vector splat idiom.
10480 auto ShufSplat = MIRBuilder.buildShuffleSplat(MaskTy, MaskElt);
10481 MaskReg = ShufSplat.getReg(0);
10482 } else {
10483 MaskReg = MaskElt;
10484 }
10485 } else if (!DstTy.isVector()) {
10486 // Cannot handle the case that mask is a vector and dst is a scalar.
10487 return UnableToLegalize;
10488 }
10489
10490 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
10491 return UnableToLegalize;
10492 }
10493
10494 if (!Op1Ty.getScalarType().isAnyScalar() &&
10495 !Op1Ty.getScalarType().isInteger())
10496 Op1Reg = MIRBuilder.buildBitcast(Op1TyInt, Op1Reg).getReg(0);
10497
10498 if (!Op2Ty.getScalarType().isAnyScalar() &&
10499 !Op2Ty.getScalarType().isInteger()) {
10500 auto Op2TyInt =
10501 Op2Ty.changeElementType(LLT::integer(Op2Ty.getScalarSizeInBits()));
10502 Op2Reg = MIRBuilder.buildBitcast(Op2TyInt, Op2Reg).getReg(0);
10503 }
10504
10505 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
10506 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
10507 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
10508 if (IsEltPtr) {
10509 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
10510 MIRBuilder.buildIntToPtr(DstReg, Or);
10511 } else {
10512 if (DstTy == Op1TyInt)
10513 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
10514 else {
10515 auto Or = MIRBuilder.buildOr(Op1TyInt, NewOp1, NewOp2);
10516 MIRBuilder.buildBitcast(DstReg, Or.getReg(0));
10517 }
10518 }
10519 MI.eraseFromParent();
10520 return Legalized;
10521}
10522
10524 // Split DIVREM into individual instructions.
10525 unsigned Opcode = MI.getOpcode();
10526
10527 MIRBuilder.buildInstr(
10528 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
10529 : TargetOpcode::G_UDIV,
10530 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10531 MIRBuilder.buildInstr(
10532 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
10533 : TargetOpcode::G_UREM,
10534 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10535 MI.eraseFromParent();
10536 return Legalized;
10537}
10538
10541 // Expand %res = G_ABS %a into:
10542 // %v1 = G_ASHR %a, scalar_size-1
10543 // %v2 = G_ADD %a, %v1
10544 // %res = G_XOR %v2, %v1
10545 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
10546 Register OpReg = MI.getOperand(1).getReg();
10547 auto ShiftAmt =
10548 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
10549 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
10550 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
10551 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
10552 MI.eraseFromParent();
10553 return Legalized;
10554}
10555
10558 // Expand %res = G_ABS %a into:
10559 // %v1 = G_CONSTANT 0
10560 // %v2 = G_SUB %v1, %a
10561 // %res = G_SMAX %a, %v2
10562 Register SrcReg = MI.getOperand(1).getReg();
10563 LLT Ty = MRI.getType(SrcReg);
10564 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10565 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
10566 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
10567 MI.eraseFromParent();
10568 return Legalized;
10569}
10570
10573 Register SrcReg = MI.getOperand(1).getReg();
10574 Register DestReg = MI.getOperand(0).getReg();
10575 LLT Ty = MRI.getType(SrcReg), IType = LLT::scalar(1);
10576 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
10577 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
10578 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
10579 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
10580 MI.eraseFromParent();
10581 return Legalized;
10582}
10583
10586 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10587 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10588 "Expected G_ABDS or G_ABDU instruction");
10589
10590 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10591 LLT Ty = MRI.getType(LHS);
10592
10593 // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10594 // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10595 Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);
10596 Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);
10597 CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)
10600 auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);
10601 MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);
10602
10603 MI.eraseFromParent();
10604 return Legalized;
10605}
10606
10609 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10610 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10611 "Expected G_ABDS or G_ABDU instruction");
10612
10613 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10614 LLT Ty = MRI.getType(LHS);
10615
10616 // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))
10617 // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))
10618 Register MaxReg, MinReg;
10619 if (MI.getOpcode() == TargetOpcode::G_ABDS) {
10620 MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);
10621 MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);
10622 } else {
10623 MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);
10624 MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);
10625 }
10626 MIRBuilder.buildSub(DstReg, MaxReg, MinReg);
10627
10628 MI.eraseFromParent();
10629 return Legalized;
10630}
10631
10633 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10634 LLT TyInt =
10635 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10636 Register CastedSrc = SrcReg;
10637
10638 if (!(SrcTy.getScalarType().isAnyScalar() ||
10639 SrcTy.getScalarType().isInteger())) {
10640 auto SrcTyInt =
10641 SrcTy.changeElementType(LLT::integer(SrcTy.getScalarSizeInBits()));
10642 CastedSrc = MIRBuilder.buildBitcast(SrcTyInt, SrcReg).getReg(0);
10643 }
10644
10645 if (MRI.getType(DstReg) != TyInt) {
10646 // Reset sign bit
10647 Register NewDst =
10649 .buildAnd(TyInt, CastedSrc,
10650 MIRBuilder.buildConstant(
10652 DstTy.getScalarSizeInBits())))
10653 .getReg(0);
10654
10655 MIRBuilder.buildBitcast(DstReg, NewDst);
10656 } else
10658 .buildAnd(
10659 DstReg, CastedSrc,
10660 MIRBuilder.buildConstant(
10661 TyInt, APInt::getSignedMaxValue(DstTy.getScalarSizeInBits())))
10662 .getReg(0);
10663
10664 MI.eraseFromParent();
10665 return Legalized;
10666}
10667
10670 Register SrcReg = MI.getOperand(1).getReg();
10671 LLT SrcTy = MRI.getType(SrcReg);
10672 LLT DstTy = MRI.getType(SrcReg);
10673
10674 // The source could be a scalar if the IR type was <1 x sN>.
10675 if (SrcTy.isScalar()) {
10676 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
10677 return UnableToLegalize; // FIXME: handle extension.
10678 // This can be just a plain copy.
10679 Observer.changingInstr(MI);
10680 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
10681 Observer.changedInstr(MI);
10682 return Legalized;
10683 }
10684 return UnableToLegalize;
10685}
10686
10688 MachineFunction &MF = *MI.getMF();
10689 const DataLayout &DL = MIRBuilder.getDataLayout();
10690 LLVMContext &Ctx = MF.getFunction().getContext();
10691 Register ListPtr = MI.getOperand(1).getReg();
10692 LLT PtrTy = MRI.getType(ListPtr);
10693
10694 // LstPtr is a pointer to the head of the list. Get the address
10695 // of the head of the list.
10696 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
10697 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
10698 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
10699 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
10700
10701 const Align A(MI.getOperand(2).getImm());
10702 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
10703 if (A > TLI.getMinStackArgumentAlignment()) {
10704 Register AlignAmt =
10705 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
10706 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
10707 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
10708 VAList = AndDst.getReg(0);
10709 }
10710
10711 // Increment the pointer, VAList, to the next vaarg
10712 // The list should be bumped by the size of element in the current head of
10713 // list.
10714 Register Dst = MI.getOperand(0).getReg();
10715 LLT LLTTy = MRI.getType(Dst);
10716 Type *Ty = getTypeForLLT(LLTTy, Ctx);
10717 auto IncAmt =
10718 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
10719 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
10720
10721 // Store the increment VAList to the legalized pointer
10723 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
10724 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
10725 // Load the actual argument out of the pointer VAList
10726 Align EltAlignment = DL.getABITypeAlign(Ty);
10727 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
10728 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
10729 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
10730
10731 MI.eraseFromParent();
10732 return Legalized;
10733}
10734
10736 [[maybe_unused]] unsigned OpCode = MI.getOpcode();
10737 assert((OpCode == TargetOpcode::G_SMULFIX ||
10738 OpCode == TargetOpcode::G_UMULFIX) &&
10739 "Operator must be either G_SMULFIX or G_UMULFIX!");
10740 auto [Dst, LHS, RHS] = MI.getFirst3Regs();
10741 LLT Ty = MRI.getType(Dst);
10742 unsigned Scale = MI.getOperand(3).getImm();
10743
10744 if (Scale == 0) {
10745 MIRBuilder.buildMul(Dst, LHS, RHS);
10746 MI.eraseFromParent();
10747 return Legalized;
10748 }
10749
10750 // TODO: Port other lowerng paths from SelectionDAG.
10751 LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
10752 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
10753 MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
10754 if (MI.getOpcode() == TargetOpcode::G_SMULFIX) {
10755 ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
10756 ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
10757 } else {
10758 ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
10759 ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
10760 }
10761
10762 auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
10763 if (MI.getOpcode() == TargetOpcode::G_SMULFIX)
10764 Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
10765 else
10766 Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
10767
10768 MIRBuilder.buildTrunc(Dst, Shift);
10769
10770 MI.eraseFromParent();
10771 return Legalized;
10772}
10773
10774// Get a vectorized representation of the memset value operand, GISel edition.
10776 MachineRegisterInfo &MRI = *MIB.getMRI();
10777 unsigned NumBits = Ty.getScalarSizeInBits();
10778 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
10779 if (!Ty.isVector() && ValVRegAndVal) {
10780 APInt Scalar = ValVRegAndVal->Value.trunc(8);
10781 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
10782 return MIB.buildConstant(Ty, SplatVal).getReg(0);
10783 }
10784
10785 // Extend the byte value to the larger type, and then multiply by a magic
10786 // value 0x010101... in order to replicate it across every byte.
10787 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
10788 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
10789 return MIB.buildConstant(Ty, 0).getReg(0);
10790 }
10791
10792 LLT ExtType = Ty.getScalarType();
10793 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
10794 if (NumBits > 8) {
10795 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
10796 auto MagicMI = MIB.buildConstant(ExtType, Magic);
10797 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
10798 }
10799
10800 // For vector types create a G_BUILD_VECTOR.
10801 if (Ty.isVector())
10802 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
10803
10804 return Val;
10805}
10806
10808LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
10809 uint64_t KnownLen, Align Alignment,
10810 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
10811 auto &MF = *MI.getParent()->getParent();
10812 const auto &TLI = *MF.getSubtarget().getTargetLowering();
10813 auto &DL = MF.getDataLayout();
10814 LLVMContext &C = MF.getFunction().getContext();
10815
10816 assert(KnownLen != 0 && "Have a zero length memset length!");
10817 assert(!MemOps.empty() && "Expected at least one memory op");
10818
10819 MachineFrameInfo &MFI = MF.getFrameInfo();
10820 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
10821 const auto &DstMMO = **MI.memoperands_begin();
10822
10823 if (DstAlignCanChange) {
10824 // Get an estimate of the type from the LLT.
10825 Type *IRTy = getTypeForLLT(MemOps[0], C);
10826 Align NewAlign = DL.getABITypeAlign(IRTy);
10827 if (NewAlign > Alignment) {
10828 Alignment = NewAlign;
10829 unsigned FI = FIDef->getOperand(1).getIndex();
10830 // Give the stack frame object a larger alignment if needed.
10831 if (MFI.getObjectAlign(FI) < Alignment)
10832 MFI.setObjectAlignment(FI, Alignment);
10833 }
10834 }
10835
10836 MachineIRBuilder MIB(MI);
10837 // Find the largest store and generate the bit pattern for it.
10838 LLT LargestTy = MemOps[0];
10839 for (unsigned i = 1; i < MemOps.size(); i++)
10840 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
10841 LargestTy = MemOps[i];
10842
10843 // The memset stored value is always defined as an s8, so in order to make it
10844 // work with larger store types we need to repeat the bit pattern across the
10845 // wider type.
10846 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
10847
10848 if (!MemSetValue)
10849 return UnableToLegalize;
10850
10851 // Generate the stores. For each store type in the list, we generate the
10852 // matching store of that type to the destination address.
10853 LLT PtrTy = MRI.getType(Dst);
10854 unsigned DstOff = 0;
10855 unsigned Size = KnownLen;
10856 for (unsigned I = 0; I < MemOps.size(); I++) {
10857 LLT Ty = MemOps[I];
10858 unsigned TySize = Ty.getSizeInBytes();
10859 if (TySize > Size) {
10860 // Issuing an unaligned load / store pair that overlaps with the previous
10861 // pair. Adjust the offset accordingly.
10862 assert(I == MemOps.size() - 1 && I != 0);
10863 DstOff -= TySize - Size;
10864 }
10865
10866 // If this store is smaller than the largest store see whether we can get
10867 // the smaller value for free with a truncate.
10868 Register Value = MemSetValue;
10869 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
10870 MVT VT = getMVTForLLT(Ty);
10871 MVT LargestVT = getMVTForLLT(LargestTy);
10872 if (!LargestTy.isVector() && !Ty.isVector() &&
10873 TLI.isTruncateFree(LargestVT, VT))
10874 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
10875 else
10876 Value = getMemsetValue(Val, Ty, MIB);
10877 if (!Value)
10878 return UnableToLegalize;
10879 }
10880
10881 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
10882
10883 Register Ptr = Dst;
10884 if (DstOff != 0) {
10885 auto Offset =
10886 MIB.buildConstant(LLT::scalar(PtrTy.getSizeInBits()), DstOff);
10887 Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);
10888 }
10889
10890 MIB.buildStore(Value, Ptr, *StoreMMO);
10891 DstOff += Ty.getSizeInBytes();
10892 Size -= TySize;
10893 }
10894
10895 MI.eraseFromParent();
10896 return Legalized;
10897}
10898
10900LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
10901 uint64_t KnownLen, Align Alignment,
10902 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
10903 auto &MF = *MI.getParent()->getParent();
10904 auto &DL = MF.getDataLayout();
10905 LLVMContext &C = MF.getFunction().getContext();
10906
10907 assert(KnownLen != 0 && "Have a zero length memcpy length!");
10908 assert(!MemOps.empty() && "Expected at least one memory op");
10909
10910 MachineFrameInfo &MFI = MF.getFrameInfo();
10911 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
10912
10913 // FIXME: infer better src pointer alignment like SelectionDAG does here.
10914 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
10915 // if the memcpy is in a tail call position.
10916
10917 const auto &DstMMO = **MI.memoperands_begin();
10918 const auto &SrcMMO = **std::next(MI.memoperands_begin());
10919
10920 if (DstAlignCanChange) {
10921 // Get an estimate of the type from the LLT.
10922 Type *IRTy = getTypeForLLT(MemOps[0], C);
10923 Align NewAlign = DL.getABITypeAlign(IRTy);
10924
10925 // Don't promote to an alignment that would require dynamic stack
10926 // realignment.
10927 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
10928 if (!TRI->hasStackRealignment(MF))
10929 if (MaybeAlign StackAlign = DL.getStackAlignment())
10930 NewAlign = std::min(NewAlign, *StackAlign);
10931
10932 if (NewAlign > Alignment) {
10933 Alignment = NewAlign;
10934 unsigned FI = FIDef->getOperand(1).getIndex();
10935 // Give the stack frame object a larger alignment if needed.
10936 if (MFI.getObjectAlign(FI) < Alignment)
10937 MFI.setObjectAlignment(FI, Alignment);
10938 }
10939 }
10940
10941 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
10942
10943 MachineIRBuilder MIB(MI);
10944 // Now we need to emit a pair of load and stores for each of the types we've
10945 // collected. I.e. for each type, generate a load from the source pointer of
10946 // that type width, and then generate a corresponding store to the dest buffer
10947 // of that value loaded. This can result in a sequence of loads and stores
10948 // mixed types, depending on what the target specifies as good types to use.
10949 unsigned CurrOffset = 0;
10950 unsigned Size = KnownLen;
10951 for (auto CopyTy : MemOps) {
10952 // Issuing an unaligned load / store pair that overlaps with the previous
10953 // pair. Adjust the offset accordingly.
10954 if (CopyTy.getSizeInBytes() > Size)
10955 CurrOffset -= CopyTy.getSizeInBytes() - Size;
10956
10957 // Construct MMOs for the accesses.
10958 auto *LoadMMO =
10959 MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
10960 auto *StoreMMO =
10961 MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
10962
10963 // Create the load.
10964 Register LoadPtr = Src;
10966 if (CurrOffset != 0) {
10967 LLT SrcTy = MRI.getType(Src);
10968 Offset =
10969 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset)
10970 .getReg(0);
10971 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
10972 }
10973 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
10974
10975 // Create the store.
10976 Register StorePtr = Dst;
10977 if (CurrOffset != 0) {
10978 LLT DstTy = MRI.getType(Dst);
10979 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
10980 }
10981 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
10982 CurrOffset += CopyTy.getSizeInBytes();
10983 Size -= CopyTy.getSizeInBytes();
10984 }
10985
10986 MI.eraseFromParent();
10987 return Legalized;
10988}
10989
10991LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
10992 uint64_t KnownLen, Align Alignment,
10993 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
10994 auto &MF = *MI.getParent()->getParent();
10995 auto &DL = MF.getDataLayout();
10996 LLVMContext &C = MF.getFunction().getContext();
10997
10998 assert(KnownLen != 0 && "Have a zero length memmove length!");
10999 assert(!MemOps.empty() && "Expected at least one memory op");
11000
11001 MachineFrameInfo &MFI = MF.getFrameInfo();
11002 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11003 const auto &DstMMO = **MI.memoperands_begin();
11004 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11005
11006 if (DstAlignCanChange) {
11007 // Get an estimate of the type from the LLT.
11008 Type *IRTy = getTypeForLLT(MemOps[0], C);
11009 Align NewAlign = DL.getABITypeAlign(IRTy);
11010
11011 // Don't promote to an alignment that would require dynamic stack
11012 // realignment.
11013 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11014 if (!TRI->hasStackRealignment(MF))
11015 if (MaybeAlign StackAlign = DL.getStackAlignment())
11016 NewAlign = std::min(NewAlign, *StackAlign);
11017
11018 if (NewAlign > Alignment) {
11019 Alignment = NewAlign;
11020 unsigned FI = FIDef->getOperand(1).getIndex();
11021 // Give the stack frame object a larger alignment if needed.
11022 if (MFI.getObjectAlign(FI) < Alignment)
11023 MFI.setObjectAlignment(FI, Alignment);
11024 }
11025 }
11026
11027 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
11028
11029 MachineIRBuilder MIB(MI);
11030 // Memmove requires that we perform the loads first before issuing the stores.
11031 // Apart from that, this loop is pretty much doing the same thing as the
11032 // memcpy codegen function.
11033 unsigned CurrOffset = 0;
11034 SmallVector<Register, 16> LoadVals;
11035 for (auto CopyTy : MemOps) {
11036 // Construct MMO for the load.
11037 auto *LoadMMO =
11038 MF.getMachineMemOperand(&SrcMMO, CurrOffset, CopyTy.getSizeInBytes());
11039
11040 // Create the load.
11041 Register LoadPtr = Src;
11042 if (CurrOffset != 0) {
11043 LLT SrcTy = MRI.getType(Src);
11044 auto Offset =
11045 MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset);
11046 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11047 }
11048 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
11049 CurrOffset += CopyTy.getSizeInBytes();
11050 }
11051
11052 CurrOffset = 0;
11053 for (unsigned I = 0; I < MemOps.size(); ++I) {
11054 LLT CopyTy = MemOps[I];
11055 // Now store the values loaded.
11056 auto *StoreMMO =
11057 MF.getMachineMemOperand(&DstMMO, CurrOffset, CopyTy.getSizeInBytes());
11058
11059 Register StorePtr = Dst;
11060 if (CurrOffset != 0) {
11061 LLT DstTy = MRI.getType(Dst);
11062 auto Offset =
11063 MIB.buildConstant(LLT::scalar(DstTy.getSizeInBits()), CurrOffset);
11064 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11065 }
11066 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
11067 CurrOffset += CopyTy.getSizeInBytes();
11068 }
11069 MI.eraseFromParent();
11070 return Legalized;
11071}
11072
11074 MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen,
11075 Align Alignment, bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11076 const unsigned Opc = MI.getOpcode();
11077 assert((Opc == TargetOpcode::G_MEMCPY ||
11078 Opc == TargetOpcode::G_MEMCPY_INLINE ||
11079 Opc == TargetOpcode::G_MEMMOVE || Opc == TargetOpcode::G_MEMSET ||
11080 Opc == TargetOpcode::G_MEMSET_INLINE) &&
11081 "Expected memcpy like instruction");
11082
11083 if (KnownLen == 0) {
11084 MI.eraseFromParent();
11085 return Legalized;
11086 }
11087
11088 if (Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMCPY_INLINE) {
11089 return lowerMemcpy(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11090 MemOps);
11091 }
11092 if (Opc == TargetOpcode::G_MEMMOVE)
11093 return lowerMemmove(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11094 MemOps);
11095 if (Opc == TargetOpcode::G_MEMSET || Opc == TargetOpcode::G_MEMSET_INLINE)
11096 return lowerMemset(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11097 MemOps);
11098 return UnableToLegalize;
11099}
11100
11103 Register Dst, Src;
11104 uint64_t KnownLen;
11105 Align Alignment;
11106 bool DstAlignCanChange;
11107 std::vector<LLT> MemOps;
11108 if (!canLowerMemCpyFamily(MI, MRI, MaxLen, Dst, Src, KnownLen, Alignment,
11109 DstAlignCanChange, MemOps))
11110 return UnableToLegalize;
11111 return lowerMemCpyFamily(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11112 MemOps);
11113}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
constexpr LLT S1
constexpr LLT S32
constexpr LLT S64
AMDGPU Register Bank Select
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
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:77
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 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 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)
MachineInstr unsigned OpIdx
uint64_t High
R600 Clause Merge
static constexpr MCPhysReg SPReg
const SmallVectorImpl< MachineOperand > & Cond
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:297
static constexpr roundingMode rmTowardZero
Definition APFloat.h:349
static const fltSemantics & IEEEdouble()
Definition APFloat.h:298
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:345
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:361
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
Definition APFloat.h:1433
APInt bitcastToAPInt() const
Definition APFloat.h:1457
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1224
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1184
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
Definition APFloat.h:1195
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:235
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1055
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:230
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1565
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1537
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:968
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
Definition APInt.h:207
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
Definition APInt.h:1191
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
Definition APInt.h:259
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:381
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1692
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:210
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
Definition APInt.h:217
void negate()
Negate this APInt in place.
Definition APInt.h:1493
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:652
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:220
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1028
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:880
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:307
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:201
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:858
static APInt getBitsSetWithWrap(unsigned numBits, unsigned loBit, unsigned hiBit)
Wrap version of getBitsSet.
Definition APInt.h:271
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
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:43
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:299
LLT getLLTTy(const MachineRegisterInfo &MRI) const
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:309
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition TypeSize.h:315
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
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:348
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 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
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:68
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 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 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 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 lowerU64ToF32BitOps(MachineInstr &MI)
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 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 Register coerceToScalar(Register Val)
Cast the given value to an LLT::scalar with an equivalent size.
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 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 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.
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:722
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:632
static LLVM_ABI MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
LLVM_ABI iterator getFirstTerminatorForward()
Finds the first terminator in a block by scanning forward.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
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.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags f, LLT MemTy, Align base_alignment, const AAMDNodes &AAInfo=AAMDNodes(), const MDNode *Ranges=nullptr, SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
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.
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,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
static LLVM_ABI PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
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:477
TargetInstrInfo - Interface to description of machine instruction set.
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:343
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:309
static LLVM_ABI Type * getFP128Ty(LLVMContext &C)
Definition Type.cpp:291
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:282
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:313
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:287
static LLVM_ABI Type * getX86_FP80Ty(LLVMContext &C)
Definition Type.cpp:290
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:286
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:284
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:255
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
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:252
#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
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ 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)
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:315
@ Offset
Definition DWP.cpp:573
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:830
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition Utils.cpp:1987
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:656
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:1669
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:297
@ 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:223
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:2208
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:284
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(MachineInstr &MI, const MachineRegisterInfo &MRI)
Determines if MI defines a constant integer or a splat vector of constant integers.
Definition Utils.cpp:1530
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< 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:1587
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1151
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:385
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:1154
unsigned M1(unsigned Val)
Definition VE.h:377
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
Definition MathExtras.h:357
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:331
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:279
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:144
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:511
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:2153
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:1885
constexpr int64_t maxIntN(int64_t N)
Gets the maximum value for a N-bit signed integer.
Definition MathExtras.h:232
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:436
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1947
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
Definition Alignment.h:100
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:197
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:1242
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:614
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:373
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:862
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:77
SmallVector< ISD::ArgFlagsTy, 4 > Flags
CallingConv::ID CallConv
Calling convention to be used for the call.
bool isKnownNeverZero() const
Return true if it's known this can never be a zero.
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.