LLVM 24.0.0git
LegalizerHelper.cpp
Go to the documentation of this file.
1//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This file implements the LegalizerHelper class to legalize
10/// individual instructions and the LegalizeMachineIR wrapper pass for the
11/// primary legalization.
12//
13//===----------------------------------------------------------------------===//
14
36#include "llvm/Support/Debug.h"
40#include <cassert>
41#include <numeric>
42#include <optional>
43
44#define DEBUG_TYPE "legalizer"
45
46using namespace llvm;
47using namespace LegalizeActions;
48using namespace MIPatternMatch;
49
50/// 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::integer(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 else if (DstTy != WideTy)
2287 MIRBuilder.buildBitcast(DstReg, ResultReg);
2288
2289 MI.eraseFromParent();
2290 return Legalized;
2291 }
2292
2293 // Unmerge the original values to the GCD type, and recombine to the next
2294 // multiple greater than the original type.
2295 //
2296 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2297 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2298 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2299 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2300 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2301 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2302 // %12:_(s12) = G_MERGE_VALUES %10, %11
2303 //
2304 // Padding with undef if necessary:
2305 //
2306 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2307 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2308 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2309 // %7:_(s2) = G_IMPLICIT_DEF
2310 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2311 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2312 // %10:_(s12) = G_MERGE_VALUES %8, %9
2313
2314 const int GCD = std::gcd(SrcSize, WideSize);
2315 LLT GCDTy = WideTy.changeElementSize(GCD);
2316
2317 SmallVector<Register, 8> NewMergeRegs;
2318 SmallVector<Register, 8> Unmerges;
2319 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2320
2321 // Decompose the original operands if they don't evenly divide.
2322 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2323 Register SrcReg = MO.getReg();
2324 if (GCD == SrcSize) {
2325 Unmerges.push_back(SrcReg);
2326 } else {
2327 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2328 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2329 Unmerges.push_back(Unmerge.getReg(J));
2330 }
2331 }
2332
2333 // Pad with undef to the next size that is a multiple of the requested size.
2334 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2335 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2336 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2337 Unmerges.push_back(UndefReg);
2338 }
2339
2340 const int PartsPerGCD = WideSize / GCD;
2341
2342 // Build merges of each piece.
2343 ArrayRef<Register> Slicer(Unmerges);
2344 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2345 auto Merge =
2346 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2347 NewMergeRegs.push_back(Merge.getReg(0));
2348 }
2349
2350 // A truncate may be necessary if the requested type doesn't evenly divide the
2351 // original result type.
2352 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2353 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2354 } else {
2355 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2356 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2357 }
2358
2359 MI.eraseFromParent();
2360 return Legalized;
2361}
2362
2364LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2365 LLT WideTy) {
2366 if (TypeIdx != 0)
2367 return UnableToLegalize;
2368
2369 int NumDst = MI.getNumOperands() - 1;
2370 Register SrcReg = MI.getOperand(NumDst).getReg();
2371 LLT SrcTy = MRI.getType(SrcReg);
2372 if (SrcTy.isVector())
2373 return UnableToLegalize;
2374
2375 Register Dst0Reg = MI.getOperand(0).getReg();
2376 LLT DstTy = MRI.getType(Dst0Reg);
2377 if (!DstTy.isScalar())
2378 return UnableToLegalize;
2379
2380 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2381 if (SrcTy.isPointer()) {
2382 const DataLayout &DL = MIRBuilder.getDataLayout();
2383 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2384 LLVM_DEBUG(
2385 dbgs() << "Not casting non-integral address space integer\n");
2386 return UnableToLegalize;
2387 }
2388
2389 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2390 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2391 }
2392
2393 // Widen SrcTy to WideTy. This does not affect the result, but since the
2394 // user requested this size, it is probably better handled than SrcTy and
2395 // should reduce the total number of legalization artifacts.
2396 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2397 SrcTy = WideTy;
2398 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2399 }
2400
2401 // Theres no unmerge type to target. Directly extract the bits from the
2402 // source type
2403 unsigned DstSize = DstTy.getSizeInBits();
2404
2405 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2406 for (int I = 1; I != NumDst; ++I) {
2407 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2408 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2409 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2410 }
2411
2412 MI.eraseFromParent();
2413 return Legalized;
2414 }
2415
2416 // Extend the source to a wider type.
2417 LLT LCMTy = getLCMType(SrcTy, WideTy);
2418
2419 Register WideSrc = SrcReg;
2420 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2421 // TODO: If this is an integral address space, cast to integer and anyext.
2422 if (SrcTy.isPointer()) {
2423 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2424 return UnableToLegalize;
2425 }
2426
2427 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2428 }
2429
2430 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2431
2432 // Create a sequence of unmerges and merges to the original results. Since we
2433 // may have widened the source, we will need to pad the results with dead defs
2434 // to cover the source register.
2435 // e.g. widen s48 to s64:
2436 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2437 //
2438 // =>
2439 // %4:_(s192) = G_ANYEXT %0:_(s96)
2440 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2441 // ; unpack to GCD type, with extra dead defs
2442 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2443 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2444 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2445 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2446 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2447 const LLT GCDTy = getGCDType(WideTy, DstTy);
2448 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2449 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2450
2451 // Directly unmerge to the destination without going through a GCD type
2452 // if possible
2453 if (PartsPerRemerge == 1) {
2454 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2455
2456 for (int I = 0; I != NumUnmerge; ++I) {
2457 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2458
2459 for (int J = 0; J != PartsPerUnmerge; ++J) {
2460 int Idx = I * PartsPerUnmerge + J;
2461 if (Idx < NumDst)
2462 MIB.addDef(MI.getOperand(Idx).getReg());
2463 else {
2464 // Create dead def for excess components.
2465 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2466 }
2467 }
2468
2469 MIB.addUse(Unmerge.getReg(I));
2470 }
2471 } else {
2472 SmallVector<Register, 16> Parts;
2473 for (int J = 0; J != NumUnmerge; ++J)
2474 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2475
2476 SmallVector<Register, 8> RemergeParts;
2477 for (int I = 0; I != NumDst; ++I) {
2478 for (int J = 0; J < PartsPerRemerge; ++J) {
2479 const int Idx = I * PartsPerRemerge + J;
2480 RemergeParts.emplace_back(Parts[Idx]);
2481 }
2482
2483 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2484 RemergeParts.clear();
2485 }
2486 }
2487
2488 MI.eraseFromParent();
2489 return Legalized;
2490}
2491
2493LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2494 LLT WideTy) {
2495 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2496 unsigned Offset = MI.getOperand(2).getImm();
2497
2498 if (TypeIdx == 0) {
2499 if (SrcTy.isVector() || DstTy.isVector())
2500 return UnableToLegalize;
2501
2502 SrcOp Src(SrcReg);
2503 if (SrcTy.isPointer()) {
2504 // Extracts from pointers can be handled only if they are really just
2505 // simple integers.
2506 const DataLayout &DL = MIRBuilder.getDataLayout();
2507 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2508 return UnableToLegalize;
2509
2510 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2511 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2512 SrcTy = SrcAsIntTy;
2513 }
2514
2515 if (DstTy.isPointer())
2516 return UnableToLegalize;
2517
2518 if (Offset == 0) {
2519 // Avoid a shift in the degenerate case.
2520 MIRBuilder.buildTrunc(DstReg,
2521 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2522 MI.eraseFromParent();
2523 return Legalized;
2524 }
2525
2526 // Do a shift in the source type.
2527 LLT ShiftTy = SrcTy;
2528 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2529 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2530 ShiftTy = WideTy;
2531 }
2532
2533 auto LShr = MIRBuilder.buildLShr(
2534 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2535 MIRBuilder.buildTrunc(DstReg, LShr);
2536 MI.eraseFromParent();
2537 return Legalized;
2538 }
2539
2540 if (SrcTy.isScalar()) {
2541 Observer.changingInstr(MI);
2542 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2543 Observer.changedInstr(MI);
2544 return Legalized;
2545 }
2546
2547 if (!SrcTy.isVector())
2548 return UnableToLegalize;
2549
2550 if (DstTy != SrcTy.getElementType())
2551 return UnableToLegalize;
2552
2553 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2554 return UnableToLegalize;
2555
2556 Observer.changingInstr(MI);
2557 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2558
2559 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2560 Offset);
2561 widenScalarDst(MI, WideTy.getScalarType(), 0);
2562 Observer.changedInstr(MI);
2563 return Legalized;
2564}
2565
2567LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2568 LLT WideTy) {
2569 if (TypeIdx != 0 || WideTy.isVector())
2570 return UnableToLegalize;
2571 Observer.changingInstr(MI);
2572 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2573 widenScalarDst(MI, WideTy);
2574 Observer.changedInstr(MI);
2575 return Legalized;
2576}
2577
2579LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2580 LLT WideTy) {
2581 unsigned Opcode;
2582 unsigned ExtOpcode;
2583 std::optional<Register> CarryIn;
2584 switch (MI.getOpcode()) {
2585 default:
2586 llvm_unreachable("Unexpected opcode!");
2587 case TargetOpcode::G_SADDO:
2588 Opcode = TargetOpcode::G_ADD;
2589 ExtOpcode = TargetOpcode::G_SEXT;
2590 break;
2591 case TargetOpcode::G_SSUBO:
2592 Opcode = TargetOpcode::G_SUB;
2593 ExtOpcode = TargetOpcode::G_SEXT;
2594 break;
2595 case TargetOpcode::G_UADDO:
2596 Opcode = TargetOpcode::G_ADD;
2597 ExtOpcode = TargetOpcode::G_ZEXT;
2598 break;
2599 case TargetOpcode::G_USUBO:
2600 Opcode = TargetOpcode::G_SUB;
2601 ExtOpcode = TargetOpcode::G_ZEXT;
2602 break;
2603 case TargetOpcode::G_SADDE:
2604 Opcode = TargetOpcode::G_UADDE;
2605 ExtOpcode = TargetOpcode::G_SEXT;
2606 CarryIn = MI.getOperand(4).getReg();
2607 break;
2608 case TargetOpcode::G_SSUBE:
2609 Opcode = TargetOpcode::G_USUBE;
2610 ExtOpcode = TargetOpcode::G_SEXT;
2611 CarryIn = MI.getOperand(4).getReg();
2612 break;
2613 case TargetOpcode::G_UADDE:
2614 Opcode = TargetOpcode::G_UADDE;
2615 ExtOpcode = TargetOpcode::G_ZEXT;
2616 CarryIn = MI.getOperand(4).getReg();
2617 break;
2618 case TargetOpcode::G_USUBE:
2619 Opcode = TargetOpcode::G_USUBE;
2620 ExtOpcode = TargetOpcode::G_ZEXT;
2621 CarryIn = MI.getOperand(4).getReg();
2622 break;
2623 }
2624
2625 if (TypeIdx == 1) {
2626 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2627
2628 Observer.changingInstr(MI);
2629 if (CarryIn)
2630 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2631 widenScalarDst(MI, WideTy, 1);
2632
2633 Observer.changedInstr(MI);
2634 return Legalized;
2635 }
2636
2637 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2638 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2639 // Do the arithmetic in the larger type.
2640 Register NewOp;
2641 if (CarryIn) {
2642 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2643 NewOp = MIRBuilder
2644 .buildInstr(Opcode, {WideTy, CarryOutTy},
2645 {LHSExt, RHSExt, *CarryIn})
2646 .getReg(0);
2647 } else {
2648 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2649 }
2650 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2651 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2652 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2653 // There is no overflow if the ExtOp is the same as NewOp.
2654 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2655 // Now trunc the NewOp to the original result.
2656 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2657 MI.eraseFromParent();
2658 return Legalized;
2659}
2660
2662LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2663 LLT WideTy) {
2664 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2665 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2666 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2667 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2668 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2669 // We can convert this to:
2670 // 1. Any extend iN to iM
2671 // 2. SHL by M-N
2672 // 3. [US][ADD|SUB|SHL]SAT
2673 // 4. L/ASHR by M-N
2674 //
2675 // It may be more efficient to lower this to a min and a max operation in
2676 // the higher precision arithmetic if the promoted operation isn't legal,
2677 // but this decision is up to the target's lowering request.
2678 Register DstReg = MI.getOperand(0).getReg();
2679
2680 unsigned NewBits = WideTy.getScalarSizeInBits();
2681 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2682
2683 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2684 // must not left shift the RHS to preserve the shift amount.
2685 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2686 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2687 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2688 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2689 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2690 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2691
2692 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2693 {ShiftL, ShiftR}, MI.getFlags());
2694
2695 // Use a shift that will preserve the number of sign bits when the trunc is
2696 // folded away.
2697 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2698 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2699
2700 MIRBuilder.buildTrunc(DstReg, Result);
2701 MI.eraseFromParent();
2702 return Legalized;
2703}
2704
2706LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2707 LLT WideTy) {
2708 if (TypeIdx == 1) {
2709 Observer.changingInstr(MI);
2710 widenScalarDst(MI, WideTy, 1);
2711 Observer.changedInstr(MI);
2712 return Legalized;
2713 }
2714
2715 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2716 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2717 LLT SrcTy = MRI.getType(LHS);
2718 LLT OverflowTy = MRI.getType(OriginalOverflow);
2719 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2720
2721 // To determine if the result overflowed in the larger type, we extend the
2722 // input to the larger type, do the multiply (checking if it overflows),
2723 // then also check the high bits of the result to see if overflow happened
2724 // there.
2725 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2726 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2727 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2728
2729 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2730 // so we don't need to check the overflow result of larger type Mulo.
2731 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2732
2733 unsigned MulOpc =
2734 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2735
2736 MachineInstrBuilder Mulo;
2737 if (WideMulCanOverflow)
2738 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2739 {LeftOperand, RightOperand});
2740 else
2741 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2742
2743 auto Mul = Mulo->getOperand(0);
2744 MIRBuilder.buildTrunc(Result, Mul);
2745
2746 MachineInstrBuilder ExtResult;
2747 // Overflow occurred if it occurred in the larger type, or if the high part
2748 // of the result does not zero/sign-extend the low part. Check this second
2749 // possibility first.
2750 if (IsSigned) {
2751 // For signed, overflow occurred when the high part does not sign-extend
2752 // the low part.
2753 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2754 } else {
2755 // Unsigned overflow occurred when the high part does not zero-extend the
2756 // low part.
2757 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2758 }
2759
2760 if (WideMulCanOverflow) {
2761 auto Overflow =
2762 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2763 // Finally check if the multiplication in the larger type itself overflowed.
2764 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2765 } else {
2766 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2767 }
2768 MI.eraseFromParent();
2769 return Legalized;
2770}
2771
2774 unsigned Opcode = MI.getOpcode();
2775 switch (Opcode) {
2776 default:
2777 return UnableToLegalize;
2778 case TargetOpcode::G_ATOMICRMW_XCHG:
2779 case TargetOpcode::G_ATOMICRMW_ADD:
2780 case TargetOpcode::G_ATOMICRMW_SUB:
2781 case TargetOpcode::G_ATOMICRMW_AND:
2782 case TargetOpcode::G_ATOMICRMW_OR:
2783 case TargetOpcode::G_ATOMICRMW_XOR:
2784 case TargetOpcode::G_ATOMICRMW_MIN:
2785 case TargetOpcode::G_ATOMICRMW_MAX:
2786 case TargetOpcode::G_ATOMICRMW_UMIN:
2787 case TargetOpcode::G_ATOMICRMW_UMAX:
2788 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2789 Observer.changingInstr(MI);
2790 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2791 widenScalarDst(MI, WideTy, 0);
2792 Observer.changedInstr(MI);
2793 return Legalized;
2794 case TargetOpcode::G_ATOMIC_CMPXCHG:
2795 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2796 Observer.changingInstr(MI);
2797 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2798 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2799 widenScalarDst(MI, WideTy, 0);
2800 Observer.changedInstr(MI);
2801 return Legalized;
2802 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2803 if (TypeIdx == 0) {
2804 Observer.changingInstr(MI);
2805 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2806 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2807 widenScalarDst(MI, WideTy, 0);
2808 Observer.changedInstr(MI);
2809 return Legalized;
2810 }
2811 assert(TypeIdx == 1 &&
2812 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2813 Observer.changingInstr(MI);
2814 widenScalarDst(MI, WideTy, 1);
2815 Observer.changedInstr(MI);
2816 return Legalized;
2817 case TargetOpcode::G_EXTRACT:
2818 return widenScalarExtract(MI, TypeIdx, WideTy);
2819 case TargetOpcode::G_INSERT:
2820 return widenScalarInsert(MI, TypeIdx, WideTy);
2821 case TargetOpcode::G_MERGE_VALUES:
2822 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2823 case TargetOpcode::G_UNMERGE_VALUES:
2824 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2825 case TargetOpcode::G_SADDO:
2826 case TargetOpcode::G_SSUBO:
2827 case TargetOpcode::G_UADDO:
2828 case TargetOpcode::G_USUBO:
2829 case TargetOpcode::G_SADDE:
2830 case TargetOpcode::G_SSUBE:
2831 case TargetOpcode::G_UADDE:
2832 case TargetOpcode::G_USUBE:
2833 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2834 case TargetOpcode::G_UMULO:
2835 case TargetOpcode::G_SMULO:
2836 return widenScalarMulo(MI, TypeIdx, WideTy);
2837 case TargetOpcode::G_SADDSAT:
2838 case TargetOpcode::G_SSUBSAT:
2839 case TargetOpcode::G_SSHLSAT:
2840 case TargetOpcode::G_UADDSAT:
2841 case TargetOpcode::G_USUBSAT:
2842 case TargetOpcode::G_USHLSAT:
2843 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2844 case TargetOpcode::G_CTTZ:
2845 case TargetOpcode::G_CTTZ_ZERO_POISON:
2846 case TargetOpcode::G_CTLZ:
2847 case TargetOpcode::G_CTLZ_ZERO_POISON:
2848 case TargetOpcode::G_CTLS:
2849 case TargetOpcode::G_CTPOP: {
2850 if (TypeIdx == 0) {
2851 Observer.changingInstr(MI);
2852 widenScalarDst(MI, WideTy, 0);
2853 Observer.changedInstr(MI);
2854 return Legalized;
2855 }
2856
2857 Register SrcReg = MI.getOperand(1).getReg();
2858
2859 // First extend the input.
2860 unsigned ExtOpc;
2861 switch (Opcode) {
2862 case TargetOpcode::G_CTTZ:
2863 case TargetOpcode::G_CTTZ_ZERO_POISON:
2864 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2865 ExtOpc = TargetOpcode::G_ANYEXT;
2866 break;
2867 case TargetOpcode::G_CTLS:
2868 ExtOpc = TargetOpcode::G_SEXT;
2869 break;
2870 default:
2871 ExtOpc = TargetOpcode::G_ZEXT;
2872 }
2873
2874 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2875 LLT CurTy = MRI.getType(SrcReg);
2876 unsigned NewOpc = Opcode;
2877 if (NewOpc == TargetOpcode::G_CTTZ) {
2878 // The count is the same in the larger type except if the original
2879 // value was zero. This can be handled by setting the bit just off
2880 // the top of the original type.
2881 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2882 CurTy.getScalarSizeInBits());
2883 MIBSrc = MIRBuilder.buildOr(
2884 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2885 // Now we know the operand is non-zero, use the more relaxed opcode.
2886 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2887 }
2888
2889 unsigned SizeDiff =
2890 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2891
2892 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2893 // An optimization where the result is the CTLZ after the left shift by
2894 // (Difference in widety and current ty), that is,
2895 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2896 // Result = ctlz MIBSrc
2897 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2898 MIRBuilder.buildConstant(WideTy, SizeDiff));
2899 }
2900
2901 // Perform the operation at the larger size.
2902 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2903 // This is already the correct result for CTPOP and CTTZs
2904 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2905 // The correct result is NewOp - (Difference in widety and current ty).
2906 // At this stage SUB is guaranteed to be positive no-wrap,
2907 // that to be used in further KnownBits optimizations for CTLZ.
2908 MIBNewOp = MIRBuilder.buildSub(
2909 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2910 Opcode == TargetOpcode::G_CTLZ
2911 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2912 : std::nullopt);
2913 }
2914
2915 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2916 MI.eraseFromParent();
2917 return Legalized;
2918 }
2919 case TargetOpcode::G_BSWAP: {
2920 Observer.changingInstr(MI);
2921 Register DstReg = MI.getOperand(0).getReg();
2922
2923 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2924 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2925 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2926 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2927
2928 MI.getOperand(0).setReg(DstExt);
2929
2930 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2931
2932 LLT Ty = MRI.getType(DstReg);
2933 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2934 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2935 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2936
2937 MIRBuilder.buildTrunc(DstReg, ShrReg);
2938 Observer.changedInstr(MI);
2939 return Legalized;
2940 }
2941 case TargetOpcode::G_BITREVERSE: {
2942 Observer.changingInstr(MI);
2943
2944 Register DstReg = MI.getOperand(0).getReg();
2945 LLT Ty = MRI.getType(DstReg);
2946 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2947
2948 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2949 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2950 MI.getOperand(0).setReg(DstExt);
2951 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2952
2953 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2954 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2955 MIRBuilder.buildTrunc(DstReg, Shift);
2956 Observer.changedInstr(MI);
2957 return Legalized;
2958 }
2959 case TargetOpcode::G_FREEZE:
2960 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2961 Observer.changingInstr(MI);
2962 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2963 widenScalarDst(MI, WideTy);
2964 Observer.changedInstr(MI);
2965 return Legalized;
2966
2967 case TargetOpcode::G_ABS:
2968 Observer.changingInstr(MI);
2969 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2970 widenScalarDst(MI, WideTy);
2971 Observer.changedInstr(MI);
2972 return Legalized;
2973
2974 case TargetOpcode::G_ADD:
2975 case TargetOpcode::G_AND:
2976 case TargetOpcode::G_MUL:
2977 case TargetOpcode::G_OR:
2978 case TargetOpcode::G_XOR:
2979 case TargetOpcode::G_SUB:
2980 case TargetOpcode::G_SHUFFLE_VECTOR:
2981 // Perform operation at larger width (any extension is fines here, high bits
2982 // don't affect the result) and then truncate the result back to the
2983 // original type.
2984 Observer.changingInstr(MI);
2985 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2986 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2987 widenScalarDst(MI, WideTy);
2988 Observer.changedInstr(MI);
2989 return Legalized;
2990
2991 case TargetOpcode::G_SBFX:
2992 case TargetOpcode::G_UBFX:
2993 Observer.changingInstr(MI);
2994
2995 if (TypeIdx == 0) {
2996 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2997 widenScalarDst(MI, WideTy);
2998 } else {
2999 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3000 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3001 }
3002
3003 Observer.changedInstr(MI);
3004 return Legalized;
3005
3006 case TargetOpcode::G_SHL:
3007 Observer.changingInstr(MI);
3008
3009 if (TypeIdx == 0) {
3010 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3011 widenScalarDst(MI, WideTy);
3012 } else {
3013 assert(TypeIdx == 1);
3014 // The "number of bits to shift" operand must preserve its value as an
3015 // unsigned integer:
3016 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3017 }
3018
3019 Observer.changedInstr(MI);
3020 return Legalized;
3021
3022 case TargetOpcode::G_ROTR:
3023 case TargetOpcode::G_ROTL:
3024 if (TypeIdx != 1)
3025 return UnableToLegalize;
3026
3027 Observer.changingInstr(MI);
3028 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3029 Observer.changedInstr(MI);
3030 return Legalized;
3031
3032 case TargetOpcode::G_SDIV:
3033 case TargetOpcode::G_SREM:
3034 case TargetOpcode::G_SMIN:
3035 case TargetOpcode::G_SMAX:
3036 case TargetOpcode::G_ABDS:
3037 Observer.changingInstr(MI);
3038 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3039 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3040 widenScalarDst(MI, WideTy);
3041 Observer.changedInstr(MI);
3042 return Legalized;
3043
3044 case TargetOpcode::G_SDIVREM:
3045 Observer.changingInstr(MI);
3046 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3047 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3048 widenScalarDst(MI, WideTy);
3049 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3050 widenScalarDst(MI, WideTy, 1);
3051 Observer.changedInstr(MI);
3052 return Legalized;
3053
3054 case TargetOpcode::G_ASHR:
3055 case TargetOpcode::G_LSHR:
3056 Observer.changingInstr(MI);
3057
3058 if (TypeIdx == 0) {
3059 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3060 : TargetOpcode::G_ZEXT;
3061
3062 widenScalarSrc(MI, WideTy, 1, CvtOp);
3063 widenScalarDst(MI, WideTy);
3064 } else {
3065 assert(TypeIdx == 1);
3066 // The "number of bits to shift" operand must preserve its value as an
3067 // unsigned integer:
3068 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3069 }
3070
3071 Observer.changedInstr(MI);
3072 return Legalized;
3073 case TargetOpcode::G_UDIV:
3074 case TargetOpcode::G_UREM:
3075 case TargetOpcode::G_ABDU:
3076 Observer.changingInstr(MI);
3077 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3078 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3079 widenScalarDst(MI, WideTy);
3080 Observer.changedInstr(MI);
3081 return Legalized;
3082 case TargetOpcode::G_UDIVREM:
3083 Observer.changingInstr(MI);
3084 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3085 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3086 widenScalarDst(MI, WideTy);
3087 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3088 widenScalarDst(MI, WideTy, 1);
3089 Observer.changedInstr(MI);
3090 return Legalized;
3091 case TargetOpcode::G_UMIN:
3092 case TargetOpcode::G_UMAX: {
3093 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3094
3095 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3096 unsigned ExtOpc =
3097 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3098 getApproximateEVTForLLT(WideTy, Ctx))
3099 ? TargetOpcode::G_SEXT
3100 : TargetOpcode::G_ZEXT;
3101
3102 Observer.changingInstr(MI);
3103 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3104 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3105 widenScalarDst(MI, WideTy);
3106 Observer.changedInstr(MI);
3107 return Legalized;
3108 }
3109
3110 case TargetOpcode::G_SELECT:
3111 Observer.changingInstr(MI);
3112 if (TypeIdx == 0) {
3113 // Perform operation at larger width (any extension is fine here, high
3114 // bits don't affect the result) and then truncate the result back to the
3115 // original type.
3116 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3117 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3118 widenScalarDst(MI, WideTy);
3119 } else {
3120 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3121 // Explicit extension is required here since high bits affect the result.
3122 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3123 }
3124 Observer.changedInstr(MI);
3125 return Legalized;
3126
3127 case TargetOpcode::G_FPEXT:
3128 if (TypeIdx != 1)
3129 return UnableToLegalize;
3130
3131 Observer.changingInstr(MI);
3132 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3133 Observer.changedInstr(MI);
3134 return Legalized;
3135 case TargetOpcode::G_FPTOSI:
3136 case TargetOpcode::G_FPTOUI:
3137 case TargetOpcode::G_INTRINSIC_LRINT:
3138 case TargetOpcode::G_INTRINSIC_LLRINT:
3139 case TargetOpcode::G_IS_FPCLASS:
3140 Observer.changingInstr(MI);
3141
3142 if (TypeIdx == 0)
3143 widenScalarDst(MI, WideTy);
3144 else
3145 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3146
3147 Observer.changedInstr(MI);
3148 return Legalized;
3149 case TargetOpcode::G_SITOFP:
3150 Observer.changingInstr(MI);
3151
3152 if (TypeIdx == 0)
3153 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3154 else
3155 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3156
3157 Observer.changedInstr(MI);
3158 return Legalized;
3159 case TargetOpcode::G_UITOFP:
3160 Observer.changingInstr(MI);
3161
3162 if (TypeIdx == 0)
3163 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3164 else
3165 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3166
3167 Observer.changedInstr(MI);
3168 return Legalized;
3169 case TargetOpcode::G_FPTOSI_SAT:
3170 case TargetOpcode::G_FPTOUI_SAT:
3171 Observer.changingInstr(MI);
3172
3173 if (TypeIdx == 0) {
3174 Register OldDst = MI.getOperand(0).getReg();
3175 LLT Ty = MRI.getType(OldDst);
3176 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3177 Register NewDst;
3178 MI.getOperand(0).setReg(ExtReg);
3179 uint64_t ShortBits = Ty.getScalarSizeInBits();
3180 uint64_t WideBits = WideTy.getScalarSizeInBits();
3181 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3182 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3183 // z = i16 fptosi_sat(a)
3184 // ->
3185 // x = i32 fptosi_sat(a)
3186 // y = smin(x, 32767)
3187 // z = smax(y, -32768)
3188 auto MaxVal = MIRBuilder.buildConstant(
3189 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3190 auto MinVal = MIRBuilder.buildConstant(
3191 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3192 Register MidReg =
3193 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3194 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3195 } else {
3196 // z = i16 fptoui_sat(a)
3197 // ->
3198 // x = i32 fptoui_sat(a)
3199 // y = smin(x, 65535)
3200 auto MaxVal = MIRBuilder.buildConstant(
3201 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3202 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3203 }
3204 MIRBuilder.buildTrunc(OldDst, NewDst);
3205 } else
3206 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3207
3208 Observer.changedInstr(MI);
3209 return Legalized;
3210 case TargetOpcode::G_LOAD:
3211 case TargetOpcode::G_SEXTLOAD:
3212 case TargetOpcode::G_ZEXTLOAD:
3213 case TargetOpcode::G_FPEXTLOAD:
3214 Observer.changingInstr(MI);
3215 widenScalarDst(MI, WideTy);
3216 Observer.changedInstr(MI);
3217 return Legalized;
3218
3219 case TargetOpcode::G_STORE: {
3220 if (TypeIdx != 0)
3221 return UnableToLegalize;
3222
3223 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3224 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3225 if (!Ty.isScalar()) {
3226 // We need to widen the vector element type.
3227 Observer.changingInstr(MI);
3228 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3229 // We also need to adjust the MMO to turn this into a truncating store.
3230 MachineMemOperand &MMO = **MI.memoperands_begin();
3231 MachineFunction &MF = MIRBuilder.getMF();
3232 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3233 MI.setMemRefs(MF, {NewMMO});
3234 Observer.changedInstr(MI);
3235 return Legalized;
3236 }
3237
3238 Observer.changingInstr(MI);
3239
3240 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3241 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3242 widenScalarSrc(MI, WideTy, 0, ExtType);
3243
3244 Observer.changedInstr(MI);
3245 return Legalized;
3246 }
3247 case TargetOpcode::G_FPTRUNCSTORE:
3248 if (TypeIdx != 0)
3249 return UnableToLegalize;
3250 Observer.changingInstr(MI);
3251 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3252 Observer.changedInstr(MI);
3253 return Legalized;
3254 case TargetOpcode::G_CONSTANT: {
3255 MachineOperand &SrcMO = MI.getOperand(1);
3256 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3257 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3258 MRI.getType(MI.getOperand(0).getReg()));
3259 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3260 ExtOpc == TargetOpcode::G_ANYEXT) &&
3261 "Illegal Extend");
3262 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3263 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3264 ? SrcVal.sext(WideTy.getSizeInBits())
3265 : SrcVal.zext(WideTy.getSizeInBits());
3266 Observer.changingInstr(MI);
3267 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3268
3269 widenScalarDst(MI, WideTy);
3270 Observer.changedInstr(MI);
3271 return Legalized;
3272 }
3273 case TargetOpcode::G_FCONSTANT: {
3274 // To avoid changing the bits of the constant due to extension to a larger
3275 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3276 MachineOperand &SrcMO = MI.getOperand(1);
3277 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3278 MIRBuilder.setInstrAndDebugLoc(MI);
3279 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3280 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3281 MI.eraseFromParent();
3282 return Legalized;
3283 }
3284 case TargetOpcode::G_IMPLICIT_DEF: {
3285 Observer.changingInstr(MI);
3286 widenScalarDst(MI, WideTy);
3287 Observer.changedInstr(MI);
3288 return Legalized;
3289 }
3290 case TargetOpcode::G_BRCOND:
3291 Observer.changingInstr(MI);
3292 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3293 Observer.changedInstr(MI);
3294 return Legalized;
3295
3296 case TargetOpcode::G_FCMP:
3297 Observer.changingInstr(MI);
3298 if (TypeIdx == 0)
3299 widenScalarDst(MI, WideTy);
3300 else {
3301 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3302 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3303 }
3304 Observer.changedInstr(MI);
3305 return Legalized;
3306
3307 case TargetOpcode::G_ICMP:
3308 Observer.changingInstr(MI);
3309 if (TypeIdx == 0)
3310 widenScalarDst(MI, WideTy);
3311 else {
3312 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3313 CmpInst::Predicate Pred =
3314 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3315
3316 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3317 unsigned ExtOpcode =
3318 (CmpInst::isSigned(Pred) ||
3319 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3320 getApproximateEVTForLLT(WideTy, Ctx)))
3321 ? TargetOpcode::G_SEXT
3322 : TargetOpcode::G_ZEXT;
3323 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3324 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3325 }
3326 Observer.changedInstr(MI);
3327 return Legalized;
3328
3329 case TargetOpcode::G_PTR_ADD:
3330 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3331 Observer.changingInstr(MI);
3332 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3333 Observer.changedInstr(MI);
3334 return Legalized;
3335
3336 case TargetOpcode::G_PHI: {
3337 assert(TypeIdx == 0 && "Expecting only Idx 0");
3338
3339 Observer.changingInstr(MI);
3340 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3341 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3342 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3343 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3344 }
3345
3346 MachineBasicBlock &MBB = *MI.getParent();
3347 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3348 widenScalarDst(MI, WideTy);
3349 Observer.changedInstr(MI);
3350 return Legalized;
3351 }
3352 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3353 if (TypeIdx == 0) {
3354 Register VecReg = MI.getOperand(1).getReg();
3355 LLT VecTy = MRI.getType(VecReg);
3356 Observer.changingInstr(MI);
3357
3358 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3359 TargetOpcode::G_ANYEXT);
3360
3361 widenScalarDst(MI, WideTy, 0);
3362 Observer.changedInstr(MI);
3363 return Legalized;
3364 }
3365
3366 if (TypeIdx != 2)
3367 return UnableToLegalize;
3368 Observer.changingInstr(MI);
3369 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3370 Observer.changedInstr(MI);
3371 return Legalized;
3372 }
3373 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3374 if (TypeIdx == 0) {
3375 Observer.changingInstr(MI);
3376 const LLT WideEltTy = WideTy.getElementType();
3377
3378 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3379 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3380 widenScalarDst(MI, WideTy, 0);
3381 Observer.changedInstr(MI);
3382 return Legalized;
3383 }
3384
3385 if (TypeIdx == 1) {
3386 Observer.changingInstr(MI);
3387
3388 Register VecReg = MI.getOperand(1).getReg();
3389 LLT VecTy = MRI.getType(VecReg);
3390 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3391
3392 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3393 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3394 widenScalarDst(MI, WideVecTy, 0);
3395 Observer.changedInstr(MI);
3396 return Legalized;
3397 }
3398
3399 if (TypeIdx == 2) {
3400 Observer.changingInstr(MI);
3401 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3402 Observer.changedInstr(MI);
3403 return Legalized;
3404 }
3405
3406 return UnableToLegalize;
3407 }
3408 case TargetOpcode::G_FADD:
3409 case TargetOpcode::G_FMUL:
3410 case TargetOpcode::G_FSUB:
3411 case TargetOpcode::G_FMA:
3412 case TargetOpcode::G_FMAD:
3413 case TargetOpcode::G_FNEG:
3414 case TargetOpcode::G_FABS:
3415 case TargetOpcode::G_FCANONICALIZE:
3416 case TargetOpcode::G_FMINNUM:
3417 case TargetOpcode::G_FMAXNUM:
3418 case TargetOpcode::G_FMINNUM_IEEE:
3419 case TargetOpcode::G_FMAXNUM_IEEE:
3420 case TargetOpcode::G_FMINIMUM:
3421 case TargetOpcode::G_FMAXIMUM:
3422 case TargetOpcode::G_FMINIMUMNUM:
3423 case TargetOpcode::G_FMAXIMUMNUM:
3424 case TargetOpcode::G_FDIV:
3425 case TargetOpcode::G_FREM:
3426 case TargetOpcode::G_FCEIL:
3427 case TargetOpcode::G_FFLOOR:
3428 case TargetOpcode::G_FCOS:
3429 case TargetOpcode::G_FSIN:
3430 case TargetOpcode::G_FTAN:
3431 case TargetOpcode::G_FACOS:
3432 case TargetOpcode::G_FASIN:
3433 case TargetOpcode::G_FATAN:
3434 case TargetOpcode::G_FATAN2:
3435 case TargetOpcode::G_FCOSH:
3436 case TargetOpcode::G_FSINH:
3437 case TargetOpcode::G_FTANH:
3438 case TargetOpcode::G_FLOG10:
3439 case TargetOpcode::G_FLOG:
3440 case TargetOpcode::G_FLOG2:
3441 case TargetOpcode::G_FRINT:
3442 case TargetOpcode::G_FNEARBYINT:
3443 case TargetOpcode::G_FSQRT:
3444 case TargetOpcode::G_FEXP:
3445 case TargetOpcode::G_FEXP2:
3446 case TargetOpcode::G_FEXP10:
3447 case TargetOpcode::G_FPOW:
3448 case TargetOpcode::G_INTRINSIC_TRUNC:
3449 case TargetOpcode::G_INTRINSIC_ROUND:
3450 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3451 assert(TypeIdx == 0);
3452 Observer.changingInstr(MI);
3453
3454 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3455 widenScalarSrcUsingFPExt(MI, WideTy, I);
3456
3457 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3458 Observer.changedInstr(MI);
3459 return Legalized;
3460 case TargetOpcode::G_FMODF: {
3461 Observer.changingInstr(MI);
3462 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3463
3464 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3465 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3466 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3467 Observer.changedInstr(MI);
3468 return Legalized;
3469 }
3470 case TargetOpcode::G_FPOWI:
3471 case TargetOpcode::G_FLDEXP:
3472 case TargetOpcode::G_STRICT_FLDEXP: {
3473 if (TypeIdx == 0) {
3474 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3475 return UnableToLegalize;
3476
3477 Observer.changingInstr(MI);
3478 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3479 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3480 Observer.changedInstr(MI);
3481 return Legalized;
3482 }
3483
3484 if (TypeIdx == 1) {
3485 // For some reason SelectionDAG tries to promote to a libcall without
3486 // actually changing the integer type for promotion.
3487 Observer.changingInstr(MI);
3488 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3489 Observer.changedInstr(MI);
3490 return Legalized;
3491 }
3492
3493 return UnableToLegalize;
3494 }
3495 case TargetOpcode::G_FFREXP: {
3496 Observer.changingInstr(MI);
3497
3498 if (TypeIdx == 0) {
3499 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3500 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3501 } else {
3502 widenScalarDst(MI, WideTy, 1);
3503 }
3504
3505 Observer.changedInstr(MI);
3506 return Legalized;
3507 }
3508 case TargetOpcode::G_LROUND:
3509 case TargetOpcode::G_LLROUND:
3510 Observer.changingInstr(MI);
3511
3512 if (TypeIdx == 0)
3513 widenScalarDst(MI, WideTy);
3514 else
3515 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3516
3517 Observer.changedInstr(MI);
3518 return Legalized;
3519
3520 case TargetOpcode::G_INTTOPTR:
3521 if (TypeIdx != 1)
3522 return UnableToLegalize;
3523
3524 Observer.changingInstr(MI);
3525 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3526 Observer.changedInstr(MI);
3527 return Legalized;
3528 case TargetOpcode::G_PTRTOINT:
3529 if (TypeIdx != 0)
3530 return UnableToLegalize;
3531
3532 Observer.changingInstr(MI);
3533 widenScalarDst(MI, WideTy, 0);
3534 Observer.changedInstr(MI);
3535 return Legalized;
3536 case TargetOpcode::G_BUILD_VECTOR: {
3537 Observer.changingInstr(MI);
3538
3539 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3540 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3541 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3542
3543 // Avoid changing the result vector type if the source element type was
3544 // requested.
3545 if (TypeIdx == 1) {
3546 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3547 } else {
3548 widenScalarDst(MI, WideTy, 0);
3549 }
3550
3551 Observer.changedInstr(MI);
3552 return Legalized;
3553 }
3554 case TargetOpcode::G_SEXT_INREG:
3555 if (TypeIdx != 0)
3556 return UnableToLegalize;
3557
3558 Observer.changingInstr(MI);
3559 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3560 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3561 Observer.changedInstr(MI);
3562 return Legalized;
3563 case TargetOpcode::G_PTRMASK: {
3564 if (TypeIdx != 1)
3565 return UnableToLegalize;
3566 Observer.changingInstr(MI);
3567 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3568 Observer.changedInstr(MI);
3569 return Legalized;
3570 }
3571 case TargetOpcode::G_VECREDUCE_ADD: {
3572 if (TypeIdx != 1)
3573 return UnableToLegalize;
3574 Observer.changingInstr(MI);
3575 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3576 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3577 Observer.changedInstr(MI);
3578 return Legalized;
3579 }
3580 case TargetOpcode::G_VECREDUCE_FADD:
3581 case TargetOpcode::G_VECREDUCE_FMUL:
3582 case TargetOpcode::G_VECREDUCE_FMIN:
3583 case TargetOpcode::G_VECREDUCE_FMAX:
3584 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3585 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3586 if (TypeIdx != 0)
3587 return UnableToLegalize;
3588 Observer.changingInstr(MI);
3589 Register VecReg = MI.getOperand(1).getReg();
3590 LLT VecTy = MRI.getType(VecReg);
3591 LLT WideVecTy = VecTy.changeElementType(WideTy);
3592 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3593 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3594 Observer.changedInstr(MI);
3595 return Legalized;
3596 }
3597 case TargetOpcode::G_VSCALE: {
3598 MachineOperand &SrcMO = MI.getOperand(1);
3599 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3600 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3601 // The CImm is always a signed value
3602 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3603 Observer.changingInstr(MI);
3604 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3605 widenScalarDst(MI, WideTy);
3606 Observer.changedInstr(MI);
3607 return Legalized;
3608 }
3609 case TargetOpcode::G_SPLAT_VECTOR: {
3610 if (TypeIdx != 1)
3611 return UnableToLegalize;
3612
3613 Observer.changingInstr(MI);
3614 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3615 Observer.changedInstr(MI);
3616 return Legalized;
3617 }
3618 case TargetOpcode::G_INSERT_SUBVECTOR: {
3619 if (TypeIdx != 0)
3620 return UnableToLegalize;
3621
3623 Register BigVec = IS.getBigVec();
3624 Register SubVec = IS.getSubVec();
3625
3626 LLT SubVecTy = MRI.getType(SubVec);
3627 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3628
3629 // Widen the G_INSERT_SUBVECTOR
3630 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3631 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3632 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3633 IS.getIndexImm());
3634
3635 // Truncate back down
3636 auto SplatZero = MIRBuilder.buildSplatVector(
3637 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3638 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3639 SplatZero);
3640
3641 MI.eraseFromParent();
3642
3643 return Legalized;
3644 }
3645 case TargetOpcode::G_BITCAST:
3646 if (WideTy.isVector())
3647 return UnableToLegalize;
3648 Observer.changingInstr(MI);
3649 if (TypeIdx == 0)
3650 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3651 else
3652 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3653 Observer.changedInstr(MI);
3654
3655 Register Dst = MI.getOperand(0).getReg();
3656 Register Src = MI.getOperand(1).getReg();
3657 if (MRI.getType(Dst) == MRI.getType(Src)) {
3658 Observer.changingAllUsesOfReg(MRI, Dst);
3659 MRI.replaceRegWith(Dst, Src);
3660 Observer.finishedChangingAllUsesOfReg();
3661 MI.eraseFromParent();
3662 }
3663
3664 return Legalized;
3665 }
3666}
3667
3669 MachineIRBuilder &B, Register Src, LLT Ty) {
3670 auto Unmerge = B.buildUnmerge(Ty, Src);
3671 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3672 Pieces.push_back(Unmerge.getReg(I));
3673}
3674
3675static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3676 MachineIRBuilder &MIRBuilder) {
3677 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3678 MachineFunction &MF = MIRBuilder.getMF();
3679 const DataLayout &DL = MIRBuilder.getDataLayout();
3680 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3681 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3682 LLT DstLLT = MRI.getType(DstReg);
3683
3684 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3685
3686 auto Addr = MIRBuilder.buildConstantPool(
3687 AddrPtrTy,
3688 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3689
3690 MachineMemOperand *MMO =
3692 MachineMemOperand::MOLoad, DstLLT, Alignment);
3693
3694 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3695}
3696
3699 const MachineOperand &ConstOperand = MI.getOperand(1);
3700 const Constant *ConstantVal = ConstOperand.getCImm();
3701
3702 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3703 MI.eraseFromParent();
3704
3705 return Legalized;
3706}
3707
3710 const MachineOperand &ConstOperand = MI.getOperand(1);
3711 const Constant *ConstantVal = ConstOperand.getFPImm();
3712
3713 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3714 MI.eraseFromParent();
3715
3716 return Legalized;
3717}
3718
3721 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3722 if (SrcTy.isVector()) {
3723 LLT SrcEltTy = SrcTy.getElementType();
3725
3726 if (DstTy.isVector()) {
3727 int NumDstElt = DstTy.getNumElements();
3728 int NumSrcElt = SrcTy.getNumElements();
3729
3730 LLT DstEltTy = DstTy.getElementType();
3731 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3732 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3733
3734 // If there's an element size mismatch, insert intermediate casts to match
3735 // the result element type.
3736 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3737 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3738 //
3739 // =>
3740 //
3741 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3742 // %3:_(<2 x s8>) = G_BITCAST %2
3743 // %4:_(<2 x s8>) = G_BITCAST %3
3744 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3745 DstCastTy = DstTy.changeVectorElementCount(
3746 ElementCount::getFixed(NumDstElt / NumSrcElt));
3747 SrcPartTy = SrcEltTy;
3748 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3749 //
3750 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3751 //
3752 // =>
3753 //
3754 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3755 // %3:_(s16) = G_BITCAST %2
3756 // %4:_(s16) = G_BITCAST %3
3757 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3758 SrcPartTy = SrcTy.changeVectorElementCount(
3759 ElementCount::getFixed(NumSrcElt / NumDstElt));
3760 DstCastTy = DstEltTy;
3761 }
3762
3763 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3764 for (Register &SrcReg : SrcRegs)
3765 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3766 } else
3767 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3768
3769 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3770 MI.eraseFromParent();
3771 return Legalized;
3772 }
3773
3774 if (DstTy.isVector()) {
3776 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3777 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3778 MI.eraseFromParent();
3779 return Legalized;
3780 }
3781
3782 return UnableToLegalize;
3783}
3784
3785/// Figure out the bit offset into a register when coercing a vector index for
3786/// the wide element type. This is only for the case when promoting vector to
3787/// one with larger elements.
3788//
3789///
3790/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3791/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3793 Register Idx,
3794 unsigned NewEltSize,
3795 unsigned OldEltSize) {
3796 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3797 LLT IdxTy = B.getMRI()->getType(Idx);
3798
3799 // Now figure out the amount we need to shift to get the target bits.
3800 auto OffsetMask = B.buildConstant(
3801 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3802 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3803 return B.buildShl(IdxTy, OffsetIdx,
3804 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3805}
3806
3807/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3808/// is casting to a vector with a smaller element size, perform multiple element
3809/// extracts and merge the results. If this is coercing to a vector with larger
3810/// elements, index the bitcasted vector and extract the target element with bit
3811/// operations. This is intended to force the indexing in the native register
3812/// size for architectures that can dynamically index the register file.
3815 LLT CastTy) {
3816 if (TypeIdx != 1)
3817 return UnableToLegalize;
3818
3819 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3820
3821 LLT SrcEltTy = SrcVecTy.getElementType();
3822 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3823 unsigned OldNumElts = SrcVecTy.getNumElements();
3824
3825 LLT NewEltTy = CastTy.getScalarType();
3826 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3827
3828 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3829 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3830 if (NewNumElts > OldNumElts) {
3831 // Decreasing the vector element size
3832 //
3833 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3834 // =>
3835 // v4i32:castx = bitcast x:v2i64
3836 //
3837 // i64 = bitcast
3838 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3839 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3840 //
3841 if (NewNumElts % OldNumElts != 0)
3842 return UnableToLegalize;
3843
3844 // Type of the intermediate result vector.
3845 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3846 LLT MidTy =
3847 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3848
3849 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3850
3851 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3852 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3853
3854 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3855 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3856 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3857 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3858 NewOps[I] = Elt.getReg(0);
3859 }
3860
3861 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3862 MIRBuilder.buildBitcast(Dst, NewVec);
3863 MI.eraseFromParent();
3864 return Legalized;
3865 }
3866
3867 if (NewNumElts < OldNumElts) {
3868 if (NewEltSize % OldEltSize != 0)
3869 return UnableToLegalize;
3870
3871 // This only depends on powers of 2 because we use bit tricks to figure out
3872 // the bit offset we need to shift to get the target element. A general
3873 // expansion could emit division/multiply.
3874 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3875 return UnableToLegalize;
3876
3877 // Increasing the vector element size.
3878 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3879 //
3880 // =>
3881 //
3882 // %cast = G_BITCAST %vec
3883 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3884 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3885 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3886 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3887 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3888 // %elt = G_TRUNC %elt_bits
3889
3890 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3891 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3892
3893 // Divide to get the index in the wider element type.
3894 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3895
3896 Register WideElt = CastVec;
3897 if (CastTy.isVector()) {
3898 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3899 ScaledIdx).getReg(0);
3900 }
3901
3902 // Compute the bit offset into the register of the target element.
3904 MIRBuilder, Idx, NewEltSize, OldEltSize);
3905
3906 // Shift the wide element to get the target element.
3907 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3908 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3909 MI.eraseFromParent();
3910 return Legalized;
3911 }
3912
3913 return UnableToLegalize;
3914}
3915
3916/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3917/// TargetReg, while preserving other bits in \p TargetReg.
3918///
3919/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3921 Register TargetReg, Register InsertReg,
3922 Register OffsetBits) {
3923 LLT TargetTy = B.getMRI()->getType(TargetReg);
3924 LLT InsertTy = B.getMRI()->getType(InsertReg);
3925 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3926 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3927
3928 // Produce a bitmask of the value to insert
3929 auto EltMask = B.buildConstant(
3930 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3931 InsertTy.getSizeInBits()));
3932 // Shift it into position
3933 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3934 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3935
3936 // Clear out the bits in the wide element
3937 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3938
3939 // The value to insert has all zeros already, so stick it into the masked
3940 // wide element.
3941 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3942}
3943
3944/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3945/// is increasing the element size, perform the indexing in the target element
3946/// type, and use bit operations to insert at the element position. This is
3947/// intended for architectures that can dynamically index the register file and
3948/// want to force indexing in the native register size.
3951 LLT CastTy) {
3952 if (TypeIdx != 0)
3953 return UnableToLegalize;
3954
3955 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3956 MI.getFirst4RegLLTs();
3957 LLT VecTy = DstTy;
3958
3959 LLT VecEltTy = VecTy.getElementType();
3960 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3961 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3962 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3963
3964 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3965 unsigned OldNumElts = VecTy.getNumElements();
3966
3967 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3968 if (NewNumElts < OldNumElts) {
3969 if (NewEltSize % OldEltSize != 0)
3970 return UnableToLegalize;
3971
3972 // This only depends on powers of 2 because we use bit tricks to figure out
3973 // the bit offset we need to shift to get the target element. A general
3974 // expansion could emit division/multiply.
3975 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3976 return UnableToLegalize;
3977
3978 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3979 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3980
3981 // Divide to get the index in the wider element type.
3982 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3983
3984 Register ExtractedElt = CastVec;
3985 if (CastTy.isVector()) {
3986 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3987 ScaledIdx).getReg(0);
3988 }
3989
3990 // Compute the bit offset into the register of the target element.
3992 MIRBuilder, Idx, NewEltSize, OldEltSize);
3993
3994 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
3995 Val, OffsetBits);
3996 if (CastTy.isVector()) {
3997 InsertedElt = MIRBuilder.buildInsertVectorElement(
3998 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
3999 }
4000
4001 MIRBuilder.buildBitcast(Dst, InsertedElt);
4002 MI.eraseFromParent();
4003 return Legalized;
4004 }
4005
4006 return UnableToLegalize;
4007}
4008
4009// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4010// those that have smaller than legal operands.
4011//
4012// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4013//
4014// ===>
4015//
4016// s32 = G_BITCAST <4 x s8>
4017// s32 = G_BITCAST <4 x s8>
4018// s32 = G_BITCAST <4 x s8>
4019// s32 = G_BITCAST <4 x s8>
4020// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4021// <16 x s8> = G_BITCAST <4 x s32>
4024 LLT CastTy) {
4025 // Convert it to CONCAT instruction
4026 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4027 if (!ConcatMI) {
4028 return UnableToLegalize;
4029 }
4030
4031 // Check if bitcast is Legal
4032 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4033 LLT SrcScalTy = CastTy.getScalarType();
4034
4035 // Check if the build vector is Legal
4036 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4037 return UnableToLegalize;
4038 }
4039
4040 // Bitcast the sources
4041 SmallVector<Register> BitcastRegs;
4042 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4043 BitcastRegs.push_back(
4044 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4045 .getReg(0));
4046 }
4047
4048 // Build the scalar values into a vector
4049 Register BuildReg =
4050 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4051 MIRBuilder.buildBitcast(DstReg, BuildReg);
4052
4053 MI.eraseFromParent();
4054 return Legalized;
4055}
4056
4057// This bitcasts a shuffle vector to a different type currently of the same
4058// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4059// will be used instead.
4060//
4061// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4062// ===>
4063// <4 x s64> = G_PTRTOINT <4 x p0>
4064// <4 x s64> = G_PTRTOINT <4 x p0>
4065// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4066// <16 x p0> = G_INTTOPTR <16 x s64>
4069 LLT CastTy) {
4070 auto ShuffleMI = cast<GShuffleVector>(&MI);
4071 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4072 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4073
4074 // We currently only handle vectors of the same size.
4075 if (TypeIdx != 0 ||
4076 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4077 CastTy.getElementCount() != DstTy.getElementCount())
4078 return UnableToLegalize;
4079
4080 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4081
4082 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4083 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4084 auto Shuf =
4085 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4086 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4087
4088 MI.eraseFromParent();
4089 return Legalized;
4090}
4091
4092/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4093///
4094/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4095///
4096/// ===>
4097///
4098/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4099/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4100/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4103 LLT CastTy) {
4104 auto ES = cast<GExtractSubvector>(&MI);
4105
4106 if (!CastTy.isVector())
4107 return UnableToLegalize;
4108
4109 if (TypeIdx != 0)
4110 return UnableToLegalize;
4111
4112 Register Dst = ES->getReg(0);
4113 Register Src = ES->getSrcVec();
4114 uint64_t Idx = ES->getIndexImm();
4115
4116 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4117
4118 LLT DstTy = MRI.getType(Dst);
4119 LLT SrcTy = MRI.getType(Src);
4120 ElementCount DstTyEC = DstTy.getElementCount();
4121 ElementCount SrcTyEC = SrcTy.getElementCount();
4122 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4123 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4124
4125 if (DstTy == CastTy)
4126 return Legalized;
4127
4128 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4129 return UnableToLegalize;
4130
4131 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4132 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4133 if (CastEltSize < DstEltSize)
4134 return UnableToLegalize;
4135
4136 auto AdjustAmt = CastEltSize / DstEltSize;
4137 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4138 SrcTyMinElts % AdjustAmt != 0)
4139 return UnableToLegalize;
4140
4141 Idx /= AdjustAmt;
4142 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4143 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4144 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4145 MIRBuilder.buildBitcast(Dst, PromotedES);
4146
4147 ES->eraseFromParent();
4148 return Legalized;
4149}
4150
4151/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4152///
4153/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4154/// <vscale x 8 x i1>,
4155/// N
4156///
4157/// ===>
4158///
4159/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4160/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4161/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4162/// <vscale x 1 x i8>, N / 8
4163/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4166 LLT CastTy) {
4167 auto ES = cast<GInsertSubvector>(&MI);
4168
4169 if (!CastTy.isVector())
4170 return UnableToLegalize;
4171
4172 if (TypeIdx != 0)
4173 return UnableToLegalize;
4174
4175 Register Dst = ES->getReg(0);
4176 Register BigVec = ES->getBigVec();
4177 Register SubVec = ES->getSubVec();
4178 uint64_t Idx = ES->getIndexImm();
4179
4180 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4181
4182 LLT DstTy = MRI.getType(Dst);
4183 LLT BigVecTy = MRI.getType(BigVec);
4184 LLT SubVecTy = MRI.getType(SubVec);
4185
4186 if (DstTy == CastTy)
4187 return Legalized;
4188
4189 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4190 return UnableToLegalize;
4191
4192 ElementCount DstTyEC = DstTy.getElementCount();
4193 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4194 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4195 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4196 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4197 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4198
4199 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4200 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4201 if (CastEltSize < DstEltSize)
4202 return UnableToLegalize;
4203
4204 auto AdjustAmt = CastEltSize / DstEltSize;
4205 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4206 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4207 return UnableToLegalize;
4208
4209 Idx /= AdjustAmt;
4210 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4211 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4212 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4213 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4214 auto PromotedIS =
4215 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4216 MIRBuilder.buildBitcast(Dst, PromotedIS);
4217
4218 ES->eraseFromParent();
4219 return Legalized;
4220}
4221
4223 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4224 Register DstReg = LoadMI.getDstReg();
4225 Register PtrReg = LoadMI.getPointerReg();
4226 LLT DstTy = MRI.getType(DstReg);
4227 MachineMemOperand &MMO = LoadMI.getMMO();
4228 LLT MemTy = MMO.getMemoryType();
4229 MachineFunction &MF = MIRBuilder.getMF();
4230
4231 LLT EltTy = MemTy.getScalarType();
4232
4233 unsigned MemSizeInBits = MemTy.getSizeInBits();
4234 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4235
4236 if (MemSizeInBits != MemStoreSizeInBits) {
4237 if (MemTy.isVector())
4238 return UnableToLegalize;
4239
4240 // Promote to a byte-sized load if not loading an integral number of
4241 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4242 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4243 MachineMemOperand *NewMMO =
4244 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4245
4246 Register LoadReg = DstReg;
4247 LLT LoadTy = DstTy;
4248
4249 // If this wasn't already an extending load, we need to widen the result
4250 // register to avoid creating a load with a narrower result than the source.
4251 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4252 LoadTy = WideMemTy;
4253 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4254 }
4255
4256 if (isa<GSExtLoad>(LoadMI)) {
4257 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4258 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4259 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4260 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4261 // The extra bits are guaranteed to be zero, since we stored them that
4262 // way. A zext load from Wide thus automatically gives zext from MemVT.
4263 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4264 } else {
4265 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4266 }
4267
4268 if (DstTy != LoadTy)
4269 MIRBuilder.buildTrunc(DstReg, LoadReg);
4270
4271 LoadMI.eraseFromParent();
4272 return Legalized;
4273 }
4274
4275 // Big endian lowering not implemented.
4276 if (MIRBuilder.getDataLayout().isBigEndian())
4277 return UnableToLegalize;
4278
4279 // This load needs splitting into power of 2 sized loads.
4280 //
4281 // Our strategy here is to generate anyextending loads for the smaller
4282 // types up to next power-2 result type, and then combine the two larger
4283 // result values together, before truncating back down to the non-pow-2
4284 // type.
4285 // E.g. v1 = i24 load =>
4286 // v2 = i32 zextload (2 byte)
4287 // v3 = i32 load (1 byte)
4288 // v4 = i32 shl v3, 16
4289 // v5 = i32 or v4, v2
4290 // v1 = i24 trunc v5
4291 // By doing this we generate the correct truncate which should get
4292 // combined away as an artifact with a matching extend.
4293
4294 uint64_t LargeSplitSize, SmallSplitSize;
4295
4296 if (!isPowerOf2_32(MemSizeInBits)) {
4297 // This load needs splitting into power of 2 sized loads.
4298 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4299 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4300 } else {
4301 // This is already a power of 2, but we still need to split this in half.
4302 //
4303 // Assume we're being asked to decompose an unaligned load.
4304 // TODO: If this requires multiple splits, handle them all at once.
4305 auto &Ctx = MF.getFunction().getContext();
4306 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4307 return UnableToLegalize;
4308
4309 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4310 }
4311
4312 if (MemTy.isVector()) {
4313 // TODO: Handle vector extloads
4314 if (MemTy != DstTy)
4315 return UnableToLegalize;
4316
4317 Align Alignment = LoadMI.getAlign();
4318 // Given an alignment larger than the size of the memory, we can increase
4319 // the size of the load without needing to scalarize it.
4320 if (Alignment.value() * 8 > MemSizeInBits &&
4322 LLT MoreTy = DstTy.changeVectorElementCount(
4324 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4325 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4326 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4327 NewLoad.getReg(0));
4328 LoadMI.eraseFromParent();
4329 return Legalized;
4330 }
4331
4332 // TODO: We can do better than scalarizing the vector and at least split it
4333 // in half.
4334 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4335 }
4336
4337 MachineMemOperand *LargeMMO =
4338 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4339 MachineMemOperand *SmallMMO =
4340 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4341
4342 LLT PtrTy = MRI.getType(PtrReg);
4343 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4344
4345 LLT AnyExtTy;
4346 LLT OffsetCstRes;
4347 if (EltTy.isPointer()) {
4348 AnyExtTy = LLT::scalar(AnyExtSize);
4349 OffsetCstRes = LLT::scalar(PtrTy.getSizeInBits());
4350 } else {
4351 AnyExtTy = DstTy.changeElementSize(AnyExtSize);
4352 OffsetCstRes = DstTy.changeElementSize(PtrTy.getSizeInBits());
4353 }
4354
4355 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4356 PtrReg, *LargeMMO);
4357
4358 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4359 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4360 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4361 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4362 SmallPtr, *SmallMMO);
4363
4364 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4365 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4366
4367 if (AnyExtTy == DstTy)
4368 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4369 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4370 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4371 MIRBuilder.buildTrunc(DstReg, {Or});
4372 } else {
4373 assert(DstTy.isPointer() && "expected pointer");
4374 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4375
4376 // FIXME: We currently consider this to be illegal for non-integral address
4377 // spaces, but we need still need a way to reinterpret the bits.
4378 MIRBuilder.buildIntToPtr(DstReg, Or);
4379 }
4380
4381 LoadMI.eraseFromParent();
4382 return Legalized;
4383}
4384
4386 // Lower a non-power of 2 store into multiple pow-2 stores.
4387 // E.g. split an i24 store into an i16 store + i8 store.
4388 // We do this by first extending the stored value to the next largest power
4389 // of 2 type, and then using truncating stores to store the components.
4390 // By doing this, likewise with G_LOAD, generate an extend that can be
4391 // artifact-combined away instead of leaving behind extracts.
4392 Register SrcReg = StoreMI.getValueReg();
4393 Register PtrReg = StoreMI.getPointerReg();
4394 LLT SrcTy = MRI.getType(SrcReg);
4395 MachineFunction &MF = MIRBuilder.getMF();
4396 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4397 LLT MemTy = MMO.getMemoryType();
4398
4399 unsigned StoreWidth = MemTy.getSizeInBits();
4400 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4401
4402 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4403 // Promote to a byte-sized store with upper bits zero if not
4404 // storing an integral number of bytes. For example, promote
4405 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4406 LLT WideTy = LLT::integer(StoreSizeInBits);
4407
4408 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4409 // Avoid creating a store with a narrower source than result.
4410 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4411 SrcTy = WideTy;
4412 }
4413
4414 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4415
4416 MachineMemOperand *NewMMO =
4417 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4418 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4419 StoreMI.eraseFromParent();
4420 return Legalized;
4421 }
4422
4423 if (MemTy.isVector()) {
4424 if (MemTy != SrcTy)
4425 return scalarizeVectorBooleanStore(StoreMI);
4426
4427 // TODO: We can do better than scalarizing the vector and at least split it
4428 // in half.
4429 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4430 }
4431
4432 unsigned MemSizeInBits = MemTy.getSizeInBits();
4433 uint64_t LargeSplitSize, SmallSplitSize;
4434
4435 if (!isPowerOf2_32(MemSizeInBits)) {
4436 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4437 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4438 } else {
4439 auto &Ctx = MF.getFunction().getContext();
4440 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4441 return UnableToLegalize; // Don't know what we're being asked to do.
4442
4443 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4444 }
4445
4446 // Extend to the next pow-2. If this store was itself the result of lowering,
4447 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4448 // that's wider than the stored size.
4449 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4450 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4451
4452 if (SrcTy.isPointer()) {
4453 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4454 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4455 }
4456
4457 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4458
4459 // Obtain the smaller value by shifting away the larger value.
4460 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4461 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4462
4463 // Generate the PtrAdd and truncating stores.
4464 LLT PtrTy = MRI.getType(PtrReg);
4465 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4466 LargeSplitSize / 8);
4467 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4468
4469 MachineMemOperand *LargeMMO =
4470 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4471 MachineMemOperand *SmallMMO =
4472 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4473 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4474 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4475 StoreMI.eraseFromParent();
4476 return Legalized;
4477}
4478
4481 Register SrcReg = StoreMI.getValueReg();
4482 Register PtrReg = StoreMI.getPointerReg();
4483 LLT SrcTy = MRI.getType(SrcReg);
4484 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4485 LLT MemTy = MMO.getMemoryType();
4486 LLT MemScalarTy = MemTy.getElementType();
4487 MachineFunction &MF = MIRBuilder.getMF();
4488
4489 assert(SrcTy.isVector() && "Expect a vector store type");
4490
4491 if (!MemScalarTy.isByteSized()) {
4492 // We need to build an integer scalar of the vector bit pattern.
4493 // It's not legal for us to add padding when storing a vector.
4494 unsigned NumBits = MemTy.getSizeInBits();
4495 LLT IntTy = LLT::integer(NumBits);
4496 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4497 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4498
4499 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4500 auto Elt = MIRBuilder.buildExtractVectorElement(
4501 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4502 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4503 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4504 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4505 ? (MemTy.getNumElements() - 1) - I
4506 : I;
4507 auto ShiftAmt = MIRBuilder.buildConstant(
4508 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4509 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4510 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4511 }
4512 auto PtrInfo = MMO.getPointerInfo();
4513 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4514 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4515 StoreMI.eraseFromParent();
4516 return Legalized;
4517 }
4518
4519 // TODO: implement simple scalarization.
4520 return UnableToLegalize;
4521}
4522
4524LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4525 switch (MI.getOpcode()) {
4526 case TargetOpcode::G_LOAD: {
4527 if (TypeIdx != 0)
4528 return UnableToLegalize;
4529 MachineMemOperand &MMO = **MI.memoperands_begin();
4530
4531 // Not sure how to interpret a bitcast of an extending load.
4532 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4533 return UnableToLegalize;
4534
4535 Observer.changingInstr(MI);
4536 bitcastDst(MI, CastTy, 0);
4537 MMO.setType(CastTy);
4538 // The range metadata is no longer valid when reinterpreted as a different
4539 // type.
4540 MMO.clearRanges();
4541 Observer.changedInstr(MI);
4542 return Legalized;
4543 }
4544 case TargetOpcode::G_STORE: {
4545 if (TypeIdx != 0)
4546 return UnableToLegalize;
4547
4548 MachineMemOperand &MMO = **MI.memoperands_begin();
4549
4550 // Not sure how to interpret a bitcast of a truncating store.
4551 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4552 return UnableToLegalize;
4553
4554 Observer.changingInstr(MI);
4555 bitcastSrc(MI, CastTy, 0);
4556 MMO.setType(CastTy);
4557 Observer.changedInstr(MI);
4558 return Legalized;
4559 }
4560 case TargetOpcode::G_SELECT: {
4561 if (TypeIdx != 0)
4562 return UnableToLegalize;
4563
4564 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4565 LLVM_DEBUG(
4566 dbgs() << "bitcast action not implemented for vector select\n");
4567 return UnableToLegalize;
4568 }
4569
4570 Observer.changingInstr(MI);
4571 bitcastSrc(MI, CastTy, 2);
4572 bitcastSrc(MI, CastTy, 3);
4573 bitcastDst(MI, CastTy, 0);
4574 Observer.changedInstr(MI);
4575 return Legalized;
4576 }
4577 case TargetOpcode::G_AND:
4578 case TargetOpcode::G_OR:
4579 case TargetOpcode::G_XOR: {
4580 Observer.changingInstr(MI);
4581 bitcastSrc(MI, CastTy, 1);
4582 bitcastSrc(MI, CastTy, 2);
4583 bitcastDst(MI, CastTy, 0);
4584 Observer.changedInstr(MI);
4585 return Legalized;
4586 }
4587 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4588 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4589 case TargetOpcode::G_INSERT_VECTOR_ELT:
4590 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4591 case TargetOpcode::G_CONCAT_VECTORS:
4592 return bitcastConcatVector(MI, TypeIdx, CastTy);
4593 case TargetOpcode::G_SHUFFLE_VECTOR:
4594 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4595 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4596 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4597 case TargetOpcode::G_INSERT_SUBVECTOR:
4598 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4599 default:
4600 return UnableToLegalize;
4601 }
4602}
4603
4604// Legalize an instruction by changing the opcode in place.
4605void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4607 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4609}
4610
4612LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4613 using namespace TargetOpcode;
4614 switch(MI.getOpcode()) {
4615 default:
4616 return UnableToLegalize;
4617 case TargetOpcode::G_FCONSTANT:
4618 return lowerFConstant(MI);
4619 case TargetOpcode::G_BITCAST:
4620 return lowerBitcast(MI);
4621 case TargetOpcode::G_SREM:
4622 case TargetOpcode::G_UREM: {
4623 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4624 auto Quot =
4625 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4626 {MI.getOperand(1), MI.getOperand(2)});
4627
4628 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4629 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4630 MI.eraseFromParent();
4631 return Legalized;
4632 }
4633 case TargetOpcode::G_SADDO:
4634 case TargetOpcode::G_SSUBO:
4635 return lowerSADDO_SSUBO(MI);
4636 case TargetOpcode::G_SADDE:
4637 return lowerSADDE(MI);
4638 case TargetOpcode::G_SSUBE:
4639 return lowerSSUBE(MI);
4640 case TargetOpcode::G_UMULH:
4641 case TargetOpcode::G_SMULH:
4642 return lowerSMULH_UMULH(MI);
4643 case TargetOpcode::G_SMULO:
4644 case TargetOpcode::G_UMULO: {
4645 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4646 // result.
4647 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4648 LLT Ty = MRI.getType(Res);
4649
4650 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4651 ? TargetOpcode::G_SMULH
4652 : TargetOpcode::G_UMULH;
4653
4654 Observer.changingInstr(MI);
4655 const auto &TII = MIRBuilder.getTII();
4656 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4657 MI.removeOperand(1);
4658 Observer.changedInstr(MI);
4659
4660 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4661 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4662
4663 // Move insert point forward so we can use the Res register if needed.
4664 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4665
4666 // For *signed* multiply, overflow is detected by checking:
4667 // (hi != (lo >> bitwidth-1))
4668 if (Opcode == TargetOpcode::G_SMULH) {
4669 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4670 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4671 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4672 } else {
4673 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4674 }
4675 return Legalized;
4676 }
4677 case TargetOpcode::G_FNEG: {
4678 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4679 LLT TyInt =
4680 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4681 Register CastedSubByReg = SubByReg;
4682
4683 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4684 !SubByRegTy.getScalarType().isInteger()) {
4685 auto BitcastDst = SubByRegTy.changeElementType(
4686 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4687 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4688 }
4689
4690 auto SignMask = MIRBuilder.buildConstant(
4691 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4692
4693 if (ResTy != TyInt) {
4694 Register NewDst =
4695 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4696 MIRBuilder.buildBitcast(Res, NewDst);
4697 } else
4698 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4699
4700 MI.eraseFromParent();
4701 return Legalized;
4702 }
4703 case TargetOpcode::G_FSUB:
4704 case TargetOpcode::G_STRICT_FSUB: {
4705 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4706 LLT Ty = MRI.getType(Res);
4707
4708 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4709 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4710
4711 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4712 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4713 else
4714 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4715
4716 MI.eraseFromParent();
4717 return Legalized;
4718 }
4719 case TargetOpcode::G_FMAD:
4720 return lowerFMad(MI);
4721 case TargetOpcode::G_FFLOOR:
4722 return lowerFFloor(MI);
4723 case TargetOpcode::G_LROUND:
4724 case TargetOpcode::G_LLROUND: {
4725 Register DstReg = MI.getOperand(0).getReg();
4726 Register SrcReg = MI.getOperand(1).getReg();
4727 LLT SrcTy = MRI.getType(SrcReg);
4728 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4729 {SrcReg});
4730 MIRBuilder.buildFPTOSI(DstReg, Round);
4731 MI.eraseFromParent();
4732 return Legalized;
4733 }
4734 case TargetOpcode::G_INTRINSIC_ROUND:
4735 return lowerIntrinsicRound(MI);
4736 case TargetOpcode::G_FRINT: {
4737 // Since round even is the assumed rounding mode for unconstrained FP
4738 // operations, rint and roundeven are the same operation.
4739 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4740 return Legalized;
4741 }
4742 case TargetOpcode::G_INTRINSIC_LRINT:
4743 case TargetOpcode::G_INTRINSIC_LLRINT: {
4744 Register DstReg = MI.getOperand(0).getReg();
4745 Register SrcReg = MI.getOperand(1).getReg();
4746 LLT SrcTy = MRI.getType(SrcReg);
4747 auto Round =
4748 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4749 MIRBuilder.buildFPTOSI(DstReg, Round);
4750 MI.eraseFromParent();
4751 return Legalized;
4752 }
4753 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4754 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4755 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4756 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4757 **MI.memoperands_begin());
4758 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4759 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4760 MI.eraseFromParent();
4761 return Legalized;
4762 }
4763 case TargetOpcode::G_LOAD:
4764 case TargetOpcode::G_SEXTLOAD:
4765 case TargetOpcode::G_ZEXTLOAD:
4766 return lowerLoad(cast<GAnyLoad>(MI));
4767 case TargetOpcode::G_STORE:
4768 return lowerStore(cast<GStore>(MI));
4769 case TargetOpcode::G_CTLZ_ZERO_POISON:
4770 case TargetOpcode::G_CTTZ_ZERO_POISON:
4771 case TargetOpcode::G_CTLZ:
4772 case TargetOpcode::G_CTTZ:
4773 case TargetOpcode::G_CTPOP:
4774 case TargetOpcode::G_CTLS:
4775 return lowerBitCount(MI);
4776 case G_UADDO: {
4777 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4778
4779 Register NewRes = MRI.cloneVirtualRegister(Res);
4780
4781 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4782 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4783
4784 MIRBuilder.buildCopy(Res, NewRes);
4785
4786 MI.eraseFromParent();
4787 return Legalized;
4788 }
4789 case G_UADDE: {
4790 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4791 const LLT CondTy = MRI.getType(CarryOut);
4792 const LLT Ty = MRI.getType(Res);
4793
4794 Register NewRes = MRI.cloneVirtualRegister(Res);
4795
4796 // Initial add of the two operands.
4797 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4798
4799 // Initial check for carry.
4800 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4801
4802 // Add the sum and the carry.
4803 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4804 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4805
4806 // Second check for carry. We can only carry if the initial sum is all 1s
4807 // and the carry is set, resulting in a new sum of 0.
4808 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4809 auto ResEqZero =
4810 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4811 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4812 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4813
4814 MIRBuilder.buildCopy(Res, NewRes);
4815
4816 MI.eraseFromParent();
4817 return Legalized;
4818 }
4819 case G_USUBO: {
4820 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4821
4822 MIRBuilder.buildSub(Res, LHS, RHS);
4823 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4824
4825 MI.eraseFromParent();
4826 return Legalized;
4827 }
4828 case G_USUBE: {
4829 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4830 const LLT CondTy = MRI.getType(BorrowOut);
4831 const LLT Ty = MRI.getType(Res);
4832
4833 // Initial subtract of the two operands.
4834 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4835
4836 // Initial check for borrow.
4837 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4838
4839 // Subtract the borrow from the first subtract.
4840 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4841 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4842
4843 // Second check for borrow. We can only borrow if the initial difference is
4844 // 0 and the borrow is set, resulting in a new difference of all 1s.
4845 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4846 auto TmpResEqZero =
4847 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4848 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4849 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4850
4851 MI.eraseFromParent();
4852 return Legalized;
4853 }
4854 case G_UITOFP:
4855 return lowerUITOFP(MI);
4856 case G_SITOFP:
4857 return lowerSITOFP(MI);
4858 case G_FPTOUI:
4859 return lowerFPTOUI(MI);
4860 case G_FPTOSI:
4861 return lowerFPTOSI(MI);
4862 case G_FPTOUI_SAT:
4863 case G_FPTOSI_SAT:
4864 return lowerFPTOINT_SAT(MI);
4865 case G_FPEXT:
4866 return lowerFPEXT(MI);
4867 case G_FPTRUNC:
4868 return lowerFPTRUNC(MI);
4869 case G_FPOWI:
4870 return lowerFPOWI(MI);
4871 case G_FMODF:
4872 return lowerFMODF(MI);
4873 case G_SMIN:
4874 case G_SMAX:
4875 case G_UMIN:
4876 case G_UMAX:
4877 return lowerMinMax(MI);
4878 case G_SCMP:
4879 case G_UCMP:
4880 return lowerThreewayCompare(MI);
4881 case G_FCOPYSIGN:
4882 return lowerFCopySign(MI);
4883 case G_FMINNUM:
4884 case G_FMAXNUM:
4885 case G_FMINIMUMNUM:
4886 case G_FMAXIMUMNUM:
4887 return lowerFMinNumMaxNum(MI);
4888 case G_FMINIMUM:
4889 case G_FMAXIMUM:
4890 return lowerFMinimumMaximum(MI);
4891 case G_MERGE_VALUES:
4892 return lowerMergeValues(MI);
4893 case G_UNMERGE_VALUES:
4894 return lowerUnmergeValues(MI);
4895 case TargetOpcode::G_SEXT_INREG: {
4896 assert(MI.getOperand(2).isImm() && "Expected immediate");
4897 int64_t SizeInBits = MI.getOperand(2).getImm();
4898
4899 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4900 LLT DstTy = MRI.getType(DstReg);
4901 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4902
4903 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4904 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4905 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4906 MI.eraseFromParent();
4907 return Legalized;
4908 }
4909 case G_EXTRACT_VECTOR_ELT:
4910 case G_INSERT_VECTOR_ELT:
4912 case G_SHUFFLE_VECTOR:
4913 return lowerShuffleVector(MI);
4914 case G_VECTOR_COMPRESS:
4915 return lowerVECTOR_COMPRESS(MI);
4916 case G_DYN_STACKALLOC:
4917 return lowerDynStackAlloc(MI);
4918 case G_INSERT_SUBVECTOR: {
4919 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
4920 MRI.getType(MI.getOperand(2).getReg()).isScalable())
4921 return UnableToLegalize;
4922
4923 // Check that subvector is half size of main vector
4924 Register Vector = MI.getOperand(1).getReg();
4925 Register Subvector = MI.getOperand(2).getReg();
4926 auto InsertionPointImm = MI.getOperand(3).getImm();
4927
4928 LLT VectorTy = MRI.getType(Vector);
4929 LLT SubvectorTy = MRI.getType(Subvector);
4930 // If so, -> concat(subvector, extract(half of vector))
4931 // (Operands can be either way round depending on insertion point
4932 if (VectorTy.getSizeInBits() == SubvectorTy.getSizeInBits() * 2) {
4933 bool InsertInLowHalf = InsertionPointImm == 0;
4934 auto Extract = MIRBuilder.buildExtractSubvector(
4935 SubvectorTy, Vector,
4936 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
4937
4938 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
4939 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
4940
4941 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
4942 {LowHalf, HighHalf});
4943 MI.eraseFromParent();
4944 return Legalized;
4945 }
4946 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
4947 else {
4948 // Extend subvector to same size as vector
4949 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
4950 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
4951
4952 // Calculate mask required for this shuffle
4953 SmallVector<int> Mask;
4954 for (int i = 0; i < VectorTy.getNumElements(); i++) {
4955 // If this index is within bounds, put subvector's index into mask
4956 if (i >= InsertionPointImm &&
4957 i < InsertionPointImm + SubvectorTy.getNumElements())
4958 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
4959 else
4960 Mask.push_back(i);
4961 }
4962
4963 // Build shuffle
4964 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
4965 Mask);
4966 MI.eraseFromParent();
4967 return Legalized;
4968 }
4969 }
4970 case G_STACKSAVE:
4971 return lowerStackSave(MI);
4972 case G_STACKRESTORE:
4973 return lowerStackRestore(MI);
4974 case G_EXTRACT:
4975 return lowerExtract(MI);
4976 case G_INSERT:
4977 return lowerInsert(MI);
4978 case G_BSWAP:
4979 return lowerBswap(MI);
4980 case G_BITREVERSE:
4981 return lowerBitreverse(MI);
4982 case G_READ_REGISTER:
4983 case G_WRITE_REGISTER:
4984 return lowerReadWriteRegister(MI);
4985 case G_UADDSAT:
4986 case G_USUBSAT: {
4987 // Try to make a reasonable guess about which lowering strategy to use. The
4988 // target can override this with custom lowering and calling the
4989 // implementation functions.
4990 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4991 if (LI.isLegalOrCustom({G_UMIN, Ty}))
4992 return lowerAddSubSatToMinMax(MI);
4994 }
4995 case G_SADDSAT:
4996 case G_SSUBSAT: {
4997 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4998
4999 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5000 // since it's a shorter expansion. However, we would need to figure out the
5001 // preferred boolean type for the carry out for the query.
5002 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5003 return lowerAddSubSatToMinMax(MI);
5005 }
5006 case G_SSHLSAT:
5007 case G_USHLSAT:
5008 return lowerShlSat(MI);
5009 case G_ABS:
5010 return lowerAbsToAddXor(MI);
5011 case G_ABDS:
5012 case G_ABDU: {
5013 bool IsSigned = MI.getOpcode() == G_ABDS;
5014 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5015 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5016 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5017 return lowerAbsDiffToMinMax(MI);
5018 }
5019 return lowerAbsDiffToSelect(MI);
5020 }
5021 case G_FABS:
5022 return lowerFAbs(MI);
5023 case G_SELECT:
5024 return lowerSelect(MI);
5025 case G_IS_FPCLASS:
5026 return lowerISFPCLASS(MI);
5027 case G_SDIVREM:
5028 case G_UDIVREM:
5029 return lowerDIVREM(MI);
5030 case G_FSHL:
5031 case G_FSHR:
5032 return lowerFunnelShift(MI);
5033 case G_ROTL:
5034 case G_ROTR:
5035 return lowerRotate(MI);
5036 case G_MEMSET:
5037 case G_MEMCPY:
5038 case G_MEMMOVE:
5039 case G_MEMCPY_INLINE:
5040 case G_MEMSET_INLINE:
5041 return lowerMemCpyFamily(MI);
5042 case G_ZEXT:
5043 case G_SEXT:
5044 case G_ANYEXT:
5045 return lowerEXT(MI);
5046 case G_TRUNC:
5047 return lowerTRUNC(MI);
5049 return lowerVectorReduction(MI);
5050 case G_VAARG:
5051 return lowerVAArg(MI);
5052 case G_ATOMICRMW_SUB: {
5053 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5054 const LLT ValTy = MRI.getType(Val);
5055 MachineMemOperand *MMO = *MI.memoperands_begin();
5056
5057 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5058 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5059 MI.eraseFromParent();
5060 return Legalized;
5061 }
5062 case G_SMULFIX:
5063 case G_UMULFIX:
5064 return lowerMulfix(MI);
5065 }
5066}
5067
5069 Align MinAlign) const {
5070 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5071 // datalayout for the preferred alignment. Also there should be a target hook
5072 // for this to allow targets to reduce the alignment and ignore the
5073 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5074 // the type.
5075 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5076}
5077
5080 MachinePointerInfo &PtrInfo) {
5081 MachineFunction &MF = MIRBuilder.getMF();
5082 const DataLayout &DL = MIRBuilder.getDataLayout();
5083 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5084
5085 unsigned AddrSpace = DL.getAllocaAddrSpace();
5086 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5087
5088 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5089 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5090}
5091
5093 const SrcOp &Val) {
5094 LLT SrcTy = Val.getLLTTy(MRI);
5095 Align StackTypeAlign =
5096 std::max(getStackTemporaryAlignment(SrcTy),
5098 MachinePointerInfo PtrInfo;
5099 auto StackTemp =
5100 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5101
5102 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5103 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5104}
5105
5107 LLT VecTy) {
5108 LLT IdxTy = B.getMRI()->getType(IdxReg);
5109 unsigned NElts = VecTy.getNumElements();
5110
5111 int64_t IdxVal;
5112 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5113 if (IdxVal < VecTy.getNumElements())
5114 return IdxReg;
5115 // If a constant index would be out of bounds, clamp it as well.
5116 }
5117
5118 if (isPowerOf2_32(NElts)) {
5119 APInt Imm = APInt::getLowBitsSet(IdxTy.getSizeInBits(), Log2_32(NElts));
5120 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5121 }
5122
5123 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5124 .getReg(0);
5125}
5126
5128 Register Index) {
5129 LLT EltTy = VecTy.getElementType();
5130
5131 // Calculate the element offset and add it to the pointer.
5132 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5133 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5134 "Converting bits to bytes lost precision");
5135
5136 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5137
5138 // Convert index to the correct size for the address space.
5139 const DataLayout &DL = MIRBuilder.getDataLayout();
5140 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5141 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5142 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5143 if (IdxTy != MRI.getType(Index))
5144 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5145
5146 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5147 MIRBuilder.buildConstant(IdxTy, EltSize));
5148
5149 LLT PtrTy = MRI.getType(VecPtr);
5150 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5151}
5152
5153#ifndef NDEBUG
5154/// Check that all vector operands have same number of elements. Other operands
5155/// should be listed in NonVecOp.
5158 std::initializer_list<unsigned> NonVecOpIndices) {
5159 if (MI.getNumMemOperands() != 0)
5160 return false;
5161
5162 LLT VecTy = MRI.getType(MI.getReg(0));
5163 if (!VecTy.isVector())
5164 return false;
5165 unsigned NumElts = VecTy.getNumElements();
5166
5167 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5168 MachineOperand &Op = MI.getOperand(OpIdx);
5169 if (!Op.isReg()) {
5170 if (!is_contained(NonVecOpIndices, OpIdx))
5171 return false;
5172 continue;
5173 }
5174
5175 LLT Ty = MRI.getType(Op.getReg());
5176 if (!Ty.isVector()) {
5177 if (!is_contained(NonVecOpIndices, OpIdx))
5178 return false;
5179 continue;
5180 }
5181
5182 if (Ty.getNumElements() != NumElts)
5183 return false;
5184 }
5185
5186 return true;
5187}
5188#endif
5189
5190/// Fill \p DstOps with DstOps that have same number of elements combined as
5191/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5192/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5193/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5194static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5195 unsigned NumElts) {
5196 LLT LeftoverTy;
5197 assert(Ty.isVector() && "Expected vector type");
5198 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5199 int NumParts, NumLeftover;
5200 std::tie(NumParts, NumLeftover) =
5201 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5202
5203 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5204 for (int i = 0; i < NumParts; ++i) {
5205 DstOps.push_back(NarrowTy);
5206 }
5207
5208 if (LeftoverTy.isValid()) {
5209 assert(NumLeftover == 1 && "expected exactly one leftover");
5210 DstOps.push_back(LeftoverTy);
5211 }
5212}
5213
5214/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5215/// made from \p Op depending on operand type.
5217 MachineOperand &Op) {
5218 for (unsigned i = 0; i < N; ++i) {
5219 if (Op.isReg())
5220 Ops.push_back(Op.getReg());
5221 else if (Op.isImm())
5222 Ops.push_back(Op.getImm());
5223 else if (Op.isPredicate())
5224 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5225 else
5226 llvm_unreachable("Unsupported type");
5227 }
5228}
5229
5230// Handle splitting vector operations which need to have the same number of
5231// elements in each type index, but each type index may have a different element
5232// type.
5233//
5234// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5235// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5236// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5237//
5238// Also handles some irregular breakdown cases, e.g.
5239// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5240// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5241// s64 = G_SHL s64, s32
5244 GenericMachineInstr &MI, unsigned NumElts,
5245 std::initializer_list<unsigned> NonVecOpIndices) {
5246 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5247 "Non-compatible opcode or not specified non-vector operands");
5248 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5249
5250 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5251 unsigned NumDefs = MI.getNumDefs();
5252
5253 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5254 // Build instructions with DstOps to use instruction found by CSE directly.
5255 // CSE copies found instruction into given vreg when building with vreg dest.
5256 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5257 // Output registers will be taken from created instructions.
5258 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5259 for (unsigned i = 0; i < NumDefs; ++i) {
5260 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5261 }
5262
5263 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5264 // Operands listed in NonVecOpIndices will be used as is without splitting;
5265 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5266 // scalar condition (op 1), immediate in sext_inreg (op 2).
5267 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5268 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5269 ++UseIdx, ++UseNo) {
5270 if (is_contained(NonVecOpIndices, UseIdx)) {
5271 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5272 MI.getOperand(UseIdx));
5273 } else {
5274 SmallVector<Register, 8> SplitPieces;
5275 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5276 MRI);
5277 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5278 }
5279 }
5280
5281 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5282
5283 // Take i-th piece of each input operand split and build sub-vector/scalar
5284 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5285 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5287 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5288 Defs.push_back(OutputOpsPieces[DstNo][i]);
5289
5291 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5292 Uses.push_back(InputOpsPieces[InputNo][i]);
5293
5294 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5295 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5296 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5297 }
5298
5299 // Merge small outputs into MI's output for each def operand.
5300 if (NumLeftovers) {
5301 for (unsigned i = 0; i < NumDefs; ++i)
5302 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5303 } else {
5304 for (unsigned i = 0; i < NumDefs; ++i)
5305 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5306 }
5307
5308 MI.eraseFromParent();
5309 return Legalized;
5310}
5311
5314 unsigned NumElts) {
5315 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5316
5317 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5318 unsigned NumDefs = MI.getNumDefs();
5319
5320 SmallVector<DstOp, 8> OutputOpsPieces;
5321 SmallVector<Register, 8> OutputRegs;
5322 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5323
5324 // Instructions that perform register split will be inserted in basic block
5325 // where register is defined (basic block is in the next operand).
5326 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5327 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5328 UseIdx += 2, ++UseNo) {
5329 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5330 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5331 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5332 MIRBuilder, MRI);
5333 }
5334
5335 // Build PHIs with fewer elements.
5336 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5337 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5338 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5339 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5340 Phi.addDef(
5341 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5342 OutputRegs.push_back(Phi.getReg(0));
5343
5344 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5345 Phi.addUse(InputOpsPieces[j][i]);
5346 Phi.add(MI.getOperand(1 + j * 2 + 1));
5347 }
5348 }
5349
5350 // Set the insert point after the existing PHIs
5351 MachineBasicBlock &MBB = *MI.getParent();
5352 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5353
5354 // Merge small outputs into MI's def.
5355 if (NumLeftovers) {
5356 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5357 } else {
5358 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5359 }
5360
5361 MI.eraseFromParent();
5362 return Legalized;
5363}
5364
5367 unsigned TypeIdx,
5368 LLT NarrowTy) {
5369 const int NumDst = MI.getNumOperands() - 1;
5370 const Register SrcReg = MI.getOperand(NumDst).getReg();
5371 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5372 LLT SrcTy = MRI.getType(SrcReg);
5373
5374 if (TypeIdx != 1 || NarrowTy == DstTy)
5375 return UnableToLegalize;
5376
5377 // Requires compatible types. Otherwise SrcReg should have been defined by
5378 // merge-like instruction that would get artifact combined. Most likely
5379 // instruction that defines SrcReg has to perform more/fewer elements
5380 // legalization compatible with NarrowTy.
5381 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5382 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5383
5384 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5385 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5386 return UnableToLegalize;
5387
5388 // This is most likely DstTy (smaller then register size) packed in SrcTy
5389 // (larger then register size) and since unmerge was not combined it will be
5390 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5391 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5392
5393 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5394 //
5395 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5396 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5397 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5398 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5399 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5400 const int PartsPerUnmerge = NumDst / NumUnmerge;
5401
5402 for (int I = 0; I != NumUnmerge; ++I) {
5403 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5404
5405 for (int J = 0; J != PartsPerUnmerge; ++J)
5406 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5407 MIB.addUse(Unmerge.getReg(I));
5408 }
5409
5410 MI.eraseFromParent();
5411 return Legalized;
5412}
5413
5416 LLT NarrowTy) {
5417 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5418 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5419 // that should have been artifact combined. Most likely instruction that uses
5420 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5421 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5422 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5423 if (NarrowTy == SrcTy)
5424 return UnableToLegalize;
5425
5426 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5427 // is for old mir tests. Since the changes to more/fewer elements it should no
5428 // longer be possible to generate MIR like this when starting from llvm-ir
5429 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5430 if (TypeIdx == 1) {
5431 assert(SrcTy.isVector() && "Expected vector types");
5432 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5433 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5434 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5435 return UnableToLegalize;
5436 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5437 //
5438 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5439 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5440 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5441 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5442 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5443 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5444
5446 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5447 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5448 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5449 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5450 Elts.push_back(Unmerge.getReg(j));
5451 }
5452
5453 SmallVector<Register, 8> NarrowTyElts;
5454 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5455 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5456 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5457 ++i, Offset += NumNarrowTyElts) {
5458 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5459 NarrowTyElts.push_back(
5460 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5461 }
5462
5463 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5464 MI.eraseFromParent();
5465 return Legalized;
5466 }
5467
5468 assert(TypeIdx == 0 && "Bad type index");
5469 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5470 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5471 return UnableToLegalize;
5472
5473 // This is most likely SrcTy (smaller then register size) packed in DstTy
5474 // (larger then register size) and since merge was not combined it will be
5475 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5476 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5477
5478 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5479 //
5480 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5481 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5482 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5483 SmallVector<Register, 8> NarrowTyElts;
5484 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5485 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5486 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5487 for (unsigned i = 0; i < NumParts; ++i) {
5489 for (unsigned j = 0; j < NumElts; ++j)
5490 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5491 NarrowTyElts.push_back(
5492 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5493 }
5494
5495 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5496 MI.eraseFromParent();
5497 return Legalized;
5498}
5499
5502 unsigned TypeIdx,
5503 LLT NarrowVecTy) {
5504 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5505 Register InsertVal;
5506 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5507
5508 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5509 if (IsInsert)
5510 InsertVal = MI.getOperand(2).getReg();
5511
5512 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5513 LLT VecTy = MRI.getType(SrcVec);
5514
5515 // If the index is a constant, we can really break this down as you would
5516 // expect, and index into the target size pieces.
5517 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5518 if (MaybeCst) {
5519 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5520 // Avoid out of bounds indexing the pieces.
5521 if (IdxVal >= VecTy.getNumElements()) {
5522 MIRBuilder.buildUndef(DstReg);
5523 MI.eraseFromParent();
5524 return Legalized;
5525 }
5526
5527 if (!NarrowVecTy.isVector()) {
5528 SmallVector<Register, 8> SplitPieces;
5529 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5530 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5531 if (IsInsert) {
5532 SplitPieces[IdxVal] = InsertVal;
5533 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5534 } else {
5535 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5536 }
5537 } else {
5538 SmallVector<Register, 8> VecParts;
5539 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5540
5541 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5542 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5543 TargetOpcode::G_ANYEXT);
5544
5545 unsigned NewNumElts = NarrowVecTy.getNumElements();
5546
5547 LLT IdxTy = MRI.getType(Idx);
5548 int64_t PartIdx = IdxVal / NewNumElts;
5549 auto NewIdx =
5550 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5551
5552 if (IsInsert) {
5553 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5554
5555 // Use the adjusted index to insert into one of the subvectors.
5556 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5557 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5558 VecParts[PartIdx] = InsertPart.getReg(0);
5559
5560 // Recombine the inserted subvector with the others to reform the result
5561 // vector.
5562 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5563 } else {
5564 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5565 }
5566 }
5567
5568 MI.eraseFromParent();
5569 return Legalized;
5570 }
5571
5572 // With a variable index, we can't perform the operation in a smaller type, so
5573 // we're forced to expand this.
5574 //
5575 // TODO: We could emit a chain of compare/select to figure out which piece to
5576 // index.
5578}
5579
5582 LLT NarrowTy) {
5583 // FIXME: Don't know how to handle secondary types yet.
5584 if (TypeIdx != 0)
5585 return UnableToLegalize;
5586
5587 if (!NarrowTy.isByteSized()) {
5588 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5589 return UnableToLegalize;
5590 }
5591
5592 // This implementation doesn't work for atomics. Give up instead of doing
5593 // something invalid.
5594 if (LdStMI.isAtomic())
5595 return UnableToLegalize;
5596
5597 bool IsLoad = isa<GLoad>(LdStMI);
5598 Register ValReg = LdStMI.getReg(0);
5599 Register AddrReg = LdStMI.getPointerReg();
5600 LLT ValTy = MRI.getType(ValReg);
5601
5602 // FIXME: Do we need a distinct NarrowMemory legalize action?
5603 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5604 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5605 return UnableToLegalize;
5606 }
5607
5608 int NumParts = -1;
5609 int NumLeftover = -1;
5610 LLT LeftoverTy;
5611 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5612 if (IsLoad) {
5613 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5614 } else {
5615 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5616 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5617 NumParts = NarrowRegs.size();
5618 NumLeftover = NarrowLeftoverRegs.size();
5619 }
5620 }
5621
5622 if (NumParts == -1)
5623 return UnableToLegalize;
5624
5625 LLT PtrTy = MRI.getType(AddrReg);
5626 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5627
5628 unsigned TotalSize = ValTy.getSizeInBits();
5629
5630 // Split the load/store into PartTy sized pieces starting at Offset. If this
5631 // is a load, return the new registers in ValRegs. For a store, each elements
5632 // of ValRegs should be PartTy. Returns the next offset that needs to be
5633 // handled.
5634 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5635 auto MMO = LdStMI.getMMO();
5636 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5637 unsigned NumParts, unsigned Offset) -> unsigned {
5638 MachineFunction &MF = MIRBuilder.getMF();
5639 unsigned PartSize = PartTy.getSizeInBits();
5640 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5641 ++Idx) {
5642 unsigned ByteOffset = Offset / 8;
5643 Register NewAddrReg;
5644
5645 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5646 ByteOffset);
5647
5648 MachineMemOperand *NewMMO =
5649 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5650
5651 if (IsLoad) {
5652 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5653 ValRegs.push_back(Dst);
5654 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5655 } else {
5656 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5657 }
5658 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5659 }
5660
5661 return Offset;
5662 };
5663
5664 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5665 unsigned HandledOffset =
5666 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5667
5668 // Handle the rest of the register if this isn't an even type breakdown.
5669 if (LeftoverTy.isValid())
5670 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5671
5672 if (IsLoad) {
5673 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5674 LeftoverTy, NarrowLeftoverRegs);
5675 }
5676
5677 LdStMI.eraseFromParent();
5678 return Legalized;
5679}
5680
5683 LLT NarrowTy) {
5684 using namespace TargetOpcode;
5686 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5687
5688 switch (MI.getOpcode()) {
5689 case G_IMPLICIT_DEF:
5690 case G_TRUNC:
5691 case G_AND:
5692 case G_OR:
5693 case G_XOR:
5694 case G_ADD:
5695 case G_SUB:
5696 case G_MUL:
5697 case G_PTR_ADD:
5698 case G_SMULH:
5699 case G_UMULH:
5700 case G_FADD:
5701 case G_FMUL:
5702 case G_FSUB:
5703 case G_FNEG:
5704 case G_FABS:
5705 case G_FCANONICALIZE:
5706 case G_FDIV:
5707 case G_FREM:
5708 case G_FMA:
5709 case G_FMAD:
5710 case G_FPOW:
5711 case G_FEXP:
5712 case G_FEXP2:
5713 case G_FEXP10:
5714 case G_FLOG:
5715 case G_FLOG2:
5716 case G_FLOG10:
5717 case G_FLDEXP:
5718 case G_FNEARBYINT:
5719 case G_FCEIL:
5720 case G_FFLOOR:
5721 case G_FRINT:
5722 case G_INTRINSIC_LRINT:
5723 case G_INTRINSIC_LLRINT:
5724 case G_INTRINSIC_ROUND:
5725 case G_INTRINSIC_ROUNDEVEN:
5726 case G_LROUND:
5727 case G_LLROUND:
5728 case G_INTRINSIC_TRUNC:
5729 case G_FMODF:
5730 case G_FCOS:
5731 case G_FSIN:
5732 case G_FTAN:
5733 case G_FACOS:
5734 case G_FASIN:
5735 case G_FATAN:
5736 case G_FATAN2:
5737 case G_FCOSH:
5738 case G_FSINH:
5739 case G_FTANH:
5740 case G_FSQRT:
5741 case G_BSWAP:
5742 case G_BITREVERSE:
5743 case G_SDIV:
5744 case G_UDIV:
5745 case G_SREM:
5746 case G_UREM:
5747 case G_SDIVREM:
5748 case G_UDIVREM:
5749 case G_SMIN:
5750 case G_SMAX:
5751 case G_UMIN:
5752 case G_UMAX:
5753 case G_ABS:
5754 case G_FMINNUM:
5755 case G_FMAXNUM:
5756 case G_FMINNUM_IEEE:
5757 case G_FMAXNUM_IEEE:
5758 case G_FMINIMUM:
5759 case G_FMAXIMUM:
5760 case G_FMINIMUMNUM:
5761 case G_FMAXIMUMNUM:
5762 case G_FSHL:
5763 case G_FSHR:
5764 case G_ROTL:
5765 case G_ROTR:
5766 case G_FREEZE:
5767 case G_SADDSAT:
5768 case G_SSUBSAT:
5769 case G_UADDSAT:
5770 case G_USUBSAT:
5771 case G_UMULO:
5772 case G_SMULO:
5773 case G_SHL:
5774 case G_LSHR:
5775 case G_ASHR:
5776 case G_SSHLSAT:
5777 case G_USHLSAT:
5778 case G_CTLZ:
5779 case G_CTLZ_ZERO_POISON:
5780 case G_CTTZ:
5781 case G_CTTZ_ZERO_POISON:
5782 case G_CTPOP:
5783 case G_CTLS:
5784 case G_FCOPYSIGN:
5785 case G_ZEXT:
5786 case G_SEXT:
5787 case G_ANYEXT:
5788 case G_FPEXT:
5789 case G_FPTRUNC:
5790 case G_SITOFP:
5791 case G_UITOFP:
5792 case G_FPTOSI:
5793 case G_FPTOUI:
5794 case G_FPTOSI_SAT:
5795 case G_FPTOUI_SAT:
5796 case G_INTTOPTR:
5797 case G_PTRTOINT:
5798 case G_ADDRSPACE_CAST:
5799 case G_UADDO:
5800 case G_USUBO:
5801 case G_UADDE:
5802 case G_USUBE:
5803 case G_SADDO:
5804 case G_SSUBO:
5805 case G_SADDE:
5806 case G_SSUBE:
5807 case G_STRICT_FADD:
5808 case G_STRICT_FSUB:
5809 case G_STRICT_FMUL:
5810 case G_STRICT_FMA:
5811 case G_STRICT_FLDEXP:
5812 case G_FFREXP:
5813 case G_TRUNC_SSAT_S:
5814 case G_TRUNC_SSAT_U:
5815 case G_TRUNC_USAT_U:
5816 return fewerElementsVectorMultiEltType(GMI, NumElts);
5817 case G_ICMP:
5818 case G_FCMP:
5819 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5820 case G_IS_FPCLASS:
5821 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5822 case G_SELECT:
5823 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5824 return fewerElementsVectorMultiEltType(GMI, NumElts);
5825 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5826 case G_PHI:
5827 return fewerElementsVectorPhi(GMI, NumElts);
5828 case G_UNMERGE_VALUES:
5829 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5830 case G_BUILD_VECTOR:
5831 assert(TypeIdx == 0 && "not a vector type index");
5832 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5833 case G_CONCAT_VECTORS:
5834 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5835 return UnableToLegalize;
5836 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5837 case G_EXTRACT_VECTOR_ELT:
5838 case G_INSERT_VECTOR_ELT:
5839 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5840 case G_LOAD:
5841 case G_STORE:
5842 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5843 case G_SEXT_INREG:
5844 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5846 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5847 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5848 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5849 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5850 case G_SHUFFLE_VECTOR:
5851 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5852 case G_FPOWI:
5853 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5854 case G_BITCAST:
5855 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5856 case G_INTRINSIC_FPTRUNC_ROUND:
5857 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5858 default:
5859 return UnableToLegalize;
5860 }
5861}
5862
5865 LLT NarrowTy) {
5866 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5867 "Not a bitcast operation");
5868
5869 if (TypeIdx != 0)
5870 return UnableToLegalize;
5871
5872 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5873
5874 unsigned NewElemCount =
5875 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5876 SmallVector<Register> SrcVRegs, BitcastVRegs;
5877 if (NewElemCount == 1) {
5878 LLT SrcNarrowTy = SrcTy.getElementType();
5879
5880 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
5881 getUnmergeResults(SrcVRegs, *Unmerge);
5882 } else {
5883 LLT SrcNarrowTy =
5885
5886 // Split the Src and Dst Reg into smaller registers
5887 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5888 return UnableToLegalize;
5889 }
5890
5891 // Build new smaller bitcast instructions
5892 // Not supporting Leftover types for now but will have to
5893 for (Register Reg : SrcVRegs)
5894 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
5895
5896 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5897 MI.eraseFromParent();
5898 return Legalized;
5899}
5900
5902 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5903 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5904 if (TypeIdx != 0)
5905 return UnableToLegalize;
5906
5907 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
5908 MI.getFirst3RegLLTs();
5909 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5910 // The shuffle should be canonicalized by now.
5911 if (DstTy != Src1Ty)
5912 return UnableToLegalize;
5913 if (DstTy != Src2Ty)
5914 return UnableToLegalize;
5915
5916 if (!isPowerOf2_32(DstTy.getNumElements()))
5917 return UnableToLegalize;
5918
5919 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
5920 // Further legalization attempts will be needed to do split further.
5921 NarrowTy =
5922 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
5923 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5924
5925 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
5926 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
5927 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
5928 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
5929 SplitSrc2Regs[1]};
5930
5931 Register Hi, Lo;
5932
5933 // If Lo or Hi uses elements from at most two of the four input vectors, then
5934 // express it as a vector shuffle of those two inputs. Otherwise extract the
5935 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
5937 for (unsigned High = 0; High < 2; ++High) {
5938 Register &Output = High ? Hi : Lo;
5939
5940 // Build a shuffle mask for the output, discovering on the fly which
5941 // input vectors to use as shuffle operands (recorded in InputUsed).
5942 // If building a suitable shuffle vector proves too hard, then bail
5943 // out with useBuildVector set.
5944 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
5945 unsigned FirstMaskIdx = High * NewElts;
5946 bool UseBuildVector = false;
5947 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5948 // The mask element. This indexes into the input.
5949 int Idx = Mask[FirstMaskIdx + MaskOffset];
5950
5951 // The input vector this mask element indexes into.
5952 unsigned Input = (unsigned)Idx / NewElts;
5953
5954 if (Input >= std::size(Inputs)) {
5955 // The mask element does not index into any input vector.
5956 Ops.push_back(-1);
5957 continue;
5958 }
5959
5960 // Turn the index into an offset from the start of the input vector.
5961 Idx -= Input * NewElts;
5962
5963 // Find or create a shuffle vector operand to hold this input.
5964 unsigned OpNo;
5965 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
5966 if (InputUsed[OpNo] == Input) {
5967 // This input vector is already an operand.
5968 break;
5969 } else if (InputUsed[OpNo] == -1U) {
5970 // Create a new operand for this input vector.
5971 InputUsed[OpNo] = Input;
5972 break;
5973 }
5974 }
5975
5976 if (OpNo >= std::size(InputUsed)) {
5977 // More than two input vectors used! Give up on trying to create a
5978 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
5979 UseBuildVector = true;
5980 break;
5981 }
5982
5983 // Add the mask index for the new shuffle vector.
5984 Ops.push_back(Idx + OpNo * NewElts);
5985 }
5986
5987 if (UseBuildVector) {
5988 LLT EltTy = NarrowTy.getElementType();
5990
5991 // Extract the input elements by hand.
5992 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
5993 // The mask element. This indexes into the input.
5994 int Idx = Mask[FirstMaskIdx + MaskOffset];
5995
5996 // The input vector this mask element indexes into.
5997 unsigned Input = (unsigned)Idx / NewElts;
5998
5999 if (Input >= std::size(Inputs)) {
6000 // The mask element is "undef" or indexes off the end of the input.
6001 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6002 continue;
6003 }
6004
6005 // Turn the index into an offset from the start of the input vector.
6006 Idx -= Input * NewElts;
6007
6008 // Extract the vector element by hand.
6009 SVOps.push_back(MIRBuilder
6010 .buildExtractVectorElement(
6011 EltTy, Inputs[Input],
6012 MIRBuilder.buildConstant(LLT::scalar(32), Idx))
6013 .getReg(0));
6014 }
6015
6016 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6017 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6018 } else if (InputUsed[0] == -1U) {
6019 // No input vectors were used! The result is undefined.
6020 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6021 } else if (NewElts == 1) {
6022 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6023 } else {
6024 Register Op0 = Inputs[InputUsed[0]];
6025 // If only one input was used, use an undefined vector for the other.
6026 Register Op1 = InputUsed[1] == -1U
6027 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6028 : Inputs[InputUsed[1]];
6029 // At least one input vector was used. Create a new shuffle vector.
6030 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6031 }
6032
6033 Ops.clear();
6034 }
6035
6036 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6037 MI.eraseFromParent();
6038 return Legalized;
6039}
6040
6042 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6043 auto &RdxMI = cast<GVecReduce>(MI);
6044
6045 if (TypeIdx != 1)
6046 return UnableToLegalize;
6047
6048 // The semantics of the normal non-sequential reductions allow us to freely
6049 // re-associate the operation.
6050 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6051
6052 if (NarrowTy.isVector() &&
6053 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6054 return UnableToLegalize;
6055
6056 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6057 SmallVector<Register> SplitSrcs;
6058 // If NarrowTy is a scalar then we're being asked to scalarize.
6059 const unsigned NumParts =
6060 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6061 : SrcTy.getNumElements();
6062
6063 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6064 if (NarrowTy.isScalar()) {
6065 if (DstTy != NarrowTy)
6066 return UnableToLegalize; // FIXME: handle implicit extensions.
6067
6068 if (isPowerOf2_32(NumParts)) {
6069 // Generate a tree of scalar operations to reduce the critical path.
6070 SmallVector<Register> PartialResults;
6071 unsigned NumPartsLeft = NumParts;
6072 while (NumPartsLeft > 1) {
6073 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6074 PartialResults.emplace_back(
6076 .buildInstr(ScalarOpc, {NarrowTy},
6077 {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
6078 .getReg(0));
6079 }
6080 SplitSrcs = PartialResults;
6081 PartialResults.clear();
6082 NumPartsLeft = SplitSrcs.size();
6083 }
6084 assert(SplitSrcs.size() == 1);
6085 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6086 MI.eraseFromParent();
6087 return Legalized;
6088 }
6089 // If we can't generate a tree, then just do sequential operations.
6090 Register Acc = SplitSrcs[0];
6091 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6092 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
6093 .getReg(0);
6094 MIRBuilder.buildCopy(DstReg, Acc);
6095 MI.eraseFromParent();
6096 return Legalized;
6097 }
6098 SmallVector<Register> PartialReductions;
6099 for (unsigned Part = 0; Part < NumParts; ++Part) {
6100 PartialReductions.push_back(
6101 MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
6102 .getReg(0));
6103 }
6104
6105 // If the types involved are powers of 2, we can generate intermediate vector
6106 // ops, before generating a final reduction operation.
6107 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6108 isPowerOf2_32(NarrowTy.getNumElements())) {
6109 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6110 }
6111
6112 Register Acc = PartialReductions[0];
6113 for (unsigned Part = 1; Part < NumParts; ++Part) {
6114 if (Part == NumParts - 1) {
6115 MIRBuilder.buildInstr(ScalarOpc, {DstReg},
6116 {Acc, PartialReductions[Part]});
6117 } else {
6118 Acc = MIRBuilder
6119 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
6120 .getReg(0);
6121 }
6122 }
6123 MI.eraseFromParent();
6124 return Legalized;
6125}
6126
6129 unsigned int TypeIdx,
6130 LLT NarrowTy) {
6131 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6132 MI.getFirst3RegLLTs();
6133 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6134 DstTy != NarrowTy)
6135 return UnableToLegalize;
6136
6137 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6138 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6139 "Unexpected vecreduce opcode");
6140 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6141 ? TargetOpcode::G_FADD
6142 : TargetOpcode::G_FMUL;
6143
6144 SmallVector<Register> SplitSrcs;
6145 unsigned NumParts = SrcTy.getNumElements();
6146 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6147 Register Acc = ScalarReg;
6148 for (unsigned i = 0; i < NumParts; i++)
6149 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
6150 .getReg(0);
6151
6152 MIRBuilder.buildCopy(DstReg, Acc);
6153 MI.eraseFromParent();
6154 return Legalized;
6155}
6156
6158LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6159 LLT SrcTy, LLT NarrowTy,
6160 unsigned ScalarOpc) {
6161 SmallVector<Register> SplitSrcs;
6162 // Split the sources into NarrowTy size pieces.
6163 extractParts(SrcReg, NarrowTy,
6164 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6165 MIRBuilder, MRI);
6166 // We're going to do a tree reduction using vector operations until we have
6167 // one NarrowTy size value left.
6168 while (SplitSrcs.size() > 1) {
6169 SmallVector<Register> PartialRdxs;
6170 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6171 Register LHS = SplitSrcs[Idx];
6172 Register RHS = SplitSrcs[Idx + 1];
6173 // Create the intermediate vector op.
6174 Register Res =
6175 MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
6176 PartialRdxs.push_back(Res);
6177 }
6178 SplitSrcs = std::move(PartialRdxs);
6179 }
6180 // Finally generate the requested NarrowTy based reduction.
6181 Observer.changingInstr(MI);
6182 MI.getOperand(1).setReg(SplitSrcs[0]);
6183 Observer.changedInstr(MI);
6184 return Legalized;
6185}
6186
6189 const LLT HalfTy, const LLT AmtTy) {
6190
6191 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6192 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6193 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6194
6195 if (Amt.isZero()) {
6196 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6197 MI.eraseFromParent();
6198 return Legalized;
6199 }
6200
6201 LLT NVT = HalfTy;
6202 unsigned NVTBits = HalfTy.getSizeInBits();
6203 unsigned VTBits = 2 * NVTBits;
6204
6205 SrcOp Lo(Register(0)), Hi(Register(0));
6206 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6207 if (Amt.ugt(VTBits)) {
6208 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6209 } else if (Amt.ugt(NVTBits)) {
6210 Lo = MIRBuilder.buildConstant(NVT, 0);
6211 Hi = MIRBuilder.buildShl(NVT, InL,
6212 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6213 } else if (Amt == NVTBits) {
6214 Lo = MIRBuilder.buildConstant(NVT, 0);
6215 Hi = InL;
6216 } else {
6217 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6218 auto OrLHS =
6219 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6220 auto OrRHS = MIRBuilder.buildLShr(
6221 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6222 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6223 }
6224 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6225 if (Amt.ugt(VTBits)) {
6226 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6227 } else if (Amt.ugt(NVTBits)) {
6228 Lo = MIRBuilder.buildLShr(NVT, InH,
6229 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6230 Hi = MIRBuilder.buildConstant(NVT, 0);
6231 } else if (Amt == NVTBits) {
6232 Lo = InH;
6233 Hi = MIRBuilder.buildConstant(NVT, 0);
6234 } else {
6235 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6236
6237 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6238 auto OrRHS = MIRBuilder.buildShl(
6239 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6240
6241 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6242 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6243 }
6244 } else {
6245 if (Amt.ugt(VTBits)) {
6246 Hi = Lo = MIRBuilder.buildAShr(
6247 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6248 } else if (Amt.ugt(NVTBits)) {
6249 Lo = MIRBuilder.buildAShr(NVT, InH,
6250 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6251 Hi = MIRBuilder.buildAShr(NVT, InH,
6252 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6253 } else if (Amt == NVTBits) {
6254 Lo = InH;
6255 Hi = MIRBuilder.buildAShr(NVT, InH,
6256 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6257 } else {
6258 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6259
6260 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6261 auto OrRHS = MIRBuilder.buildShl(
6262 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6263
6264 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6265 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6266 }
6267 }
6268
6269 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6270 MI.eraseFromParent();
6271
6272 return Legalized;
6273}
6274
6277 LLT RequestedTy) {
6278 if (TypeIdx == 1) {
6279 Observer.changingInstr(MI);
6280 narrowScalarSrc(MI, RequestedTy, 2);
6281 Observer.changedInstr(MI);
6282 return Legalized;
6283 }
6284
6285 Register DstReg = MI.getOperand(0).getReg();
6286 LLT DstTy = MRI.getType(DstReg);
6287 if (DstTy.isVector())
6288 return UnableToLegalize;
6289
6290 Register Amt = MI.getOperand(2).getReg();
6291 LLT ShiftAmtTy = MRI.getType(Amt);
6292 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6293 if (DstEltSize % 2 != 0)
6294 return UnableToLegalize;
6295
6296 // Check if we should use multi-way splitting instead of recursive binary
6297 // splitting.
6298 //
6299 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6300 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6301 // and dependency chains created by usual binary splitting approach
6302 // (128->64->32).
6303 //
6304 // The >= 8 parts threshold ensures we only use this optimization when binary
6305 // splitting would require multiple recursive passes, avoiding overhead for
6306 // simple 2-way splits where binary approach is sufficient.
6307 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6308 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6309 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6310 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6311 // steps).
6312 if (NumParts >= 8)
6313 return narrowScalarShiftMultiway(MI, RequestedTy);
6314 }
6315
6316 // Fall back to binary splitting:
6317 // Ignore the input type. We can only go to exactly half the size of the
6318 // input. If that isn't small enough, the resulting pieces will be further
6319 // legalized.
6320 const unsigned NewBitSize = DstEltSize / 2;
6321 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6322 const LLT CondTy = LLT::integer(1);
6323
6324 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6325 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6326 ShiftAmtTy);
6327 }
6328
6329 // TODO: Expand with known bits.
6330
6331 // Handle the fully general expansion by an unknown amount.
6332 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6333
6334 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6335 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6336 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6337
6338 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6339 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6340
6341 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6342 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6343 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6344
6345 Register ResultRegs[2];
6346 switch (MI.getOpcode()) {
6347 case TargetOpcode::G_SHL: {
6348 // Short: ShAmt < NewBitSize
6349 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6350
6351 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6352 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6353 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6354
6355 // Long: ShAmt >= NewBitSize
6356 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6357 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6358
6359 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6360 auto Hi = MIRBuilder.buildSelect(
6361 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6362
6363 ResultRegs[0] = Lo.getReg(0);
6364 ResultRegs[1] = Hi.getReg(0);
6365 break;
6366 }
6367 case TargetOpcode::G_LSHR:
6368 case TargetOpcode::G_ASHR: {
6369 // Short: ShAmt < NewBitSize
6370 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6371
6372 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6373 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6374 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6375
6376 // Long: ShAmt >= NewBitSize
6378 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6379 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6380 } else {
6381 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6382 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6383 }
6384 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6385 {InH, AmtExcess}); // Lo from Hi part.
6386
6387 auto Lo = MIRBuilder.buildSelect(
6388 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6389
6390 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6391
6392 ResultRegs[0] = Lo.getReg(0);
6393 ResultRegs[1] = Hi.getReg(0);
6394 break;
6395 }
6396 default:
6397 llvm_unreachable("not a shift");
6398 }
6399
6400 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6401 MI.eraseFromParent();
6402 return Legalized;
6403}
6404
6406 unsigned PartIdx,
6407 unsigned NumParts,
6408 ArrayRef<Register> SrcParts,
6409 const ShiftParams &Params,
6410 LLT TargetTy, LLT ShiftAmtTy) {
6411 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6412 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6413 assert(WordShiftConst && BitShiftConst && "Expected constants");
6414
6415 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6416 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6417 const bool NeedsInterWordShift = ShiftBits != 0;
6418
6419 switch (Opcode) {
6420 case TargetOpcode::G_SHL: {
6421 // Data moves from lower indices to higher indices
6422 // If this part would come from a source beyond our range, it's zero
6423 if (PartIdx < ShiftWords)
6424 return Params.Zero;
6425
6426 unsigned SrcIdx = PartIdx - ShiftWords;
6427 if (!NeedsInterWordShift)
6428 return SrcParts[SrcIdx];
6429
6430 // Combine shifted main part with carry from previous part
6431 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6432 if (SrcIdx > 0) {
6433 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6434 Params.InvBitShift);
6435 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6436 }
6437 return Hi.getReg(0);
6438 }
6439
6440 case TargetOpcode::G_LSHR: {
6441 unsigned SrcIdx = PartIdx + ShiftWords;
6442 if (SrcIdx >= NumParts)
6443 return Params.Zero;
6444 if (!NeedsInterWordShift)
6445 return SrcParts[SrcIdx];
6446
6447 // Combine shifted main part with carry from next part
6448 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6449 if (SrcIdx + 1 < NumParts) {
6450 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6451 Params.InvBitShift);
6452 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6453 }
6454 return Lo.getReg(0);
6455 }
6456
6457 case TargetOpcode::G_ASHR: {
6458 // Like LSHR but preserves sign bit
6459 unsigned SrcIdx = PartIdx + ShiftWords;
6460 if (SrcIdx >= NumParts)
6461 return Params.SignBit;
6462 if (!NeedsInterWordShift)
6463 return SrcParts[SrcIdx];
6464
6465 // Only the original MSB part uses arithmetic shift to preserve sign. All
6466 // other parts use logical shift since they're just moving data bits.
6467 auto Lo =
6468 (SrcIdx == NumParts - 1)
6469 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6470 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6471 Register HiSrc =
6472 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6473 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6474 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6475 }
6476
6477 default:
6478 llvm_unreachable("not a shift");
6479 }
6480}
6481
6483 Register MainOperand,
6484 Register ShiftAmt,
6485 LLT TargetTy,
6486 Register CarryOperand) {
6487 // This helper generates a single output part for variable shifts by combining
6488 // the main operand (shifted by BitShift) with carry bits from an adjacent
6489 // part.
6490
6491 // For G_ASHR, individual parts don't have their own sign bit, only the
6492 // complete value does. So we use LSHR for the main operand shift in ASHR
6493 // context.
6494 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6495 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6496 : Opcode;
6497
6498 // Perform the primary shift on the main operand
6499 Register MainShifted =
6500 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6501 .getReg(0);
6502
6503 // No carry operand available
6504 if (!CarryOperand.isValid())
6505 return MainShifted;
6506
6507 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6508 // so carry bits aren't needed.
6509 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6510 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6511 LLT BoolTy = LLT::scalar(1);
6512 auto IsZeroBitShift =
6513 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6514
6515 // Extract bits from the adjacent part that will "carry over" into this part.
6516 // The carry direction is opposite to the main shift direction, so we can
6517 // align the two shifted values before combining them with OR.
6518
6519 // Determine the carry shift opcode (opposite direction)
6520 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6521 : TargetOpcode::G_SHL;
6522
6523 // Calculate inverse shift amount: BitWidth - ShiftAmt
6524 auto TargetBitsConst =
6525 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6526 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6527
6528 // Shift the carry operand
6529 Register CarryBits =
6531 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6532 .getReg(0);
6533
6534 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6535 // TargetBits which would be poison for the individual carry shift operation).
6536 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6537 Register SafeCarryBits =
6538 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6539 .getReg(0);
6540
6541 // Combine the main shifted part with the carry bits
6542 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6543}
6544
6547 const APInt &Amt,
6548 LLT TargetTy,
6549 LLT ShiftAmtTy) {
6550 // Any wide shift can be decomposed into WordShift + BitShift components.
6551 // When shift amount is known constant, directly compute the decomposition
6552 // values and generate constant registers.
6553 Register DstReg = MI.getOperand(0).getReg();
6554 Register SrcReg = MI.getOperand(1).getReg();
6555 LLT DstTy = MRI.getType(DstReg);
6556
6557 const unsigned DstBits = DstTy.getScalarSizeInBits();
6558 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6559 const unsigned NumParts = DstBits / TargetBits;
6560
6561 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6562
6563 // When the shift amount is known at compile time, we just calculate which
6564 // source parts contribute to each output part.
6565
6566 SmallVector<Register, 8> SrcParts;
6567 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6568
6569 if (Amt.isZero()) {
6570 // No shift needed, just copy
6571 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6572 MI.eraseFromParent();
6573 return Legalized;
6574 }
6575
6576 ShiftParams Params;
6577 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6578 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6579
6580 // Generate constants and values needed by all shift types
6581 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6582 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6583 Params.InvBitShift =
6584 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6585 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6586
6587 // For ASHR, we need the sign-extended value to fill shifted-out positions
6588 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6589 Params.SignBit =
6591 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6592 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6593 .getReg(0);
6594
6595 SmallVector<Register, 8> DstParts(NumParts);
6596 for (unsigned I = 0; I < NumParts; ++I)
6597 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6598 Params, TargetTy, ShiftAmtTy);
6599
6600 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6601 MI.eraseFromParent();
6602 return Legalized;
6603}
6604
6607 Register DstReg = MI.getOperand(0).getReg();
6608 Register SrcReg = MI.getOperand(1).getReg();
6609 Register AmtReg = MI.getOperand(2).getReg();
6610 LLT DstTy = MRI.getType(DstReg);
6611 LLT ShiftAmtTy = MRI.getType(AmtReg);
6612
6613 const unsigned DstBits = DstTy.getScalarSizeInBits();
6614 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6615 const unsigned NumParts = DstBits / TargetBits;
6616
6617 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6618 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6619
6620 // If the shift amount is known at compile time, we can use direct indexing
6621 // instead of generating select chains in the general case.
6622 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6623 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6624 ShiftAmtTy);
6625
6626 // For runtime-variable shift amounts, we must generate a more complex
6627 // sequence that handles all possible shift values using select chains.
6628
6629 // Split the input into target-sized pieces
6630 SmallVector<Register, 8> SrcParts;
6631 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6632
6633 // Shifting by zero should be a no-op.
6634 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6635 LLT BoolTy = LLT::scalar(1);
6636 auto IsZeroShift =
6637 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6638
6639 // Any wide shift can be decomposed into two components:
6640 // 1. WordShift: number of complete target-sized words to shift
6641 // 2. BitShift: number of bits to shift within each word
6642 //
6643 // Example: 128-bit >> 50 with 32-bit target:
6644 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6645 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6646 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6647 auto TargetBitsLog2Const =
6648 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6649 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6650
6651 Register WordShift =
6652 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6653 Register BitShift =
6654 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6655
6656 // Fill values:
6657 // - SHL/LSHR: fill with zeros
6658 // - ASHR: fill with sign-extended MSB
6659 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6660
6661 Register FillValue;
6662 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6663 auto TargetBitsMinusOneConst =
6664 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6665 FillValue = MIRBuilder
6666 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6667 TargetBitsMinusOneConst)
6668 .getReg(0);
6669 } else {
6670 FillValue = ZeroReg;
6671 }
6672
6673 SmallVector<Register, 8> DstParts(NumParts);
6674
6675 // For each output part, generate a select chain that chooses the correct
6676 // result based on the runtime WordShift value. This handles all possible
6677 // word shift amounts by pre-calculating what each would produce.
6678 for (unsigned I = 0; I < NumParts; ++I) {
6679 // Initialize with appropriate default value for this shift type
6680 Register InBoundsResult = FillValue;
6681
6682 // clang-format off
6683 // Build a branchless select chain by pre-computing results for all possible
6684 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6685 //
6686 // K=0: select(WordShift==0, result0, FillValue)
6687 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6688 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6689 // clang-format on
6690 for (unsigned K = 0; K < NumParts; ++K) {
6691 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6692 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6693 WordShift, WordShiftKConst);
6694
6695 // Calculate source indices for this word shift
6696 //
6697 // For 4-part 128-bit value with K=1 word shift:
6698 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6699 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6700 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6701 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6702 int MainSrcIdx;
6703 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6704
6705 switch (MI.getOpcode()) {
6706 case TargetOpcode::G_SHL:
6707 MainSrcIdx = (int)I - (int)K;
6708 CarrySrcIdx = MainSrcIdx - 1;
6709 break;
6710 case TargetOpcode::G_LSHR:
6711 case TargetOpcode::G_ASHR:
6712 MainSrcIdx = (int)I + (int)K;
6713 CarrySrcIdx = MainSrcIdx + 1;
6714 break;
6715 default:
6716 llvm_unreachable("Not a shift");
6717 }
6718
6719 // Check bounds and build the result for this word shift
6720 Register ResultForK;
6721 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6722 Register MainOp = SrcParts[MainSrcIdx];
6723 Register CarryOp;
6724
6725 // Determine carry operand with bounds checking
6726 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6727 CarryOp = SrcParts[CarrySrcIdx];
6728 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6729 CarrySrcIdx >= (int)NumParts)
6730 CarryOp = FillValue; // Use sign extension
6731
6732 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6733 TargetTy, CarryOp);
6734 } else {
6735 // Out of bounds - use fill value for this k
6736 ResultForK = FillValue;
6737 }
6738
6739 // Select this result if WordShift equals k
6740 InBoundsResult =
6742 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6743 .getReg(0);
6744 }
6745
6746 // Handle zero-shift special case: if shift is 0, use original input
6747 DstParts[I] =
6749 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6750 .getReg(0);
6751 }
6752
6753 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6754 MI.eraseFromParent();
6755 return Legalized;
6756}
6757
6760 LLT MoreTy) {
6761 assert(TypeIdx == 0 && "Expecting only Idx 0");
6762
6763 Observer.changingInstr(MI);
6764 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6765 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6766 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6767 moreElementsVectorSrc(MI, MoreTy, I);
6768 }
6769
6770 MachineBasicBlock &MBB = *MI.getParent();
6771 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6772 moreElementsVectorDst(MI, MoreTy, 0);
6773 Observer.changedInstr(MI);
6774 return Legalized;
6775}
6776
6777MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6778 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6779 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6780
6781 switch (Opcode) {
6782 default:
6784 "getNeutralElementForVecReduce called with invalid opcode!");
6785 case TargetOpcode::G_VECREDUCE_ADD:
6786 case TargetOpcode::G_VECREDUCE_OR:
6787 case TargetOpcode::G_VECREDUCE_XOR:
6788 case TargetOpcode::G_VECREDUCE_UMAX:
6789 return MIRBuilder.buildConstant(Ty, 0);
6790 case TargetOpcode::G_VECREDUCE_MUL:
6791 return MIRBuilder.buildConstant(Ty, 1);
6792 case TargetOpcode::G_VECREDUCE_AND:
6793 case TargetOpcode::G_VECREDUCE_UMIN:
6795 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6796 case TargetOpcode::G_VECREDUCE_SMAX:
6798 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6799 case TargetOpcode::G_VECREDUCE_SMIN:
6801 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6802 case TargetOpcode::G_VECREDUCE_FADD:
6803 return MIRBuilder.buildFConstant(Ty, -0.0);
6804 case TargetOpcode::G_VECREDUCE_FMUL:
6805 return MIRBuilder.buildFConstant(Ty, 1.0);
6806 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6807 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6808 assert(false && "getNeutralElementForVecReduce unimplemented for "
6809 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6810 }
6811 llvm_unreachable("switch expected to return!");
6812}
6813
6816 LLT MoreTy) {
6817 unsigned Opc = MI.getOpcode();
6818 switch (Opc) {
6819 case TargetOpcode::G_IMPLICIT_DEF:
6820 case TargetOpcode::G_LOAD: {
6821 if (TypeIdx != 0)
6822 return UnableToLegalize;
6823 Observer.changingInstr(MI);
6824 moreElementsVectorDst(MI, MoreTy, 0);
6825 Observer.changedInstr(MI);
6826 return Legalized;
6827 }
6828 case TargetOpcode::G_STORE:
6829 if (TypeIdx != 0)
6830 return UnableToLegalize;
6831 Observer.changingInstr(MI);
6832 moreElementsVectorSrc(MI, MoreTy, 0);
6833 Observer.changedInstr(MI);
6834 return Legalized;
6835 case TargetOpcode::G_AND:
6836 case TargetOpcode::G_OR:
6837 case TargetOpcode::G_XOR:
6838 case TargetOpcode::G_ADD:
6839 case TargetOpcode::G_SUB:
6840 case TargetOpcode::G_MUL:
6841 case TargetOpcode::G_FADD:
6842 case TargetOpcode::G_FSUB:
6843 case TargetOpcode::G_FMUL:
6844 case TargetOpcode::G_FDIV:
6845 case TargetOpcode::G_FCOPYSIGN:
6846 case TargetOpcode::G_UADDSAT:
6847 case TargetOpcode::G_USUBSAT:
6848 case TargetOpcode::G_SADDSAT:
6849 case TargetOpcode::G_SSUBSAT:
6850 case TargetOpcode::G_SMIN:
6851 case TargetOpcode::G_SMAX:
6852 case TargetOpcode::G_UMIN:
6853 case TargetOpcode::G_UMAX:
6854 case TargetOpcode::G_FMINNUM:
6855 case TargetOpcode::G_FMAXNUM:
6856 case TargetOpcode::G_FMINNUM_IEEE:
6857 case TargetOpcode::G_FMAXNUM_IEEE:
6858 case TargetOpcode::G_FMINIMUM:
6859 case TargetOpcode::G_FMAXIMUM:
6860 case TargetOpcode::G_FMINIMUMNUM:
6861 case TargetOpcode::G_FMAXIMUMNUM:
6862 case TargetOpcode::G_STRICT_FADD:
6863 case TargetOpcode::G_STRICT_FSUB:
6864 case TargetOpcode::G_STRICT_FMUL: {
6865 Observer.changingInstr(MI);
6866 moreElementsVectorSrc(MI, MoreTy, 1);
6867 moreElementsVectorSrc(MI, MoreTy, 2);
6868 moreElementsVectorDst(MI, MoreTy, 0);
6869 Observer.changedInstr(MI);
6870 return Legalized;
6871 }
6872 case TargetOpcode::G_SHL:
6873 case TargetOpcode::G_ASHR:
6874 case TargetOpcode::G_LSHR: {
6875 Observer.changingInstr(MI);
6876 moreElementsVectorSrc(MI, MoreTy, 1);
6877 // The shift operand may have a different scalar type from the source and
6878 // destination operands.
6879 LLT ShiftMoreTy = MoreTy.changeElementType(
6880 MRI.getType(MI.getOperand(2).getReg()).getElementType());
6881 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
6882 moreElementsVectorDst(MI, MoreTy, 0);
6883 Observer.changedInstr(MI);
6884 return Legalized;
6885 }
6886 case TargetOpcode::G_FMA:
6887 case TargetOpcode::G_STRICT_FMA:
6888 case TargetOpcode::G_FSHR:
6889 case TargetOpcode::G_FSHL: {
6890 Observer.changingInstr(MI);
6891 moreElementsVectorSrc(MI, MoreTy, 1);
6892 moreElementsVectorSrc(MI, MoreTy, 2);
6893 moreElementsVectorSrc(MI, MoreTy, 3);
6894 moreElementsVectorDst(MI, MoreTy, 0);
6895 Observer.changedInstr(MI);
6896 return Legalized;
6897 }
6898 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
6899 case TargetOpcode::G_EXTRACT:
6900 if (TypeIdx != 1)
6901 return UnableToLegalize;
6902 Observer.changingInstr(MI);
6903 moreElementsVectorSrc(MI, MoreTy, 1);
6904 Observer.changedInstr(MI);
6905 return Legalized;
6906 case TargetOpcode::G_INSERT:
6907 case TargetOpcode::G_INSERT_VECTOR_ELT:
6908 case TargetOpcode::G_FREEZE:
6909 case TargetOpcode::G_FNEG:
6910 case TargetOpcode::G_FABS:
6911 case TargetOpcode::G_FSQRT:
6912 case TargetOpcode::G_FCEIL:
6913 case TargetOpcode::G_FFLOOR:
6914 case TargetOpcode::G_FNEARBYINT:
6915 case TargetOpcode::G_FRINT:
6916 case TargetOpcode::G_INTRINSIC_ROUND:
6917 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
6918 case TargetOpcode::G_INTRINSIC_TRUNC:
6919 case TargetOpcode::G_BITREVERSE:
6920 case TargetOpcode::G_BSWAP:
6921 case TargetOpcode::G_FCANONICALIZE:
6922 case TargetOpcode::G_SEXT_INREG:
6923 case TargetOpcode::G_ABS:
6924 case TargetOpcode::G_CTLZ:
6925 case TargetOpcode::G_CTPOP:
6926 if (TypeIdx != 0)
6927 return UnableToLegalize;
6928 Observer.changingInstr(MI);
6929 moreElementsVectorSrc(MI, MoreTy, 1);
6930 moreElementsVectorDst(MI, MoreTy, 0);
6931 Observer.changedInstr(MI);
6932 return Legalized;
6933 case TargetOpcode::G_SELECT: {
6934 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
6935 if (TypeIdx == 1) {
6936 if (!CondTy.isScalar() ||
6937 DstTy.getElementCount() != MoreTy.getElementCount())
6938 return UnableToLegalize;
6939
6940 // This is turning a scalar select of vectors into a vector
6941 // select. Broadcast the select condition.
6942 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
6943 Observer.changingInstr(MI);
6944 MI.getOperand(1).setReg(ShufSplat.getReg(0));
6945 Observer.changedInstr(MI);
6946 return Legalized;
6947 }
6948
6949 if (CondTy.isVector())
6950 return UnableToLegalize;
6951
6952 Observer.changingInstr(MI);
6953 moreElementsVectorSrc(MI, MoreTy, 2);
6954 moreElementsVectorSrc(MI, MoreTy, 3);
6955 moreElementsVectorDst(MI, MoreTy, 0);
6956 Observer.changedInstr(MI);
6957 return Legalized;
6958 }
6959 case TargetOpcode::G_UNMERGE_VALUES:
6960 return UnableToLegalize;
6961 case TargetOpcode::G_PHI:
6962 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
6963 case TargetOpcode::G_SHUFFLE_VECTOR:
6964 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
6965 case TargetOpcode::G_BUILD_VECTOR: {
6967 for (auto Op : MI.uses()) {
6968 Elts.push_back(Op.getReg());
6969 }
6970
6971 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
6972 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
6973 }
6974
6975 MIRBuilder.buildDeleteTrailingVectorElements(
6976 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
6977 MI.eraseFromParent();
6978 return Legalized;
6979 }
6980 case TargetOpcode::G_SEXT:
6981 case TargetOpcode::G_ZEXT:
6982 case TargetOpcode::G_ANYEXT:
6983 case TargetOpcode::G_TRUNC:
6984 case TargetOpcode::G_FPTRUNC:
6985 case TargetOpcode::G_FPEXT:
6986 case TargetOpcode::G_FPTOSI:
6987 case TargetOpcode::G_FPTOUI:
6988 case TargetOpcode::G_FPTOSI_SAT:
6989 case TargetOpcode::G_FPTOUI_SAT:
6990 case TargetOpcode::G_SITOFP:
6991 case TargetOpcode::G_UITOFP: {
6992 Observer.changingInstr(MI);
6993 LLT SrcExtTy;
6994 LLT DstExtTy;
6995 if (TypeIdx == 0) {
6996 DstExtTy = MoreTy;
6997 SrcExtTy = MoreTy.changeElementType(
6998 MRI.getType(MI.getOperand(1).getReg()).getElementType());
6999 } else {
7000 DstExtTy = MoreTy.changeElementType(
7001 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7002 SrcExtTy = MoreTy;
7003 }
7004 moreElementsVectorSrc(MI, SrcExtTy, 1);
7005 moreElementsVectorDst(MI, DstExtTy, 0);
7006 Observer.changedInstr(MI);
7007 return Legalized;
7008 }
7009 case TargetOpcode::G_ICMP:
7010 case TargetOpcode::G_FCMP: {
7011 if (TypeIdx != 1)
7012 return UnableToLegalize;
7013
7014 Observer.changingInstr(MI);
7015 moreElementsVectorSrc(MI, MoreTy, 2);
7016 moreElementsVectorSrc(MI, MoreTy, 3);
7017 LLT CondTy = MoreTy.changeVectorElementType(
7018 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7019 moreElementsVectorDst(MI, CondTy, 0);
7020 Observer.changedInstr(MI);
7021 return Legalized;
7022 }
7023 case TargetOpcode::G_BITCAST: {
7024 if (TypeIdx != 0)
7025 return UnableToLegalize;
7026
7027 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7028 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7029
7030 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7031 if (coefficient % DstTy.getNumElements() != 0)
7032 return UnableToLegalize;
7033
7034 coefficient = coefficient / DstTy.getNumElements();
7035
7036 LLT NewTy = SrcTy.changeElementCount(
7037 ElementCount::get(coefficient, MoreTy.isScalable()));
7038 Observer.changingInstr(MI);
7039 moreElementsVectorSrc(MI, NewTy, 1);
7040 moreElementsVectorDst(MI, MoreTy, 0);
7041 Observer.changedInstr(MI);
7042 return Legalized;
7043 }
7044 case TargetOpcode::G_VECREDUCE_FADD:
7045 case TargetOpcode::G_VECREDUCE_FMUL:
7046 case TargetOpcode::G_VECREDUCE_ADD:
7047 case TargetOpcode::G_VECREDUCE_MUL:
7048 case TargetOpcode::G_VECREDUCE_AND:
7049 case TargetOpcode::G_VECREDUCE_OR:
7050 case TargetOpcode::G_VECREDUCE_XOR:
7051 case TargetOpcode::G_VECREDUCE_SMAX:
7052 case TargetOpcode::G_VECREDUCE_SMIN:
7053 case TargetOpcode::G_VECREDUCE_UMAX:
7054 case TargetOpcode::G_VECREDUCE_UMIN: {
7055 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7056 MachineOperand &MO = MI.getOperand(1);
7057 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7058 auto NeutralElement = getNeutralElementForVecReduce(
7059 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7060
7061 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7062 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7063 i != e; i++) {
7064 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7065 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7066 NeutralElement, Idx);
7067 }
7068
7069 Observer.changingInstr(MI);
7070 MO.setReg(NewVec.getReg(0));
7071 Observer.changedInstr(MI);
7072 return Legalized;
7073 }
7074
7075 default:
7076 return UnableToLegalize;
7077 }
7078}
7079
7082 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7083 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7084 unsigned MaskNumElts = Mask.size();
7085 unsigned SrcNumElts = SrcTy.getNumElements();
7086 LLT DestEltTy = DstTy.getElementType();
7087
7088 if (MaskNumElts == SrcNumElts)
7089 return Legalized;
7090
7091 if (MaskNumElts < SrcNumElts) {
7092 // Extend mask to match new destination vector size with
7093 // undef values.
7094 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7095 llvm::copy(Mask, NewMask.begin());
7096
7097 moreElementsVectorDst(MI, SrcTy, 0);
7098 MIRBuilder.setInstrAndDebugLoc(MI);
7099 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7100 MI.getOperand(1).getReg(),
7101 MI.getOperand(2).getReg(), NewMask);
7102 MI.eraseFromParent();
7103
7104 return Legalized;
7105 }
7106
7107 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7108 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7109 LLT PaddedTy =
7110 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7111
7112 // Create new source vectors by concatenating the initial
7113 // source vectors with undefined vectors of the same size.
7114 auto Undef = MIRBuilder.buildUndef(SrcTy);
7115 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7116 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7117 MOps1[0] = MI.getOperand(1).getReg();
7118 MOps2[0] = MI.getOperand(2).getReg();
7119
7120 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7121 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7122
7123 // Readjust mask for new input vector length.
7124 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7125 for (unsigned I = 0; I != MaskNumElts; ++I) {
7126 int Idx = Mask[I];
7127 if (Idx >= static_cast<int>(SrcNumElts))
7128 Idx += PaddedMaskNumElts - SrcNumElts;
7129 MappedOps[I] = Idx;
7130 }
7131
7132 // If we got more elements than required, extract subvector.
7133 if (MaskNumElts != PaddedMaskNumElts) {
7134 auto Shuffle =
7135 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7136
7137 SmallVector<Register, 16> Elts(MaskNumElts);
7138 for (unsigned I = 0; I < MaskNumElts; ++I) {
7139 Elts[I] =
7140 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7141 .getReg(0);
7142 }
7143 MIRBuilder.buildBuildVector(DstReg, Elts);
7144 } else {
7145 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7146 }
7147
7148 MI.eraseFromParent();
7150}
7151
7154 unsigned int TypeIdx, LLT MoreTy) {
7155 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7156 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7157 unsigned NumElts = DstTy.getNumElements();
7158 unsigned WidenNumElts = MoreTy.getNumElements();
7159
7160 if (DstTy.isVector() && Src1Ty.isVector() &&
7161 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7163 }
7164
7165 if (TypeIdx != 0)
7166 return UnableToLegalize;
7167
7168 // Expect a canonicalized shuffle.
7169 if (DstTy != Src1Ty || DstTy != Src2Ty)
7170 return UnableToLegalize;
7171
7172 moreElementsVectorSrc(MI, MoreTy, 1);
7173 moreElementsVectorSrc(MI, MoreTy, 2);
7174
7175 // Adjust mask based on new input vector length.
7176 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7177 for (unsigned I = 0; I != NumElts; ++I) {
7178 int Idx = Mask[I];
7179 if (Idx < static_cast<int>(NumElts))
7180 NewMask[I] = Idx;
7181 else
7182 NewMask[I] = Idx - NumElts + WidenNumElts;
7183 }
7184 moreElementsVectorDst(MI, MoreTy, 0);
7185 MIRBuilder.setInstrAndDebugLoc(MI);
7186 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7187 MI.getOperand(1).getReg(),
7188 MI.getOperand(2).getReg(), NewMask);
7189 MI.eraseFromParent();
7190 return Legalized;
7191}
7192
7193void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7194 ArrayRef<Register> Src1Regs,
7195 ArrayRef<Register> Src2Regs,
7196 LLT NarrowTy) {
7198 unsigned SrcParts = Src1Regs.size();
7199 unsigned DstParts = DstRegs.size();
7200
7201 unsigned DstIdx = 0; // Low bits of the result.
7202 Register FactorSum =
7203 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7204 DstRegs[DstIdx] = FactorSum;
7205
7206 Register CarrySumPrevDstIdx;
7208
7209 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7210 // Collect high parts of muls from previous DstIdx.
7211 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7212 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7213 MachineInstrBuilder Umulh =
7214 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7215 Factors.push_back(Umulh.getReg(0));
7216 }
7217 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7218 // the low Src1 part, so multiply-add selectors can use it as the first
7219 // accumulated cross product.
7220 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7221 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7222 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7223 unsigned i = RevI - 1;
7225 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7226 Factors.push_back(Mul.getReg(0));
7227 }
7228 // Add CarrySum from additions calculated for previous DstIdx.
7229 if (DstIdx != 1) {
7230 Factors.push_back(CarrySumPrevDstIdx);
7231 }
7232
7233 Register CarrySum;
7234 // Add all factors and accumulate all carries into CarrySum.
7235 if (DstIdx != DstParts - 1) {
7236 MachineInstrBuilder Uaddo =
7237 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7238 FactorSum = Uaddo.getReg(0);
7239 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7240 for (unsigned i = 2; i < Factors.size(); ++i) {
7241 MachineInstrBuilder Uaddo =
7242 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7243 FactorSum = Uaddo.getReg(0);
7244 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7245 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7246 }
7247 } else {
7248 // Since value for the next index is not calculated, neither is CarrySum.
7249 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7250 for (unsigned i = 2; i < Factors.size(); ++i)
7251 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7252 }
7253
7254 CarrySumPrevDstIdx = CarrySum;
7255 DstRegs[DstIdx] = FactorSum;
7256 Factors.clear();
7257 }
7258}
7259
7262 LLT NarrowTy) {
7263 if (TypeIdx != 0)
7264 return UnableToLegalize;
7265
7266 Register DstReg = MI.getOperand(0).getReg();
7267 LLT DstType = MRI.getType(DstReg);
7268 // FIXME: add support for vector types
7269 if (DstType.isVector())
7270 return UnableToLegalize;
7271
7272 unsigned Opcode = MI.getOpcode();
7273 unsigned OpO, OpE, OpF;
7274 switch (Opcode) {
7275 case TargetOpcode::G_SADDO:
7276 case TargetOpcode::G_SADDE:
7277 case TargetOpcode::G_UADDO:
7278 case TargetOpcode::G_UADDE:
7279 case TargetOpcode::G_ADD:
7280 OpO = TargetOpcode::G_UADDO;
7281 OpE = TargetOpcode::G_UADDE;
7282 OpF = TargetOpcode::G_UADDE;
7283 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7284 OpF = TargetOpcode::G_SADDE;
7285 break;
7286 case TargetOpcode::G_SSUBO:
7287 case TargetOpcode::G_SSUBE:
7288 case TargetOpcode::G_USUBO:
7289 case TargetOpcode::G_USUBE:
7290 case TargetOpcode::G_SUB:
7291 OpO = TargetOpcode::G_USUBO;
7292 OpE = TargetOpcode::G_USUBE;
7293 OpF = TargetOpcode::G_USUBE;
7294 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7295 OpF = TargetOpcode::G_SSUBE;
7296 break;
7297 default:
7298 llvm_unreachable("Unexpected add/sub opcode!");
7299 }
7300
7301 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7302 unsigned NumDefs = MI.getNumExplicitDefs();
7303 Register Src1 = MI.getOperand(NumDefs).getReg();
7304 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7305 Register CarryDst, CarryIn;
7306 if (NumDefs == 2)
7307 CarryDst = MI.getOperand(1).getReg();
7308 if (MI.getNumOperands() == NumDefs + 3)
7309 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7310
7311 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7312 LLT LeftoverTy, DummyTy;
7313 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7314 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7315 MIRBuilder, MRI);
7316 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7317 MRI);
7318
7319 int NarrowParts = Src1Regs.size();
7320 Src1Regs.append(Src1Left);
7321 Src2Regs.append(Src2Left);
7322 DstRegs.reserve(Src1Regs.size());
7323
7324 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7325 Register DstReg =
7326 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7327 Register CarryOut;
7328 // Forward the final carry-out to the destination register
7329 if (i == e - 1 && CarryDst)
7330 CarryOut = CarryDst;
7331 else
7332 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7333
7334 if (!CarryIn) {
7335 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7336 {Src1Regs[i], Src2Regs[i]});
7337 } else if (i == e - 1) {
7338 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7339 {Src1Regs[i], Src2Regs[i], CarryIn});
7340 } else {
7341 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7342 {Src1Regs[i], Src2Regs[i], CarryIn});
7343 }
7344
7345 DstRegs.push_back(DstReg);
7346 CarryIn = CarryOut;
7347 }
7348 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7349 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7350 ArrayRef(DstRegs).drop_front(NarrowParts));
7351
7352 MI.eraseFromParent();
7353 return Legalized;
7354}
7355
7358 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7359
7360 LLT Ty = MRI.getType(DstReg);
7361 if (Ty.isVector())
7362 return UnableToLegalize;
7363
7364 unsigned Size = Ty.getSizeInBits();
7365 unsigned NarrowSize = NarrowTy.getSizeInBits();
7366 if (Size % NarrowSize != 0)
7367 return UnableToLegalize;
7368
7369 unsigned NumParts = Size / NarrowSize;
7370 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
7371 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7372
7373 SmallVector<Register, 2> Src1Parts, Src2Parts;
7374 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7375 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7376 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7377 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7378
7379 // Take only high half of registers if this is high mul.
7380 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7381 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7382 MI.eraseFromParent();
7383 return Legalized;
7384}
7385
7388 LLT NarrowTy) {
7389 if (TypeIdx != 0)
7390 return UnableToLegalize;
7391
7392 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7393
7394 Register Src = MI.getOperand(1).getReg();
7395 LLT SrcTy = MRI.getType(Src);
7396
7397 // If all finite floats fit into the narrowed integer type, we can just swap
7398 // out the result type. This is practically only useful for conversions from
7399 // half to at least 16-bits, so just handle the one case.
7400 if (SrcTy.getScalarType() != LLT::scalar(16) ||
7401 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7402 return UnableToLegalize;
7403
7404 Observer.changingInstr(MI);
7405 narrowScalarDst(MI, NarrowTy, 0,
7406 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7407 Observer.changedInstr(MI);
7408 return Legalized;
7409}
7410
7413 LLT NarrowTy) {
7414 if (TypeIdx != 1)
7415 return UnableToLegalize;
7416
7417 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7418
7419 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7420 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7421 // NarrowSize.
7422 if (SizeOp1 % NarrowSize != 0)
7423 return UnableToLegalize;
7424 int NumParts = SizeOp1 / NarrowSize;
7425
7426 SmallVector<Register, 2> SrcRegs, DstRegs;
7427 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7428 MIRBuilder, MRI);
7429
7430 Register OpReg = MI.getOperand(0).getReg();
7431 uint64_t OpStart = MI.getOperand(2).getImm();
7432 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7433 for (int i = 0; i < NumParts; ++i) {
7434 unsigned SrcStart = i * NarrowSize;
7435
7436 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7437 // No part of the extract uses this subregister, ignore it.
7438 continue;
7439 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7440 // The entire subregister is extracted, forward the value.
7441 DstRegs.push_back(SrcRegs[i]);
7442 continue;
7443 }
7444
7445 // OpSegStart is where this destination segment would start in OpReg if it
7446 // extended infinitely in both directions.
7447 int64_t ExtractOffset;
7448 uint64_t SegSize;
7449 if (OpStart < SrcStart) {
7450 ExtractOffset = 0;
7451 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7452 } else {
7453 ExtractOffset = OpStart - SrcStart;
7454 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7455 }
7456
7457 Register SegReg = SrcRegs[i];
7458 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7459 // A genuine extract is needed.
7460 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7461 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7462 }
7463
7464 DstRegs.push_back(SegReg);
7465 }
7466
7467 Register DstReg = MI.getOperand(0).getReg();
7468 if (MRI.getType(DstReg).isVector())
7469 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7470 else if (DstRegs.size() > 1)
7471 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7472 else
7473 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7474 MI.eraseFromParent();
7475 return Legalized;
7476}
7477
7480 LLT NarrowTy) {
7481 // FIXME: Don't know how to handle secondary types yet.
7482 if (TypeIdx != 0)
7483 return UnableToLegalize;
7484
7485 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7486 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7487 LLT LeftoverTy;
7488 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7489 LeftoverRegs, MIRBuilder, MRI);
7490
7491 SrcRegs.append(LeftoverRegs);
7492
7493 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7494 Register OpReg = MI.getOperand(2).getReg();
7495 uint64_t OpStart = MI.getOperand(3).getImm();
7496 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7497 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7498 unsigned DstStart = I * NarrowSize;
7499
7500 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7501 // The entire subregister is defined by this insert, forward the new
7502 // value.
7503 DstRegs.push_back(OpReg);
7504 continue;
7505 }
7506
7507 Register SrcReg = SrcRegs[I];
7508 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7509 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7510 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7511 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7512 }
7513
7514 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7515 // No part of the insert affects this subregister, forward the original.
7516 DstRegs.push_back(SrcReg);
7517 continue;
7518 }
7519
7520 // OpSegStart is where this destination segment would start in OpReg if it
7521 // extended infinitely in both directions.
7522 int64_t ExtractOffset, InsertOffset;
7523 uint64_t SegSize;
7524 if (OpStart < DstStart) {
7525 InsertOffset = 0;
7526 ExtractOffset = DstStart - OpStart;
7527 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7528 } else {
7529 InsertOffset = OpStart - DstStart;
7530 ExtractOffset = 0;
7531 SegSize =
7532 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
7533 }
7534
7535 Register SegReg = OpReg;
7536 if (ExtractOffset != 0 || SegSize != OpSize) {
7537 // A genuine extract is needed.
7538 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7539 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7540 }
7541
7542 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7543 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7544 DstRegs.push_back(DstReg);
7545 }
7546
7547 uint64_t WideSize = DstRegs.size() * NarrowSize;
7548 Register DstReg = MI.getOperand(0).getReg();
7549 if (WideSize > RegTy.getSizeInBits()) {
7550 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7551 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7552 MIRBuilder.buildTrunc(DstReg, MergeReg);
7553 } else
7554 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7555
7556 MI.eraseFromParent();
7557 return Legalized;
7558}
7559
7562 LLT NarrowTy) {
7563 Register DstReg = MI.getOperand(0).getReg();
7564 LLT DstTy = MRI.getType(DstReg);
7565
7566 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7567
7568 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7569 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7570 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7571 LLT LeftoverTy;
7572 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7573 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7574 return UnableToLegalize;
7575
7576 LLT Unused;
7577 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7578 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7579 llvm_unreachable("inconsistent extractParts result");
7580
7581 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7582 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7583 {Src0Regs[I], Src1Regs[I]});
7584 DstRegs.push_back(Inst.getReg(0));
7585 }
7586
7587 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7588 auto Inst = MIRBuilder.buildInstr(
7589 MI.getOpcode(),
7590 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7591 DstLeftoverRegs.push_back(Inst.getReg(0));
7592 }
7593
7594 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7595 LeftoverTy, DstLeftoverRegs);
7596
7597 MI.eraseFromParent();
7598 return Legalized;
7599}
7600
7603 LLT NarrowTy) {
7604 if (TypeIdx != 0)
7605 return UnableToLegalize;
7606
7607 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7608
7609 LLT DstTy = MRI.getType(DstReg);
7610 if (DstTy.isVector())
7611 return UnableToLegalize;
7612
7614 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7615 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7616 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7617
7618 MI.eraseFromParent();
7619 return Legalized;
7620}
7621
7624 LLT NarrowTy) {
7625 if (TypeIdx != 0)
7626 return UnableToLegalize;
7627
7628 Register CondReg = MI.getOperand(1).getReg();
7629 LLT CondTy = MRI.getType(CondReg);
7630 if (CondTy.isVector()) // TODO: Handle vselect
7631 return UnableToLegalize;
7632
7633 Register DstReg = MI.getOperand(0).getReg();
7634 LLT DstTy = MRI.getType(DstReg);
7635
7636 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7637 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7638 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7639 LLT LeftoverTy;
7640 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7641 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7642 return UnableToLegalize;
7643
7644 LLT Unused;
7645 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7646 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7647 llvm_unreachable("inconsistent extractParts result");
7648
7649 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7650 auto Select = MIRBuilder.buildSelect(NarrowTy,
7651 CondReg, Src1Regs[I], Src2Regs[I]);
7652 DstRegs.push_back(Select.getReg(0));
7653 }
7654
7655 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7656 auto Select = MIRBuilder.buildSelect(
7657 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7658 DstLeftoverRegs.push_back(Select.getReg(0));
7659 }
7660
7661 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7662 LeftoverTy, DstLeftoverRegs);
7663
7664 MI.eraseFromParent();
7665 return Legalized;
7666}
7667
7670 LLT NarrowTy) {
7671 if (TypeIdx != 1)
7672 return UnableToLegalize;
7673
7674 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7675 unsigned NarrowSize = NarrowTy.getSizeInBits();
7676
7677 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7678 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7679
7681 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7682 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7683 auto C_0 = B.buildConstant(NarrowTy, 0);
7684 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7685 UnmergeSrc.getReg(1), C_0);
7686 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7687 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7688 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7689 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7690 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7691 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7692
7693 MI.eraseFromParent();
7694 return Legalized;
7695 }
7696
7697 return UnableToLegalize;
7698}
7699
7702 LLT NarrowTy) {
7703 if (TypeIdx != 1)
7704 return UnableToLegalize;
7705
7706 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7707 unsigned NarrowSize = NarrowTy.getSizeInBits();
7708
7709 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7710 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7711
7713 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7714 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7715 auto C_0 = B.buildConstant(NarrowTy, 0);
7716 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7717 UnmergeSrc.getReg(0), C_0);
7718 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7719 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7720 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7721 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7722 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7723 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7724
7725 MI.eraseFromParent();
7726 return Legalized;
7727 }
7728
7729 return UnableToLegalize;
7730}
7731
7734 LLT NarrowTy) {
7735 if (TypeIdx != 1)
7736 return UnableToLegalize;
7737
7738 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7739 unsigned NarrowSize = NarrowTy.getSizeInBits();
7740
7741 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7742 return UnableToLegalize;
7743
7745
7746 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7747 Register Lo = UnmergeSrc.getReg(0);
7748 Register Hi = UnmergeSrc.getReg(1);
7749
7750 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7751 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7752
7753 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7754
7755 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7756 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7757 // Otherwise the leading zeros represent additional sign bits of the original
7758 // value.
7759 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7760 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7761
7762 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7763 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7764 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7765
7766 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7767
7768 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7769
7770 MI.eraseFromParent();
7771 return Legalized;
7772}
7773
7776 LLT NarrowTy) {
7777 if (TypeIdx != 1)
7778 return UnableToLegalize;
7779
7780 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7781 unsigned NarrowSize = NarrowTy.getSizeInBits();
7782
7783 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7784 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
7785
7786 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
7787 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
7788 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
7789
7790 MI.eraseFromParent();
7791 return Legalized;
7792 }
7793
7794 return UnableToLegalize;
7795}
7796
7799 LLT NarrowTy) {
7800 if (TypeIdx != 1)
7801 return UnableToLegalize;
7802
7804 Register ExpReg = MI.getOperand(2).getReg();
7805 LLT ExpTy = MRI.getType(ExpReg);
7806
7807 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
7808
7809 // Clamp the exponent to the range of the target type.
7810 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
7811 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
7812 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
7813 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
7814
7815 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
7816 Observer.changingInstr(MI);
7817 MI.getOperand(2).setReg(Trunc.getReg(0));
7818 Observer.changedInstr(MI);
7819 return Legalized;
7820}
7821
7824 unsigned Opc = MI.getOpcode();
7825 const auto &TII = MIRBuilder.getTII();
7826 auto isSupported = [this](const LegalityQuery &Q) {
7827 auto QAction = LI.getAction(Q).Action;
7828 return QAction == Legal || QAction == Libcall || QAction == Custom;
7829 };
7830 switch (Opc) {
7831 default:
7832 return UnableToLegalize;
7833 case TargetOpcode::G_CTLZ_ZERO_POISON: {
7834 // This trivially expands to CTLZ.
7835 Observer.changingInstr(MI);
7836 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
7837 Observer.changedInstr(MI);
7838 return Legalized;
7839 }
7840 case TargetOpcode::G_CTLZ: {
7841 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7842 unsigned Len = SrcTy.getScalarSizeInBits();
7843
7844 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
7845 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
7846 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
7847 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
7848 auto ICmp = MIRBuilder.buildICmp(
7849 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
7850 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7851 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
7852 MI.eraseFromParent();
7853 return Legalized;
7854 }
7855 // for now, we do this:
7856 // NewLen = NextPowerOf2(Len);
7857 // x = x | (x >> 1);
7858 // x = x | (x >> 2);
7859 // ...
7860 // x = x | (x >>16);
7861 // x = x | (x >>32); // for 64-bit input
7862 // Upto NewLen/2
7863 // return Len - popcount(x);
7864 //
7865 // Ref: "Hacker's Delight" by Henry Warren
7866 Register Op = SrcReg;
7867 unsigned NewLen = PowerOf2Ceil(Len);
7868 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
7869 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
7870 auto MIBOp = MIRBuilder.buildOr(
7871 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
7872 Op = MIBOp.getReg(0);
7873 }
7874 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
7875 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
7876 MIBPop);
7877 MI.eraseFromParent();
7878 return Legalized;
7879 }
7880 case TargetOpcode::G_CTTZ_ZERO_POISON: {
7881 // This trivially expands to CTTZ.
7882 Observer.changingInstr(MI);
7883 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
7884 Observer.changedInstr(MI);
7885 return Legalized;
7886 }
7887 case TargetOpcode::G_CTTZ: {
7888 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7889
7890 unsigned Len = SrcTy.getScalarSizeInBits();
7891 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
7892 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
7893 // zero.
7894 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
7895 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
7896 auto ICmp = MIRBuilder.buildICmp(
7897 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
7898 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7899 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
7900 MI.eraseFromParent();
7901 return Legalized;
7902 }
7903 // for now, we use: { return popcount(~x & (x - 1)); }
7904 // unless the target has ctlz but not ctpop, in which case we use:
7905 // { return 32 - nlz(~x & (x-1)); }
7906 // Ref: "Hacker's Delight" by Henry Warren
7907 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
7908 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
7909 auto MIBTmp = MIRBuilder.buildAnd(
7910 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
7911 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
7912 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
7913 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
7914 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
7915 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
7916 MI.eraseFromParent();
7917 return Legalized;
7918 }
7919 Observer.changingInstr(MI);
7920 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
7921 MI.getOperand(1).setReg(MIBTmp.getReg(0));
7922 Observer.changedInstr(MI);
7923 return Legalized;
7924 }
7925 case TargetOpcode::G_CTPOP: {
7926 Register SrcReg = MI.getOperand(1).getReg();
7927 LLT Ty = MRI.getType(SrcReg);
7928 unsigned Size = Ty.getScalarSizeInBits();
7930
7931 // Bail out on irregular type lengths.
7932 if (Size > 128 || Size % 8 != 0)
7933 return UnableToLegalize;
7934
7935 // Count set bits in blocks of 2 bits. Default approach would be
7936 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
7937 // We use following formula instead:
7938 // B2Count = val - { (val >> 1) & 0x55555555 }
7939 // since it gives same result in blocks of 2 with one instruction less.
7940 auto C_1 = B.buildConstant(Ty, 1);
7941 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
7942 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
7943 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
7944 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
7945 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
7946
7947 // In order to get count in blocks of 4 add values from adjacent block of 2.
7948 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
7949 auto C_2 = B.buildConstant(Ty, 2);
7950 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
7951 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
7952 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
7953 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
7954 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
7955 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
7956
7957 // For count in blocks of 8 bits we don't have to mask high 4 bits before
7958 // addition since count value sits in range {0,...,8} and 4 bits are enough
7959 // to hold such binary values. After addition high 4 bits still hold count
7960 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
7961 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
7962 auto C_4 = B.buildConstant(Ty, 4);
7963 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
7964 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
7965 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
7966 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
7967 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
7968
7969 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
7970
7971 // Avoid the multiply when shift-add is cheaper.
7972 if (Size == 16 && !Ty.isVector()) {
7973 // v = (v + (v >> 8)) & 0xFF;
7974 auto C_8 = B.buildConstant(Ty, 8);
7975 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
7976 auto Res = B.buildAdd(Ty, B8Count, HighSum);
7977 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
7978 MI.eraseFromParent();
7979 return Legalized;
7980 }
7981
7982 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
7983 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
7984 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
7985
7986 // Shift count result from 8 high bits to low bits.
7987 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
7988
7989 auto IsMulSupported = [this](const LLT Ty) {
7990 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
7991 return Action == Legal || Action == WidenScalar || Action == Custom;
7992 };
7993 if (IsMulSupported(Ty)) {
7994 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
7995 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
7996 } else {
7997 auto ResTmp = B8Count;
7998 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
7999 auto ShiftC = B.buildConstant(Ty, Shift);
8000 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
8001 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
8002 }
8003 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8004 }
8005 MI.eraseFromParent();
8006 return Legalized;
8007 }
8008 case TargetOpcode::G_CTLS: {
8009 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8010
8011 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
8012 auto SignIdxC =
8013 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
8014 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
8015
8016 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
8017
8018 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
8019 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
8020
8021 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8022 MI.eraseFromParent();
8023 return Legalized;
8024 }
8025 }
8026}
8027
8028// Check that (every element of) Reg is undef or not an exact multiple of BW.
8030 Register Reg, unsigned BW) {
8031 return matchUnaryPredicate(
8032 MRI, Reg,
8033 [=](const Constant *C) {
8034 // Null constant here means an undef.
8036 return !CI || CI->getValue().urem(BW) != 0;
8037 },
8038 /*AllowUndefs*/ true);
8039}
8040
8043 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8044 LLT Ty = MRI.getType(Dst);
8045 LLT ShTy = MRI.getType(Z);
8046
8047 unsigned BW = Ty.getScalarSizeInBits();
8048
8049 if (!isPowerOf2_32(BW))
8050 return UnableToLegalize;
8051
8052 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8053 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8054
8055 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8056 // fshl X, Y, Z -> fshr X, Y, -Z
8057 // fshr X, Y, Z -> fshl X, Y, -Z
8058 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8059 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8060 } else {
8061 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8062 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8063 auto One = MIRBuilder.buildConstant(ShTy, 1);
8064 if (IsFSHL) {
8065 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8066 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8067 } else {
8068 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8069 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8070 }
8071
8072 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8073 }
8074
8075 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8076 MI.eraseFromParent();
8077 return Legalized;
8078}
8079
8082 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8083 LLT Ty = MRI.getType(Dst);
8084 LLT ShTy = MRI.getType(Z);
8085
8086 const unsigned BW = Ty.getScalarSizeInBits();
8087 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8088
8089 Register ShX, ShY;
8090 Register ShAmt, InvShAmt;
8091
8092 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8093 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8094 // fshl: X << C | Y >> (BW - C)
8095 // fshr: X << (BW - C) | Y >> C
8096 // where C = Z % BW is not zero
8097 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8098 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8099 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8100 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8101 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8102 } else {
8103 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8104 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8105 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8106 if (isPowerOf2_32(BW)) {
8107 // Z % BW -> Z & (BW - 1)
8108 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8109 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8110 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8111 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8112 } else {
8113 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8114 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8115 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8116 }
8117
8118 auto One = MIRBuilder.buildConstant(ShTy, 1);
8119 if (IsFSHL) {
8120 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8121 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8122 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8123 } else {
8124 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8125 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8126 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8127 }
8128 }
8129
8130 MIRBuilder.buildOr(Dst, ShX, ShY, MachineInstr::Disjoint);
8131 MI.eraseFromParent();
8132 return Legalized;
8133}
8134
8137 // These operations approximately do the following (while avoiding undefined
8138 // shifts by BW):
8139 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8140 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8141 Register Dst = MI.getOperand(0).getReg();
8142 LLT Ty = MRI.getType(Dst);
8143 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8144
8145 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8146 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8147
8148 // TODO: Use smarter heuristic that accounts for vector legalization.
8149 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8150 return lowerFunnelShiftAsShifts(MI);
8151
8152 // This only works for powers of 2, fallback to shifts if it fails.
8153 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8154 if (Result == UnableToLegalize)
8155 return lowerFunnelShiftAsShifts(MI);
8156 return Result;
8157}
8158
8160 auto [Dst, Src] = MI.getFirst2Regs();
8161 LLT DstTy = MRI.getType(Dst);
8162 LLT SrcTy = MRI.getType(Src);
8163
8164 uint32_t DstTySize = DstTy.getSizeInBits();
8165 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8166 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8167
8168 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8169 !isPowerOf2_32(SrcTyScalarSize))
8170 return UnableToLegalize;
8171
8172 // The step between extend is too large, split it by creating an intermediate
8173 // extend instruction
8174 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8175 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8176 // If the destination type is illegal, split it into multiple statements
8177 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8178 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8179 // Unmerge the vector
8180 LLT EltTy = MidTy.changeElementCount(
8182 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8183
8184 // ZExt the vectors
8185 LLT ZExtResTy = DstTy.changeElementCount(
8187 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8188 {UnmergeSrc.getReg(0)});
8189 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8190 {UnmergeSrc.getReg(1)});
8191
8192 // Merge the ending vectors
8193 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8194
8195 MI.eraseFromParent();
8196 return Legalized;
8197 }
8198 return UnableToLegalize;
8199}
8200
8202 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8203 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8204 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8205 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8206 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8207 // %lo16(<4 x s16>) = G_TRUNC %inlo
8208 // %hi16(<4 x s16>) = G_TRUNC %inhi
8209 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8210 // %res(<8 x s8>) = G_TRUNC %in16
8211
8212 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8213
8214 Register DstReg = MI.getOperand(0).getReg();
8215 Register SrcReg = MI.getOperand(1).getReg();
8216 LLT DstTy = MRI.getType(DstReg);
8217 LLT SrcTy = MRI.getType(SrcReg);
8218
8219 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8221 isPowerOf2_32(SrcTy.getNumElements()) &&
8222 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8223 // Split input type.
8224 LLT SplitSrcTy = SrcTy.changeElementCount(
8225 SrcTy.getElementCount().divideCoefficientBy(2));
8226
8227 // First, split the source into two smaller vectors.
8228 SmallVector<Register, 2> SplitSrcs;
8229 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8230
8231 // Truncate the splits into intermediate narrower elements.
8232 LLT InterTy;
8233 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8234 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8235 else
8236 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8237 for (Register &Src : SplitSrcs)
8238 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8239
8240 // Combine the new truncates into one vector
8241 auto Merge = MIRBuilder.buildMergeLikeInstr(
8242 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8243
8244 // Truncate the new vector to the final result type
8245 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8246 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8247 else
8248 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8249
8250 MI.eraseFromParent();
8251
8252 return Legalized;
8253 }
8254 return UnableToLegalize;
8255}
8256
8259 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8260 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8261 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8262 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8263 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8264 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8265 MI.eraseFromParent();
8266 return Legalized;
8267}
8268
8270 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8271
8272 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8273 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8274
8275 MIRBuilder.setInstrAndDebugLoc(MI);
8276
8277 // If a rotate in the other direction is supported, use it.
8278 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8279 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8280 isPowerOf2_32(EltSizeInBits))
8281 return lowerRotateWithReverseRotate(MI);
8282
8283 // If a funnel shift is supported, use it.
8284 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8285 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8286 bool IsFShLegal = false;
8287 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8288 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8289 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8290 Register R3) {
8291 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8292 MI.eraseFromParent();
8293 return Legalized;
8294 };
8295 // If a funnel shift in the other direction is supported, use it.
8296 if (IsFShLegal) {
8297 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8298 } else if (isPowerOf2_32(EltSizeInBits)) {
8299 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8300 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8301 }
8302 }
8303
8304 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8305 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8306 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8307 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8308 Register ShVal;
8309 Register RevShiftVal;
8310 if (isPowerOf2_32(EltSizeInBits)) {
8311 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8312 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8313 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8314 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8315 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8316 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8317 RevShiftVal =
8318 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8319 } else {
8320 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8321 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8322 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8323 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8324 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8325 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8326 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8327 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8328 RevShiftVal =
8329 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8330 }
8331 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, MachineInstr::Disjoint);
8332 MI.eraseFromParent();
8333 return Legalized;
8334}
8335
8336// Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
8337// representation.
8340 auto [Dst, Src] = MI.getFirst2Regs();
8341 const LLT S64 = LLT::scalar(64);
8342 const LLT S32 = LLT::scalar(32);
8343 const LLT S1 = LLT::scalar(1);
8344
8345 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8346
8347 // unsigned cul2f(ulong u) {
8348 // uint lz = clz(u);
8349 // uint e = (u != 0) ? 127U + 63U - lz : 0;
8350 // u = (u << lz) & 0x7fffffffffffffffUL;
8351 // ulong t = u & 0xffffffffffUL;
8352 // uint v = (e << 23) | (uint)(u >> 40);
8353 // uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
8354 // return as_float(v + r);
8355 // }
8356
8357 auto Zero32 = MIRBuilder.buildConstant(S32, 0);
8358 auto Zero64 = MIRBuilder.buildConstant(S64, 0);
8359
8360 auto LZ = MIRBuilder.buildCTLZ_ZERO_POISON(S32, Src);
8361
8362 auto K = MIRBuilder.buildConstant(S32, 127U + 63U);
8363 auto Sub = MIRBuilder.buildSub(S32, K, LZ);
8364
8365 auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);
8366 auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);
8367
8368 auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);
8369 auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);
8370
8371 auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);
8372
8373 auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);
8374 auto T = MIRBuilder.buildAnd(S64, U, Mask1);
8375
8376 auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));
8377 auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));
8378 auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));
8379
8380 auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);
8381 auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);
8382 auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);
8383 auto One = MIRBuilder.buildConstant(S32, 1);
8384
8385 auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);
8386 auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);
8387 auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);
8388 MIRBuilder.buildAdd(Dst, V, R);
8389
8390 MI.eraseFromParent();
8391 return Legalized;
8392}
8393
8394// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8395// operations and G_SITOFP
8398 auto [Dst, Src] = MI.getFirst2Regs();
8399 const LLT S64 = LLT::scalar(64);
8400 const LLT S32 = LLT::scalar(32);
8401 const LLT S1 = LLT::scalar(1);
8402
8403 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8404
8405 // For i64 < INT_MAX we simply reuse SITOFP.
8406 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8407 // saved before division, convert to float by SITOFP, multiply the result
8408 // by 2.
8409 auto One = MIRBuilder.buildConstant(S64, 1);
8410 auto Zero = MIRBuilder.buildConstant(S64, 0);
8411 // Result if Src < INT_MAX
8412 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8413 // Result if Src >= INT_MAX
8414 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8415 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8416 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8417 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8418 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8419 // Check if the original value is larger than INT_MAX by comparing with
8420 // zero to pick one of the two conversions.
8421 auto IsLarge =
8422 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
8423 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8424
8425 MI.eraseFromParent();
8426 return Legalized;
8427}
8428
8429// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8430// IEEE double representation.
8433 auto [Dst, Src] = MI.getFirst2Regs();
8434 const LLT S64 = LLT::scalar(64);
8435 const LLT S32 = LLT::scalar(32);
8436
8437 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8438
8439 // We create double value from 32 bit parts with 32 exponent difference.
8440 // Note that + and - are float operations that adjust the implicit leading
8441 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8442 //
8443 // X = 2^52 * 1.0...LowBits
8444 // Y = 2^84 * 1.0...HighBits
8445 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8446 // = - 2^52 * 1.0...HighBits
8447 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8448 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8449 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8450 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8451 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8452 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8453
8454 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8455 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8456 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8457 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8458 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8459 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8460 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8461
8462 MI.eraseFromParent();
8463 return Legalized;
8464}
8465
8466/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8467/// convert fpround f64->f16 without double-rounding, so we manually perform the
8468/// lowering here where we know it is valid.
8471 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8472 auto DstFpTy =
8473 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8474 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8475 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8476 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8477 LLT F32Ty = DstFpTy.changeElementSize(32);
8478 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8479 MIRBuilder.buildFPTrunc(Dst, M2);
8480 MI.eraseFromParent();
8482}
8483
8485 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8486
8487 if (SrcTy == LLT::scalar(1)) {
8488 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8489 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8490 MIRBuilder.buildSelect(Dst, Src, True, False);
8491 MI.eraseFromParent();
8492 return Legalized;
8493 }
8494
8495 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8496 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8497
8498 if (SrcTy != LLT::scalar(64))
8499 return UnableToLegalize;
8500
8501 if (DstTy == LLT::scalar(32))
8502 // TODO: SelectionDAG has several alternative expansions to port which may
8503 // be more reasonable depending on the available instructions. We also need
8504 // a more advanced mechanism to choose an optimal version depending on
8505 // target features such as sitofp or CTLZ availability.
8507
8508 if (DstTy == LLT::scalar(64))
8510
8511 return UnableToLegalize;
8512}
8513
8515 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8516
8517 const LLT I64 = LLT::integer(64);
8518 const LLT I32 = LLT::integer(32);
8519 const LLT I1 = LLT::integer(1);
8520
8521 if (SrcTy == I1) {
8522 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8523 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8524 MIRBuilder.buildSelect(Dst, Src, True, False);
8525 MI.eraseFromParent();
8526 return Legalized;
8527 }
8528
8529 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8530 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8531
8532 if (SrcTy != I64)
8533 return UnableToLegalize;
8534
8535 if (DstTy.getScalarSizeInBits() == 32) {
8536 // signed cl2f(long l) {
8537 // long s = l >> 63;
8538 // float r = cul2f((l + s) ^ s);
8539 // return s ? -r : r;
8540 // }
8541 Register L = Src;
8542 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8543 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8544
8545 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8546 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8547 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8548
8549 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8550 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8551 MIRBuilder.buildConstant(I64, 0));
8552 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8553 MI.eraseFromParent();
8554 return Legalized;
8555 }
8556
8557 return UnableToLegalize;
8558}
8559
8561 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8562 const LLT S64 = LLT::scalar(64);
8563 const LLT S32 = LLT::scalar(32);
8564
8565 if (SrcTy != S64 && SrcTy != S32)
8566 return UnableToLegalize;
8567 if (DstTy != S32 && DstTy != S64)
8568 return UnableToLegalize;
8569
8570 // FPTOSI gives same result as FPTOUI for positive signed integers.
8571 // FPTOUI needs to deal with fp values that convert to unsigned integers
8572 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8573
8574 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8575 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8577 APInt::getZero(SrcTy.getSizeInBits()));
8578 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8579
8580 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8581
8582 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8583 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8584 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8585 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8586 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8587 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8588 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8589
8590 const LLT S1 = LLT::scalar(1);
8591
8592 MachineInstrBuilder FCMP =
8593 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8594 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8595
8596 MI.eraseFromParent();
8597 return Legalized;
8598}
8599
8601 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8602 const LLT S64 = LLT::scalar(64);
8603 const LLT S32 = LLT::scalar(32);
8604
8605 // FIXME: Only f32 to i64 conversions are supported.
8606 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8607 return UnableToLegalize;
8608
8609 // Expand f32 -> i64 conversion
8610 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8611 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8612
8613 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8614
8615 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8616 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8617
8618 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8619 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8620
8621 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8622 APInt::getSignMask(SrcEltBits));
8623 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8624 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8625 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8626 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8627
8628 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8629 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8630 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8631
8632 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8633 R = MIRBuilder.buildZExt(DstTy, R);
8634
8635 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8636 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8637 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8638 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8639
8640 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8641 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8642
8643 const LLT S1 = LLT::scalar(1);
8644 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8645 S1, Exponent, ExponentLoBit);
8646
8647 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8648
8649 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8650 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8651
8652 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8653
8654 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8655 S1, Exponent, ZeroSrcTy);
8656
8657 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8658 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8659
8660 MI.eraseFromParent();
8661 return Legalized;
8662}
8663
8666 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8667
8668 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8669 unsigned SatWidth = DstTy.getScalarSizeInBits();
8670
8671 // Determine minimum and maximum integer values and their corresponding
8672 // floating-point values.
8673 APInt MinInt, MaxInt;
8674 if (IsSigned) {
8675 MinInt = APInt::getSignedMinValue(SatWidth);
8676 MaxInt = APInt::getSignedMaxValue(SatWidth);
8677 } else {
8678 MinInt = APInt::getMinValue(SatWidth);
8679 MaxInt = APInt::getMaxValue(SatWidth);
8680 }
8681
8682 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8683 APFloat MinFloat(Semantics);
8684 APFloat MaxFloat(Semantics);
8685
8686 APFloat::opStatus MinStatus =
8687 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8688 APFloat::opStatus MaxStatus =
8689 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8690 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8691 !(MaxStatus & APFloat::opStatus::opInexact);
8692
8693 // If the integer bounds are exactly representable as floats, emit a
8694 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8695 // and selects.
8696 if (AreExactFloatBounds) {
8697 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8698 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8699 auto MaxP =
8700 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8701 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8702 // Clamp by MaxFloat from above. NaN cannot occur.
8703 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8704 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8706 auto Min =
8707 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8708 // Convert clamped value to integer. In the unsigned case we're done,
8709 // because we mapped NaN to MinFloat, which will cast to zero.
8710 if (!IsSigned) {
8711 MIRBuilder.buildFPTOUI(Dst, Min);
8712 MI.eraseFromParent();
8713 return Legalized;
8714 }
8715
8716 // Otherwise, select 0 if Src is NaN.
8717 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8718 auto IsZero =
8719 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8720 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8721 FpToInt);
8722 MI.eraseFromParent();
8723 return Legalized;
8724 }
8725
8726 // Result of direct conversion. The assumption here is that the operation is
8727 // non-trapping and it's fine to apply it to an out-of-range value if we
8728 // select it away later.
8729 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8730 : MIRBuilder.buildFPTOUI(DstTy, Src);
8731
8732 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8733 // MinInt if Src is NaN.
8734 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8735 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8736 auto Max = MIRBuilder.buildSelect(
8737 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8738 // If Src OGT MaxFloat, select MaxInt.
8739 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8740 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8741
8742 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8743 // is already zero.
8744 if (!IsSigned) {
8745 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8746 Max);
8747 MI.eraseFromParent();
8748 return Legalized;
8749 }
8750
8751 // Otherwise, select 0 if Src is NaN.
8752 auto Min = MIRBuilder.buildSelect(
8753 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8754 auto IsZero =
8755 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8756 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8757 MI.eraseFromParent();
8758 return Legalized;
8759}
8760
8761// Floating-point conversions using truncating and extending loads and stores.
8764 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8765 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8766 "Only G_FPEXT and G_FPTRUNC are expected");
8767
8768 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8769 MachinePointerInfo PtrInfo;
8770 unsigned StoreOpc;
8771 unsigned LoadOpc;
8772 LLT StackTy;
8773 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8774 StackTy = SrcTy;
8775 StoreOpc = TargetOpcode::G_STORE;
8776 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8777 } else {
8778 StackTy = DstTy;
8779 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8780 LoadOpc = TargetOpcode::G_LOAD;
8781 }
8782
8783 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8784 auto StackTemp =
8785 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8786
8787 MachineFunction &MF = MIRBuilder.getMF();
8788 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8789 StackTy, StackTyAlign);
8790 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8791
8792 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8793 StackTy, StackTyAlign);
8794 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8795
8796 MI.eraseFromParent();
8797 return Legalized;
8798}
8799
8800// Expand a bf16 -> f32/f64 fpext with a shift and bitcast. This is based on the
8801// SDAG ISD::BF16_TO_FP lowering.
8804 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8805 assert(SrcTy.getScalarType().isBFloat16() &&
8806 "expected a bf16 source for bf16 fpext lowering");
8807
8808 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8809 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8810 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
8811
8812 auto SrcI =
8813 MIRBuilder.buildAnyExt(I32Ty, MIRBuilder.buildBitcast(I16Ty, SrcReg));
8814 auto Shl =
8815 MIRBuilder.buildShl(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8816
8817 if (DstTy.getScalarType().isFloat32())
8818 MIRBuilder.buildBitcast(DstReg, Shl);
8819 else
8820 MIRBuilder.buildFPExt(DstReg, MIRBuilder.buildBitcast(F32Ty, Shl));
8821
8822 MI.eraseFromParent();
8823 return Legalized;
8824}
8825
8827 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
8828 if (SrcTy.getScalarType().isBFloat16() &&
8829 (DstTy.getScalarType().isFloat32() || DstTy.getScalarType().isFloat64()))
8830 return lowerFPEXT_BF16(MI);
8831
8832 return lowerFPExtAndTruncMem(MI);
8833}
8834
8835// f64 -> f16 conversion using round-to-nearest-even rounding mode.
8838 const LLT S1 = LLT::scalar(1);
8839 const LLT I32 = LLT::integer(32);
8840
8841 auto [Dst, Src] = MI.getFirst2Regs();
8842 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
8843 MRI.getType(Src).getScalarType() == LLT::float64());
8844
8845 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
8846 return UnableToLegalize;
8847
8848 if (MI.getFlag(MachineInstr::FmAfn)) {
8849 unsigned Flags = MI.getFlags();
8850 auto Src32 = MIRBuilder.buildFPTrunc(LLT::float32(), Src, Flags);
8851 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
8852 MI.eraseFromParent();
8853 return Legalized;
8854 }
8855
8856 const unsigned ExpMask = 0x7ff;
8857 const unsigned ExpBiasf64 = 1023;
8858 const unsigned ExpBiasf16 = 15;
8859
8860 auto Unmerge = MIRBuilder.buildUnmerge(I32, Src);
8861 Register U = Unmerge.getReg(0);
8862 Register UH = Unmerge.getReg(1);
8863
8864 auto E = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 20));
8865 E = MIRBuilder.buildAnd(I32, E, MIRBuilder.buildConstant(I32, ExpMask));
8866
8867 // Subtract the fp64 exponent bias (1023) to get the real exponent and
8868 // add the f16 bias (15) to get the biased exponent for the f16 format.
8869 E = MIRBuilder.buildAdd(
8870 I32, E, MIRBuilder.buildConstant(I32, -ExpBiasf64 + ExpBiasf16));
8871
8872 auto M = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 8));
8873 M = MIRBuilder.buildAnd(I32, M, MIRBuilder.buildConstant(I32, 0xffe));
8874
8875 auto MaskedSig =
8876 MIRBuilder.buildAnd(I32, UH, MIRBuilder.buildConstant(I32, 0x1ff));
8877 MaskedSig = MIRBuilder.buildOr(I32, MaskedSig, U);
8878
8879 auto Zero = MIRBuilder.buildConstant(I32, 0);
8880 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
8881 auto Lo40Set = MIRBuilder.buildZExt(I32, SigCmpNE0);
8882 M = MIRBuilder.buildOr(I32, M, Lo40Set);
8883
8884 // (M != 0 ? 0x0200 : 0) | 0x7c00;
8885 auto Bits0x200 = MIRBuilder.buildConstant(I32, 0x0200);
8886 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
8887 auto SelectCC = MIRBuilder.buildSelect(I32, CmpM_NE0, Bits0x200, Zero);
8888
8889 auto Bits0x7c00 = MIRBuilder.buildConstant(I32, 0x7c00);
8890 auto I = MIRBuilder.buildOr(I32, SelectCC, Bits0x7c00);
8891
8892 // N = M | (E << 12);
8893 auto EShl12 = MIRBuilder.buildShl(I32, E, MIRBuilder.buildConstant(I32, 12));
8894 auto N = MIRBuilder.buildOr(I32, M, EShl12);
8895
8896 // B = clamp(1-E, 0, 13);
8897 auto One = MIRBuilder.buildConstant(I32, 1);
8898 auto OneSubExp = MIRBuilder.buildSub(I32, One, E);
8899 auto B = MIRBuilder.buildSMax(I32, OneSubExp, Zero);
8900 B = MIRBuilder.buildSMin(I32, B, MIRBuilder.buildConstant(I32, 13));
8901
8902 auto SigSetHigh =
8903 MIRBuilder.buildOr(I32, M, MIRBuilder.buildConstant(I32, 0x1000));
8904
8905 auto D = MIRBuilder.buildLShr(I32, SigSetHigh, B);
8906 auto D0 = MIRBuilder.buildShl(I32, D, B);
8907
8908 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
8909 D0, SigSetHigh);
8910 auto D1 = MIRBuilder.buildZExt(I32, D0_NE_SigSetHigh);
8911 D = MIRBuilder.buildOr(I32, D, D1);
8912
8913 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
8914 auto V = MIRBuilder.buildSelect(I32, CmpELtOne, D, N);
8915
8916 auto VLow3 = MIRBuilder.buildAnd(I32, V, MIRBuilder.buildConstant(I32, 7));
8917 V = MIRBuilder.buildLShr(I32, V, MIRBuilder.buildConstant(I32, 2));
8918
8919 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
8920 MIRBuilder.buildConstant(I32, 3));
8921 auto V0 = MIRBuilder.buildZExt(I32, VLow3Eq3);
8922
8923 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
8924 MIRBuilder.buildConstant(I32, 5));
8925 auto V1 = MIRBuilder.buildZExt(I32, VLow3Gt5);
8926
8927 V1 = MIRBuilder.buildOr(I32, V0, V1);
8928 V = MIRBuilder.buildAdd(I32, V, V1);
8929
8930 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, E,
8931 MIRBuilder.buildConstant(I32, 30));
8932 V = MIRBuilder.buildSelect(I32, CmpEGt30,
8933 MIRBuilder.buildConstant(I32, 0x7c00), V);
8934
8935 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, E,
8936 MIRBuilder.buildConstant(I32, 1039));
8937 V = MIRBuilder.buildSelect(I32, CmpEGt1039, I, V);
8938
8939 // Extract the sign bit.
8940 auto Sign = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 16));
8941 Sign = MIRBuilder.buildAnd(I32, Sign, MIRBuilder.buildConstant(I32, 0x8000));
8942
8943 // Insert the sign bit
8944 V = MIRBuilder.buildOr(I32, Sign, V);
8945
8946 MIRBuilder.buildTrunc(Dst, V);
8947 MI.eraseFromParent();
8948 return Legalized;
8949}
8950
8951// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
8954 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8955 assert(DstTy.getScalarType() == LLT::bfloat16() &&
8956 SrcTy.getScalarType() == LLT::float32());
8957
8958 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
8959 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8960 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8961
8962 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
8963
8964 // Conversions should set NaN's quiet bit. This also prevents NaNs from
8965 // turning into infinities.
8966 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
8967 MIRBuilder.buildConstant(I32Ty, 0x400000));
8968
8969 // Factor in the contribution of the low 16 bits.
8970 auto Lsb =
8971 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8972 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
8973 auto RoundingBias =
8974 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
8975 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
8976
8977 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
8978 // 0x80000000.
8979 if (!MI.getFlag(MachineInstr::FmNoNans)) {
8980 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
8981 MIRBuilder.buildFConstant(SrcTy, 0));
8982 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
8983 }
8984
8985 // Now that we have rounded, shift the bits into position.
8986 auto Srl =
8987 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
8988 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
8989 MIRBuilder.buildBitcast(DstReg, Trunc);
8990 MI.eraseFromParent();
8991 return Legalized;
8992}
8993
8994// Round a wide fp value to ResultTy's element size, forcing inexact
8995// results to the odd value so a subsequent narrowing round is correct. This
8996// avoids double-rounding when narrowing e.g. f64 -> f32 -> bf16. See Boldo &
8997// Melquiond, "When double rounding is odd" (2005).
8999 LLT OperandTy = MRI.getType(Op);
9000 if (OperandTy.getScalarType() == ResultTy.getScalarType())
9001 return Op;
9002
9003 LLT ResultIntTy =
9005 LLT ResultCCTy = ResultTy.changeElementType(LLT::integer(1));
9006 LLT OperandCCTy = OperandTy.changeElementType(LLT::integer(1));
9007
9008 auto Narrow = MIRBuilder.buildFPTrunc(ResultTy, Op);
9009 auto NarrowAsWide = MIRBuilder.buildFPExt(OperandTy, Narrow);
9010
9011 auto NarrowBits = MIRBuilder.buildBitcast(ResultIntTy, Narrow);
9012 auto One = MIRBuilder.buildConstant(ResultIntTy, 1);
9013 auto NegativeOne = MIRBuilder.buildConstant(ResultIntTy, -1);
9014 auto Zero = MIRBuilder.buildConstant(ResultIntTy, 0);
9015 auto And = MIRBuilder.buildAnd(ResultIntTy, NarrowBits, One);
9016 // The result is already odd so we don't need to do anything.
9017 auto AlreadyOdd =
9018 MIRBuilder.buildICmp(CmpInst::ICMP_NE, ResultCCTy, And, Zero);
9019
9020 // We keep results which are exact, odd or NaN.
9021 auto KeepNarrow =
9022 MIRBuilder.buildFCmp(CmpInst::FCMP_UEQ, OperandCCTy, Op, NarrowAsWide);
9023 KeepNarrow = MIRBuilder.buildOr(OperandCCTy, KeepNarrow, AlreadyOdd);
9024 // We morally performed a round-down if AbsNarrow is smaller than AbsWide.
9025 auto AbsWide = MIRBuilder.buildFAbs(OperandTy, Op);
9026 auto AbsNarrowAsWide = MIRBuilder.buildFAbs(OperandTy, NarrowAsWide);
9027 auto NarrowIsRd = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, OperandCCTy,
9028 AbsWide, AbsNarrowAsWide);
9029 // If narrow is the rounded-down value, pick the rounded-up value as it will
9030 // be odd; otherwise adjust down.
9031 auto Adjust =
9032 MIRBuilder.buildSelect(ResultIntTy, NarrowIsRd, One, NegativeOne);
9033 auto Adjusted = MIRBuilder.buildAdd(ResultIntTy, NarrowBits, Adjust);
9034 auto Res =
9035 MIRBuilder.buildSelect(ResultIntTy, KeepNarrow, NarrowBits, Adjusted);
9036 return MIRBuilder.buildBitcast(ResultTy, Res).getReg(0);
9037}
9038
9039// f64 -> bf16 conversion, correcting for double rounding.
9042 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9043 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9044 SrcTy.getScalarType() == LLT::float64());
9045
9046 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
9047 Register OddF32 = lowerRoundInexactToOdd(F32Ty, SrcReg);
9048 MIRBuilder.buildFPTrunc(DstReg, OddF32, MI.getFlags());
9049 MI.eraseFromParent();
9050 return Legalized;
9051}
9052
9055 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9056 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
9058
9059 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
9061
9062 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat64())
9064
9065 return lowerFPExtAndTruncMem(MI);
9066}
9067
9069 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9070 LLT Ty = MRI.getType(Dst);
9071
9072 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
9073 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
9074 MI.eraseFromParent();
9075 return Legalized;
9076}
9077
9079 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
9080 LLT Ty = MRI.getType(Src);
9081 auto Flags = MI.getFlags();
9082 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9083
9084 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
9085 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
9086
9087 Register FracToUse;
9088 if (MI.getFlag(MachineInstr::FmNoInfs)) {
9089 FracToUse = FracPart.getReg(0);
9090 } else {
9091 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
9092 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
9093 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
9094 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
9095 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9096 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
9097 FracToUse = Select.getReg(0);
9098 }
9099
9100 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
9101 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
9102
9103 MI.eraseFromParent();
9104 return Legalized;
9105}
9106
9108 switch (Opc) {
9109 case TargetOpcode::G_SMIN:
9110 return CmpInst::ICMP_SLT;
9111 case TargetOpcode::G_SMAX:
9112 return CmpInst::ICMP_SGT;
9113 case TargetOpcode::G_UMIN:
9114 return CmpInst::ICMP_ULT;
9115 case TargetOpcode::G_UMAX:
9116 return CmpInst::ICMP_UGT;
9117 default:
9118 llvm_unreachable("not in integer min/max");
9119 }
9120}
9121
9123 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9124
9125 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9126 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9127
9128 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9129 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9130
9131 MI.eraseFromParent();
9132 return Legalized;
9133}
9134
9137 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9138
9139 Register Dst = Cmp->getReg(0);
9140 LLT DstTy = MRI.getType(Dst);
9141 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9142 LLT CmpTy = DstTy.changeElementSize(1);
9143
9144 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9147 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9150
9151 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9152 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9153 Cmp->getRHSReg());
9154 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9155 Cmp->getRHSReg());
9156
9157 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9158 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9159 if (TLI.preferSelectsOverBooleanArithmetic(
9160 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9162 auto One = MIRBuilder.buildConstant(DstTy, 1);
9163 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9164
9165 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9166 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9167 } else {
9169 std::swap(IsGT, IsLT);
9170 // Extend boolean results to DstTy, which is at least i2, before subtracting
9171 // them.
9172 unsigned BoolExtOp =
9173 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9174 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9175 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9176 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9177 }
9178
9179 MI.eraseFromParent();
9180 return Legalized;
9181}
9182
9185 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9186 const int Src0Size = Src0Ty.getScalarSizeInBits();
9187 const int Src1Size = Src1Ty.getScalarSizeInBits();
9188
9189 LLT DstIntTy =
9190 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9191 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9192 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9193
9194 Register Src0Int = Src0;
9195 Register Src1Int = Src1;
9196
9197 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9198 Src0Ty.getScalarType().isInteger()))
9199 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9200
9201 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9202 Src1Ty.getScalarType().isInteger()))
9203 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9204
9205 auto SignBitMask =
9206 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9207
9208 auto NotSignBitMask = MIRBuilder.buildConstant(
9209 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9210
9211 Register And0 =
9212 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9213 Register And1;
9214 if (Src0Ty == Src1Ty) {
9215 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9216 } else if (Src0Size > Src1Size) {
9217 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9218 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9219 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9220 And1 = MIRBuilder.buildAnd(Src0Ty, Shift, SignBitMask).getReg(0);
9221 } else {
9222 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9223 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9224 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9225 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9226 }
9227
9228 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9229 // constants are a nan and -0.0, but the final result should preserve
9230 // everything.
9231 unsigned Flags = MI.getFlags();
9232
9233 // We masked the sign bit and the not-sign bit, so these are disjoint.
9234 Flags |= MachineInstr::Disjoint;
9235
9236 if (DstTy == DstIntTy)
9237 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9238 else {
9239 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9240 MIRBuilder.buildBitcast(Dst, NewDst);
9241 }
9242
9243 MI.eraseFromParent();
9244 return Legalized;
9245}
9246
9249 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9250 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9251 // depend on fminnum/fmaxnum.
9252
9253 unsigned NewOp;
9254 switch (MI.getOpcode()) {
9255 case TargetOpcode::G_FMINNUM:
9256 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9257 break;
9258 case TargetOpcode::G_FMINIMUMNUM:
9259 NewOp = TargetOpcode::G_FMINNUM;
9260 break;
9261 case TargetOpcode::G_FMAXNUM:
9262 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9263 break;
9264 case TargetOpcode::G_FMAXIMUMNUM:
9265 NewOp = TargetOpcode::G_FMAXNUM;
9266 break;
9267 default:
9268 llvm_unreachable("unexpected min/max opcode");
9269 }
9270
9271 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9272 LLT Ty = MRI.getType(Dst);
9273
9274 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9275 // Insert canonicalizes if it's possible we need to quiet to get correct
9276 // sNaN behavior.
9277
9278 // Note this must be done here, and not as an optimization combine in the
9279 // absence of a dedicate quiet-snan instruction as we're using an
9280 // omni-purpose G_FCANONICALIZE.
9281 if (!VT->isKnownNeverSNaN(Src0))
9282 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9283
9284 if (!VT->isKnownNeverSNaN(Src1))
9285 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9286 }
9287
9288 // If there are no nans, it's safe to simply replace this with the non-IEEE
9289 // version.
9290 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9291 MI.eraseFromParent();
9292 return Legalized;
9293}
9294
9297 unsigned Opc = MI.getOpcode();
9298 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9299 LLT Ty = MRI.getType(Dst);
9300 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9301
9302 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9303 unsigned OpcIeee =
9304 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9305 unsigned OpcNonIeee =
9306 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9307 bool MinMaxMustRespectOrderedZero = false;
9308 Register Res;
9309
9310 // IEEE variants don't need canonicalization
9311 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9312 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9313 MinMaxMustRespectOrderedZero = true;
9314 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9315 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9316 } else {
9317 auto Compare = MIRBuilder.buildFCmp(
9318 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9319 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9320 }
9321
9322 // Propagate any NaN of both operands
9323 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9324 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9325 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9326
9327 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9328 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9329 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9330 if (Ty.isVector())
9331 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9332
9333 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9334 }
9335
9336 // fminimum/fmaximum requires -0.0 less than +0.0
9337 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9338 GISelValueTracking VT(MIRBuilder.getMF());
9339 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9340 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9341
9342 if (!Src0Info.isKnownNeverZero() && !Src1Info.isKnownNeverZero()) {
9343 const unsigned Flags = MI.getFlags();
9344 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9345 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9346
9347 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9348
9349 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9350 auto LHSSelect =
9351 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9352
9353 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9354 auto RHSSelect =
9355 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9356
9357 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9358 }
9359 }
9360
9361 MIRBuilder.buildCopy(Dst, Res);
9362 MI.eraseFromParent();
9363 return Legalized;
9364}
9365
9367 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9368 Register DstReg = MI.getOperand(0).getReg();
9369 LLT Ty = MRI.getType(DstReg);
9370 unsigned Flags = MI.getFlags();
9371
9372 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9373 Flags);
9374 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9375 MI.eraseFromParent();
9376 return Legalized;
9377}
9378
9381 auto [DstReg, X] = MI.getFirst2Regs();
9382 const unsigned Flags = MI.getFlags();
9383 const LLT Ty = MRI.getType(DstReg);
9384 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9385
9386 // round(x) =>
9387 // t = trunc(x);
9388 // d = fabs(x - t);
9389 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9390 // return t + o;
9391
9392 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9393
9394 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9395 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9396
9397 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9398 auto Cmp =
9399 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9400
9401 // Could emit G_UITOFP instead
9402 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9403 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9404 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9405 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9406
9407 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9408
9409 MI.eraseFromParent();
9410 return Legalized;
9411}
9412
9414 auto [DstReg, SrcReg] = MI.getFirst2Regs();
9415 unsigned Flags = MI.getFlags();
9416 LLT Ty = MRI.getType(DstReg);
9417 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9418
9419 // result = trunc(src);
9420 // if (src < 0.0 && src != result)
9421 // result += -1.0.
9422
9423 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
9424 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9425
9426 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
9427 SrcReg, Zero, Flags);
9428 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
9429 SrcReg, Trunc, Flags);
9430 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
9431 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
9432
9433 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
9434 MI.eraseFromParent();
9435 return Legalized;
9436}
9437
9440 const unsigned NumOps = MI.getNumOperands();
9441 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
9442 unsigned PartSize = Src0Ty.getSizeInBits();
9443
9444 LLT WideTy = LLT::integer(DstTy.getSizeInBits());
9445 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
9446
9447 for (unsigned I = 2; I != NumOps; ++I) {
9448 const unsigned Offset = (I - 1) * PartSize;
9449
9450 Register SrcReg = MI.getOperand(I).getReg();
9451 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
9452
9453 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
9454 MRI.createGenericVirtualRegister(WideTy);
9455
9456 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
9457 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
9458 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
9459 ResultReg = NextResult;
9460 }
9461
9462 if (DstTy.isPointer()) {
9463 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
9464 DstTy.getAddressSpace())) {
9465 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
9466 return UnableToLegalize;
9467 }
9468
9469 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9470 } else if (WideTy != DstTy) {
9471 MIRBuilder.buildBitcast(DstReg, ResultReg);
9472 }
9473
9474 MI.eraseFromParent();
9475 return Legalized;
9476}
9477
9480 const unsigned NumDst = MI.getNumOperands() - 1;
9481 Register SrcReg = MI.getOperand(NumDst).getReg();
9482 Register Dst0Reg = MI.getOperand(0).getReg();
9483 LLT DstTy = MRI.getType(Dst0Reg);
9484 if (DstTy.isPointer())
9485 return UnableToLegalize; // TODO
9486
9487 SrcReg = coerceToInteger(SrcReg);
9488 if (!SrcReg)
9489 return UnableToLegalize;
9490
9491 // Expand scalarizing unmerge as bitcast to integer and shift.
9492 LLT IntTy = MRI.getType(SrcReg);
9493
9494 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
9495
9496 const unsigned DstSize = DstTy.getSizeInBits();
9497 unsigned Offset = DstSize;
9498 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
9499 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
9500 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
9501 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
9502 }
9503
9504 MI.eraseFromParent();
9505 return Legalized;
9506}
9507
9508/// Lower a vector extract or insert by writing the vector to a stack temporary
9509/// and reloading the element or vector.
9510///
9511/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
9512/// =>
9513/// %stack_temp = G_FRAME_INDEX
9514/// G_STORE %vec, %stack_temp
9515/// %idx = clamp(%idx, %vec.getNumElements())
9516/// %element_ptr = G_PTR_ADD %stack_temp, %idx
9517/// %dst = G_LOAD %element_ptr
9520 Register DstReg = MI.getOperand(0).getReg();
9521 Register SrcVec = MI.getOperand(1).getReg();
9522 Register InsertVal;
9523 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
9524 InsertVal = MI.getOperand(2).getReg();
9525
9526 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
9527
9528 LLT VecTy = MRI.getType(SrcVec);
9529 LLT EltTy = VecTy.getElementType();
9530 unsigned NumElts = VecTy.getNumElements();
9531
9532 int64_t IdxVal;
9533 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
9535 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
9536
9537 if (InsertVal) {
9538 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
9539 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
9540 } else {
9541 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
9542 }
9543
9544 MI.eraseFromParent();
9545 return Legalized;
9546 }
9547
9548 if (!EltTy.isByteSized()) { // Not implemented.
9549 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
9550 return UnableToLegalize;
9551 }
9552
9553 unsigned EltBytes = EltTy.getSizeInBytes();
9554 Align VecAlign = getStackTemporaryAlignment(VecTy);
9555 Align EltAlign;
9556
9557 MachinePointerInfo PtrInfo;
9558 auto StackTemp = createStackTemporary(
9559 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
9560 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
9561
9562 // Get the pointer to the element, and be sure not to hit undefined behavior
9563 // if the index is out of bounds.
9564 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
9565
9566 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
9567 int64_t Offset = IdxVal * EltBytes;
9568 PtrInfo = PtrInfo.getWithOffset(Offset);
9569 EltAlign = commonAlignment(VecAlign, Offset);
9570 } else {
9571 // We lose information with a variable offset.
9572 EltAlign = getStackTemporaryAlignment(EltTy);
9573 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
9574 }
9575
9576 if (InsertVal) {
9577 // Write the inserted element
9578 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
9579
9580 // Reload the whole vector.
9581 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
9582 } else {
9583 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
9584 }
9585
9586 MI.eraseFromParent();
9587 return Legalized;
9588}
9589
9592 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
9593 MI.getFirst3RegLLTs();
9594 LLT IdxTy = LLT::scalar(32);
9595
9596 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
9599 LLT EltTy = DstTy.getScalarType();
9600
9601 DenseMap<unsigned, Register> CachedExtract;
9602
9603 for (int Idx : Mask) {
9604 if (Idx < 0) {
9605 if (!Undef.isValid())
9606 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
9607 BuildVec.push_back(Undef);
9608 continue;
9609 }
9610
9611 assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");
9612
9613 int NumElts = Src0Ty.getNumElements();
9614 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
9615 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
9616 auto [It, Inserted] = CachedExtract.try_emplace(Idx);
9617 if (Inserted) {
9618 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
9619 It->second =
9620 MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);
9621 }
9622 BuildVec.push_back(It->second);
9623 }
9624
9625 assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");
9626 MIRBuilder.buildBuildVector(DstReg, BuildVec);
9627 MI.eraseFromParent();
9628 return Legalized;
9629}
9630
9633 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
9634 MI.getFirst4RegLLTs();
9635
9636 if (VecTy.isScalableVector())
9637 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
9638
9639 Align VecAlign = getStackTemporaryAlignment(VecTy);
9640 MachinePointerInfo PtrInfo;
9641 Register StackPtr =
9642 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
9643 PtrInfo)
9644 .getReg(0);
9645 MachinePointerInfo ValPtrInfo =
9647
9648 LLT IdxTy = LLT::scalar(32);
9649 LLT ValTy = VecTy.getElementType();
9650 Align ValAlign = getStackTemporaryAlignment(ValTy);
9651
9652 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
9653
9654 bool HasPassthru =
9655 MRI.getVRegDef(Passthru)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF;
9656
9657 if (HasPassthru)
9658 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
9659
9660 Register LastWriteVal;
9661 std::optional<APInt> PassthruSplatVal =
9662 isConstantOrConstantSplatVector(Passthru, MRI);
9663
9664 if (PassthruSplatVal.has_value()) {
9665 LastWriteVal =
9666 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
9667 } else if (HasPassthru) {
9668 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
9669 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
9670 {LLT::scalar(32)}, {Popcount});
9671
9672 Register LastElmtPtr =
9673 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
9674 LastWriteVal =
9675 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
9676 .getReg(0);
9677 }
9678
9679 unsigned NumElmts = VecTy.getNumElements();
9680 for (unsigned I = 0; I < NumElmts; ++I) {
9681 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
9682 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
9683 Register ElmtPtr =
9684 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9685 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
9686
9687 LLT MaskITy = MaskTy.getElementType();
9688 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
9689 if (MaskITy.getSizeInBits() > 1)
9690 MaskI = MIRBuilder.buildTrunc(LLT::scalar(1), MaskI);
9691
9692 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
9693 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
9694
9695 if (HasPassthru && I == NumElmts - 1) {
9696 auto EndOfVector =
9697 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
9698 auto AllLanesSelected = MIRBuilder.buildICmp(
9699 CmpInst::ICMP_UGT, LLT::scalar(1), OutPos, EndOfVector);
9700 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
9701 {OutPos, EndOfVector});
9702 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9703
9704 LastWriteVal =
9705 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
9706 .getReg(0);
9707 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
9708 }
9709 }
9710
9711 // TODO: Use StackPtr's FrameIndex alignment.
9712 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
9713
9714 MI.eraseFromParent();
9715 return Legalized;
9716}
9717
9719 Register AllocSize,
9720 Align Alignment,
9721 LLT PtrTy) {
9723
9724 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
9725 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
9726
9727 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
9728 // have to generate an extra instruction to negate the alloc and then use
9729 // G_PTR_ADD to add the negative offset.
9730 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
9731 if (Alignment > Align(1)) {
9732 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
9733 AlignMask.negate();
9734 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
9735 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
9736 }
9737
9738 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
9739}
9740
9743 const auto &MF = *MI.getMF();
9744 const auto &TFI = *MF.getSubtarget().getFrameLowering();
9745 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
9746 return UnableToLegalize;
9747
9748 Register Dst = MI.getOperand(0).getReg();
9749 Register AllocSize = MI.getOperand(1).getReg();
9750 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
9751
9752 LLT PtrTy = MRI.getType(Dst);
9753 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
9754 Register SPTmp =
9755 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
9756
9757 MIRBuilder.buildCopy(SPReg, SPTmp);
9758 MIRBuilder.buildCopy(Dst, SPTmp);
9759
9760 MI.eraseFromParent();
9761 return Legalized;
9762}
9763
9766 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9767 if (!StackPtr)
9768 return UnableToLegalize;
9769
9770 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
9771 MI.eraseFromParent();
9772 return Legalized;
9773}
9774
9777 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9778 if (!StackPtr)
9779 return UnableToLegalize;
9780
9781 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
9782 MI.eraseFromParent();
9783 return Legalized;
9784}
9785
9788 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9789 unsigned Offset = MI.getOperand(2).getImm();
9790
9791 // Extract sub-vector or one element
9792 if (SrcTy.isVector()) {
9793 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
9794 unsigned DstSize = DstTy.getSizeInBits();
9795
9796 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
9797 (Offset + DstSize <= SrcTy.getSizeInBits())) {
9798 // Unmerge and allow access to each Src element for the artifact combiner.
9799 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
9800
9801 // Take element(s) we need to extract and copy it (merge them).
9802 SmallVector<Register, 8> SubVectorElts;
9803 for (unsigned Idx = Offset / SrcEltSize;
9804 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
9805 SubVectorElts.push_back(Unmerge.getReg(Idx));
9806 }
9807 if (SubVectorElts.size() == 1)
9808 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
9809 else
9810 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
9811
9812 MI.eraseFromParent();
9813 return Legalized;
9814 }
9815 }
9816
9817 const DataLayout &DL = MIRBuilder.getDataLayout();
9818 if ((SrcTy.isPointer() &&
9819 DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) ||
9820 (DstTy.isPointer() &&
9821 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace()))) {
9822 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9823 return UnableToLegalize;
9824 }
9825
9826 if ((DstTy.isScalar() || DstTy.isPointer()) &&
9827 (SrcTy.isScalar() || SrcTy.isPointer() ||
9828 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
9829 LLT SrcIntTy = SrcTy;
9830 if (!SrcTy.isScalar()) {
9831 SrcIntTy = LLT::scalar(SrcTy.getSizeInBits());
9832 SrcReg = MIRBuilder.buildCast(SrcIntTy, SrcReg).getReg(0);
9833 }
9834
9835 Register ResultReg = DstReg;
9836 if (DstTy.isPointer())
9837 ResultReg =
9838 MRI.createGenericVirtualRegister(LLT::integer(DstTy.getSizeInBits()));
9839
9840 if (Offset == 0)
9841 MIRBuilder.buildTrunc(ResultReg, SrcReg);
9842 else {
9843 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
9844 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
9845 MIRBuilder.buildTrunc(ResultReg, Shr);
9846 }
9847
9848 if (DstTy.isPointer())
9849 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9850
9851 MI.eraseFromParent();
9852 return Legalized;
9853 }
9854
9855 return UnableToLegalize;
9856}
9857
9859 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
9860 uint64_t Offset = MI.getOperand(3).getImm();
9861
9862 LLT DstTy = MRI.getType(Src);
9863 LLT InsertTy = MRI.getType(InsertSrc);
9864
9865 const DataLayout &DL = MIRBuilder.getDataLayout();
9866 bool IsNonIntegralInsert =
9867 InsertTy.isPointerOrPointerVector() &&
9868 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace());
9869 bool IsNonIntegralDst = DstTy.isPointerOrPointerVector() &&
9870 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace());
9871
9872 // Insert sub-vector or one element
9873 if (DstTy.isVector()) {
9874 LLT EltTy = DstTy.getElementType();
9875
9876 if ((IsNonIntegralInsert || IsNonIntegralDst) && InsertTy != EltTy) {
9877 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9878 return UnableToLegalize;
9879 }
9880
9881 unsigned EltSize = EltTy.getSizeInBits();
9882 unsigned InsertSize = InsertTy.getSizeInBits();
9883
9884 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
9885 (Offset + InsertSize <= DstTy.getSizeInBits())) {
9886 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
9888 unsigned Idx = 0;
9889 // Elements from Src before insert start Offset
9890 for (; Idx < Offset / EltSize; ++Idx) {
9891 DstElts.push_back(UnmergeSrc.getReg(Idx));
9892 }
9893
9894 // Replace elements in Src with elements from InsertSrc
9895 if (InsertTy.getSizeInBits() > EltSize) {
9896 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
9897 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
9898 ++Idx, ++i) {
9899 DstElts.push_back(UnmergeInsertSrc.getReg(i));
9900 }
9901 } else {
9902 if (InsertTy.isPointer() && !EltTy.isPointer())
9903 InsertSrc = MIRBuilder.buildPtrToInt(EltTy, InsertSrc).getReg(0);
9904 else if (!InsertTy.isPointer() && EltTy.isPointer())
9905 InsertSrc = MIRBuilder.buildIntToPtr(EltTy, InsertSrc).getReg(0);
9906 DstElts.push_back(InsertSrc);
9907 ++Idx;
9908 }
9909
9910 // Remaining elements from Src after insert
9911 for (; Idx < DstTy.getNumElements(); ++Idx) {
9912 DstElts.push_back(UnmergeSrc.getReg(Idx));
9913 }
9914
9915 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
9916 MI.eraseFromParent();
9917 return Legalized;
9918 }
9919 }
9920
9921 if (InsertTy.isVector() ||
9922 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
9923 return UnableToLegalize;
9924
9925 if (IsNonIntegralDst || IsNonIntegralInsert) {
9926 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9927 return UnableToLegalize;
9928 }
9929
9930 LLT IntDstTy = DstTy;
9931
9932 if (!DstTy.isScalar()) {
9933 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
9934 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
9935 }
9936
9937 if (!InsertTy.isScalar()) {
9938 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
9939 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
9940 }
9941
9942 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
9943 if (Offset != 0) {
9944 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
9945 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
9946 }
9947
9949 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
9950
9951 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
9952 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
9953 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
9954
9955 MIRBuilder.buildCast(Dst, Or);
9956 MI.eraseFromParent();
9957 return Legalized;
9958}
9959
9962 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
9963 MI.getFirst4RegLLTs();
9964 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
9965
9966 LLT Ty = Dst0Ty;
9967 LLT BoolTy = Dst1Ty;
9968
9969 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
9970
9971 if (IsAdd)
9972 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
9973 else
9974 MIRBuilder.buildSub(NewDst0, LHS, RHS);
9975
9976 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
9977
9978 auto Zero = MIRBuilder.buildConstant(Ty, 0);
9979
9980 if (IsAdd) {
9981 // For an addition, the result should be less than one of the operands (LHS)
9982 // if and only if the other operand (RHS) is negative, otherwise there will
9983 // be overflow.
9984 auto ResultLowerThanLHS =
9985 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
9986 auto RHSNegative =
9987 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
9988 MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
9989 } else {
9990 // For subtraction, overflow occurs when the signed comparison of operands
9991 // doesn't match the sign of the result.
9992 auto LHSLessThanRHS =
9993 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
9994 auto ResultNegative =
9995 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
9996 MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
9997 }
9998
9999 MIRBuilder.buildCopy(Dst0, NewDst0);
10000 MI.eraseFromParent();
10001
10002 return Legalized;
10003}
10004
10006 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10007 const LLT Ty = MRI.getType(Res);
10008
10009 // sum = LHS + RHS + zext(CarryIn)
10010 auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);
10011 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10012 auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);
10013 MIRBuilder.buildCopy(Res, Sum);
10014
10015 // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 0
10016 auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);
10017 auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);
10018 auto T = MIRBuilder.buildAnd(Ty, AX, BX);
10019
10020 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10021 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10022
10023 MI.eraseFromParent();
10024 return Legalized;
10025}
10026
10028 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10029 const LLT Ty = MRI.getType(Res);
10030
10031 // Diff = LHS - (RHS + zext(CarryIn))
10032 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10033 auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
10034 auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);
10035 MIRBuilder.buildCopy(Res, Diff);
10036
10037 // ov = msb((LHS ^ RHS) & (LHS ^ Diff))
10038 auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);
10039 auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);
10040 auto T = MIRBuilder.buildAnd(Ty, X1, X2);
10041 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10042 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10043
10044 MI.eraseFromParent();
10045 return Legalized;
10046}
10047
10050 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10051 LLT Ty = MRI.getType(Res);
10052 bool IsSigned;
10053 bool IsAdd;
10054 unsigned BaseOp;
10055 switch (MI.getOpcode()) {
10056 default:
10057 llvm_unreachable("unexpected addsat/subsat opcode");
10058 case TargetOpcode::G_UADDSAT:
10059 IsSigned = false;
10060 IsAdd = true;
10061 BaseOp = TargetOpcode::G_ADD;
10062 break;
10063 case TargetOpcode::G_SADDSAT:
10064 IsSigned = true;
10065 IsAdd = true;
10066 BaseOp = TargetOpcode::G_ADD;
10067 break;
10068 case TargetOpcode::G_USUBSAT:
10069 IsSigned = false;
10070 IsAdd = false;
10071 BaseOp = TargetOpcode::G_SUB;
10072 break;
10073 case TargetOpcode::G_SSUBSAT:
10074 IsSigned = true;
10075 IsAdd = false;
10076 BaseOp = TargetOpcode::G_SUB;
10077 break;
10078 }
10079
10080 if (IsSigned) {
10081 // sadd.sat(a, b) ->
10082 // hi = 0x7fffffff - smax(a, 0)
10083 // lo = 0x80000000 - smin(a, 0)
10084 // a + smin(smax(lo, b), hi)
10085 // ssub.sat(a, b) ->
10086 // lo = smax(a, -1) - 0x7fffffff
10087 // hi = smin(a, -1) - 0x80000000
10088 // a - smin(smax(lo, b), hi)
10089 // TODO: AMDGPU can use a "median of 3" instruction here:
10090 // a +/- med3(lo, b, hi)
10091 uint64_t NumBits = Ty.getScalarSizeInBits();
10092 auto MaxVal =
10093 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
10094 auto MinVal =
10095 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10097 if (IsAdd) {
10098 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10099 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
10100 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
10101 } else {
10102 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
10103 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
10104 MaxVal);
10105 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
10106 MinVal);
10107 }
10108 auto RHSClamped =
10109 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
10110 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
10111 } else {
10112 // uadd.sat(a, b) -> a + umin(~a, b)
10113 // usub.sat(a, b) -> a - umin(a, b)
10114 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
10115 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
10116 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
10117 }
10118
10119 MI.eraseFromParent();
10120 return Legalized;
10121}
10122
10125 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10126 LLT Ty = MRI.getType(Res);
10127 LLT BoolTy = Ty.changeElementSize(1);
10128 bool IsSigned;
10129 bool IsAdd;
10130 unsigned OverflowOp;
10131 switch (MI.getOpcode()) {
10132 default:
10133 llvm_unreachable("unexpected addsat/subsat opcode");
10134 case TargetOpcode::G_UADDSAT:
10135 IsSigned = false;
10136 IsAdd = true;
10137 OverflowOp = TargetOpcode::G_UADDO;
10138 break;
10139 case TargetOpcode::G_SADDSAT:
10140 IsSigned = true;
10141 IsAdd = true;
10142 OverflowOp = TargetOpcode::G_SADDO;
10143 break;
10144 case TargetOpcode::G_USUBSAT:
10145 IsSigned = false;
10146 IsAdd = false;
10147 OverflowOp = TargetOpcode::G_USUBO;
10148 break;
10149 case TargetOpcode::G_SSUBSAT:
10150 IsSigned = true;
10151 IsAdd = false;
10152 OverflowOp = TargetOpcode::G_SSUBO;
10153 break;
10154 }
10155
10156 auto OverflowRes =
10157 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
10158 Register Tmp = OverflowRes.getReg(0);
10159 Register Ov = OverflowRes.getReg(1);
10160 MachineInstrBuilder Clamp;
10161 if (IsSigned) {
10162 // sadd.sat(a, b) ->
10163 // {tmp, ov} = saddo(a, b)
10164 // ov ? (tmp >>s 31) + 0x80000000 : r
10165 // ssub.sat(a, b) ->
10166 // {tmp, ov} = ssubo(a, b)
10167 // ov ? (tmp >>s 31) + 0x80000000 : r
10168 uint64_t NumBits = Ty.getScalarSizeInBits();
10169 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
10170 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
10171 auto MinVal =
10172 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10173 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
10174 } else {
10175 // uadd.sat(a, b) ->
10176 // {tmp, ov} = uaddo(a, b)
10177 // ov ? 0xffffffff : tmp
10178 // usub.sat(a, b) ->
10179 // {tmp, ov} = usubo(a, b)
10180 // ov ? 0 : tmp
10181 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
10182 }
10183 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
10184
10185 MI.eraseFromParent();
10186 return Legalized;
10187}
10188
10191 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
10192 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
10193 "Expected shlsat opcode!");
10194 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
10195 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10196 LLT Ty = MRI.getType(Res);
10197 LLT BoolTy = Ty.changeElementSize(1);
10198
10199 unsigned BW = Ty.getScalarSizeInBits();
10200 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
10201 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
10202 : MIRBuilder.buildLShr(Ty, Result, RHS);
10203
10204 MachineInstrBuilder SatVal;
10205 if (IsSigned) {
10206 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
10207 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
10208 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
10209 MIRBuilder.buildConstant(Ty, 0));
10210 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
10211 } else {
10212 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
10213 }
10214 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
10215 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
10216
10217 MI.eraseFromParent();
10218 return Legalized;
10219}
10220
10222 auto [Dst, Src] = MI.getFirst2Regs();
10223 const LLT Ty = MRI.getType(Src);
10224 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
10225 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
10226
10227 // Swap most and least significant byte, set remaining bytes in Res to zero.
10228 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
10229 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
10230 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10231 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
10232
10233 // Set i-th high/low byte in Res to i-th low/high byte from Src.
10234 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
10235 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
10236 APInt APMask = APInt::getBitsSet(SizeInBytes * 8, i * 8, i * 8 + 8);
10237 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
10238 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
10239 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
10240 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
10241 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
10242 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
10243 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
10244 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10245 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
10246 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
10247 }
10248 Res.getInstr()->getOperand(0).setReg(Dst);
10249
10250 MI.eraseFromParent();
10251 return Legalized;
10252}
10253
10254//{ (Src & Mask) >> N } | { (Src << N) & Mask }
10256 MachineInstrBuilder Src, const APInt &Mask) {
10257 const LLT Ty = Dst.getLLTTy(*B.getMRI());
10258 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
10259 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
10260 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
10261 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
10262 return B.buildOr(Dst, LHS, RHS);
10263}
10264
10267 auto [Dst, Src] = MI.getFirst2Regs();
10268 const LLT SrcTy = MRI.getType(Src);
10269 unsigned Size = SrcTy.getScalarSizeInBits();
10270 unsigned VSize = SrcTy.getSizeInBits();
10271
10272 if (Size >= 8) {
10273 if (SrcTy.isVector() && (VSize % 8 == 0) &&
10274 (LI.isLegal({TargetOpcode::G_BITREVERSE,
10275 {LLT::fixed_vector(VSize / 8, LLT::integer(8)),
10276 LLT::fixed_vector(VSize / 8, LLT::integer(8))}}))) {
10277 // If bitreverse is legal for i8 vector of the same size, then cast
10278 // to i8 vector type.
10279 // e.g. v4s32 -> v16s8
10280 LLT VTy = LLT::fixed_vector(VSize / 8, LLT::integer(8));
10281 auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);
10282 auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);
10283 auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);
10284 MIRBuilder.buildBitcast(Dst, RBIT);
10285 } else {
10286 MachineInstrBuilder BSWAP =
10287 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});
10288
10289 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
10290 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
10291 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
10292 MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,
10293 APInt::getSplat(Size, APInt(8, 0xF0)));
10294
10295 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
10296 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
10297 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
10298 MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,
10299 APInt::getSplat(Size, APInt(8, 0xCC)));
10300
10301 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
10302 // 6|7
10303 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
10304 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
10305 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
10306 }
10307 } else {
10308 // Expand bitreverse for types smaller than 8 bits.
10310 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
10312 if (I < J) {
10313 auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);
10314 Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);
10315 } else {
10316 auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);
10317 Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);
10318 }
10319
10320 auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);
10321 Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);
10322 if (I == 0)
10323 Tmp = Tmp2;
10324 else
10325 Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);
10326 }
10327 MIRBuilder.buildCopy(Dst, Tmp);
10328 }
10329
10330 MI.eraseFromParent();
10331 return Legalized;
10332}
10333
10336 MachineFunction &MF = MIRBuilder.getMF();
10337
10338 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
10339 int NameOpIdx = IsRead ? 1 : 0;
10340 int ValRegIndex = IsRead ? 0 : 1;
10341
10342 Register ValReg = MI.getOperand(ValRegIndex).getReg();
10343 const LLT Ty = MRI.getType(ValReg);
10344 const MDString *RegStr = cast<MDString>(
10345 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
10346
10347 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
10348 if (!PhysReg) {
10349 const Function &Fn = MF.getFunction();
10351 "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +
10352 (IsRead ? "llvm.read_register" : "llvm.write_register"),
10353 Fn, MI.getDebugLoc()));
10354 if (IsRead)
10355 MIRBuilder.buildUndef(ValReg);
10356
10357 MI.eraseFromParent();
10358 return Legalized;
10359 }
10360
10361 if (IsRead)
10362 MIRBuilder.buildCopy(ValReg, PhysReg);
10363 else
10364 MIRBuilder.buildCopy(PhysReg, ValReg);
10365
10366 MI.eraseFromParent();
10367 return Legalized;
10368}
10369
10372 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
10373 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
10374 Register Result = MI.getOperand(0).getReg();
10375 LLT OrigTy = MRI.getType(Result);
10376 auto SizeInBits = OrigTy.getScalarSizeInBits();
10377 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
10378
10379 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
10380 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
10381 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
10382 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
10383
10384 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
10385 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
10386 MIRBuilder.buildTrunc(Result, Shifted);
10387
10388 MI.eraseFromParent();
10389 return Legalized;
10390}
10391
10394 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10395 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
10396
10397 if (Mask == fcNone) {
10398 MIRBuilder.buildConstant(DstReg, 0);
10399 MI.eraseFromParent();
10400 return Legalized;
10401 }
10402 if (Mask == fcAllFlags) {
10403 MIRBuilder.buildConstant(DstReg, 1);
10404 MI.eraseFromParent();
10405 return Legalized;
10406 }
10407
10408 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
10409 // version
10410
10411 unsigned BitSize = SrcTy.getScalarSizeInBits();
10412 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
10413
10414 LLT IntTy = SrcTy.changeElementType(LLT::integer(BitSize));
10415 auto AsInt = SrcTy == IntTy ? MIRBuilder.buildCopy(IntTy, SrcReg)
10416 : MIRBuilder.buildBitcast(IntTy, SrcReg);
10417
10418 // Various masks.
10419 APInt SignBit = APInt::getSignMask(BitSize);
10420 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
10421 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
10422 APInt ExpMask = Inf;
10423 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
10424 APInt QNaNBitMask =
10425 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
10426 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
10427
10428 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
10429 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
10430 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
10431 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
10432 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
10433
10434 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
10435 auto Sign =
10436 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
10437
10438 auto Res = MIRBuilder.buildConstant(DstTy, 0);
10439 // Clang doesn't support capture of structured bindings:
10440 LLT DstTyCopy = DstTy;
10441 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
10442 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
10443 };
10444
10445 // Tests that involve more than one class should be processed first.
10446 if ((Mask & fcFinite) == fcFinite) {
10447 // finite(V) ==> abs(V) u< exp_mask
10448 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10449 ExpMaskC));
10450 Mask &= ~fcFinite;
10451 } else if ((Mask & fcFinite) == fcPosFinite) {
10452 // finite(V) && V > 0 ==> V u< exp_mask
10453 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
10454 ExpMaskC));
10455 Mask &= ~fcPosFinite;
10456 } else if ((Mask & fcFinite) == fcNegFinite) {
10457 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
10458 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10459 ExpMaskC);
10460 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
10461 appendToRes(And);
10462 Mask &= ~fcNegFinite;
10463 }
10464
10465 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
10466 // fcZero | fcSubnormal => test all exponent bits are 0
10467 // TODO: Handle sign bit specific cases
10468 // TODO: Handle inverted case
10469 if (PartialCheck == (fcZero | fcSubnormal)) {
10470 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
10471 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10472 ExpBits, ZeroC));
10473 Mask &= ~PartialCheck;
10474 }
10475 }
10476
10477 // Check for individual classes.
10478 if (FPClassTest PartialCheck = Mask & fcZero) {
10479 if (PartialCheck == fcPosZero)
10480 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10481 AsInt, ZeroC));
10482 else if (PartialCheck == fcZero)
10483 appendToRes(
10484 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
10485 else // fcNegZero
10486 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10487 AsInt, SignBitC));
10488 }
10489
10490 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
10491 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
10492 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
10493 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
10494 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
10495 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
10496 auto SubnormalRes =
10497 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
10498 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
10499 if (PartialCheck == fcNegSubnormal)
10500 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
10501 appendToRes(SubnormalRes);
10502 }
10503
10504 if (FPClassTest PartialCheck = Mask & fcInf) {
10505 if (PartialCheck == fcPosInf)
10506 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10507 AsInt, InfC));
10508 else if (PartialCheck == fcInf)
10509 appendToRes(
10510 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
10511 else { // fcNegInf
10512 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
10513 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
10514 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10515 AsInt, NegInfC));
10516 }
10517 }
10518
10519 if (FPClassTest PartialCheck = Mask & fcNan) {
10520 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
10521 if (PartialCheck == fcNan) {
10522 // isnan(V) ==> abs(V) u> int(inf)
10523 appendToRes(
10524 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
10525 } else if (PartialCheck == fcQNan) {
10526 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
10527 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
10528 InfWithQnanBitC));
10529 } else { // fcSNan
10530 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
10531 // abs(V) u< (unsigned(Inf) | quiet_bit)
10532 auto IsNan =
10533 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
10534 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
10535 Abs, InfWithQnanBitC);
10536 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
10537 }
10538 }
10539
10540 if (FPClassTest PartialCheck = Mask & fcNormal) {
10541 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
10542 // (max_exp-1))
10543 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
10544 auto ExpMinusOne = MIRBuilder.buildSub(
10545 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
10546 APInt MaxExpMinusOne = ExpMask - ExpLSB;
10547 auto NormalRes =
10548 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
10549 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
10550 if (PartialCheck == fcNegNormal)
10551 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
10552 else if (PartialCheck == fcPosNormal) {
10553 auto PosSign = MIRBuilder.buildXor(
10554 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));
10555 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
10556 }
10557 appendToRes(NormalRes);
10558 }
10559
10560 MIRBuilder.buildCopy(DstReg, Res);
10561 MI.eraseFromParent();
10562 return Legalized;
10563}
10564
10566 // Implement G_SELECT in terms of XOR, AND, OR.
10567 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
10568 MI.getFirst4RegLLTs();
10569
10570 LLT Op1TyInt =
10571 Op1Ty.changeElementType(LLT::integer(Op1Ty.getScalarSizeInBits()));
10572
10573 bool IsEltPtr = DstTy.isPointerOrPointerVector();
10574 if (IsEltPtr) {
10575 LLT ScalarPtrTy = LLT::integer(DstTy.getScalarSizeInBits());
10576 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
10577 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
10578 Op1Ty = MRI.getType(Op1Reg);
10579 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
10580 Op2Ty = MRI.getType(Op2Reg);
10581 DstTy = NewTy;
10582 }
10583
10584 if (MaskTy.isScalar()) {
10585 // Turn the scalar condition into a vector condition mask if needed.
10586
10587 Register MaskElt = MaskReg;
10588
10589 // The condition was potentially zero extended before, but we want a sign
10590 // extended boolean.
10591 if (MaskTy != LLT::scalar(1))
10592 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
10593
10594 // Continue the sign extension (or truncate) to match the data type.
10595 MaskTy = DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10596 MaskElt =
10597 MIRBuilder.buildSExtOrTrunc(MaskTy.getScalarType(), MaskElt).getReg(0);
10598
10599 if (DstTy.isVector()) {
10600 // Generate a vector splat idiom.
10601 auto ShufSplat = MIRBuilder.buildShuffleSplat(MaskTy, MaskElt);
10602 MaskReg = ShufSplat.getReg(0);
10603 } else {
10604 MaskReg = MaskElt;
10605 }
10606 } else if (!DstTy.isVector()) {
10607 // Cannot handle the case that mask is a vector and dst is a scalar.
10608 return UnableToLegalize;
10609 }
10610
10611 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
10612 return UnableToLegalize;
10613 }
10614
10615 if (!Op1Ty.getScalarType().isAnyScalar() &&
10616 !Op1Ty.getScalarType().isInteger())
10617 Op1Reg = MIRBuilder.buildBitcast(Op1TyInt, Op1Reg).getReg(0);
10618
10619 if (!Op2Ty.getScalarType().isAnyScalar() &&
10620 !Op2Ty.getScalarType().isInteger()) {
10621 auto Op2TyInt =
10622 Op2Ty.changeElementType(LLT::integer(Op2Ty.getScalarSizeInBits()));
10623 Op2Reg = MIRBuilder.buildBitcast(Op2TyInt, Op2Reg).getReg(0);
10624 }
10625
10626 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
10627 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
10628 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
10629 if (IsEltPtr) {
10630 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
10631 MIRBuilder.buildIntToPtr(DstReg, Or);
10632 } else {
10633 if (DstTy == Op1TyInt)
10634 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
10635 else {
10636 auto Or = MIRBuilder.buildOr(Op1TyInt, NewOp1, NewOp2);
10637 MIRBuilder.buildBitcast(DstReg, Or.getReg(0));
10638 }
10639 }
10640 MI.eraseFromParent();
10641 return Legalized;
10642}
10643
10645 // Split DIVREM into individual instructions.
10646 unsigned Opcode = MI.getOpcode();
10647
10648 MIRBuilder.buildInstr(
10649 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
10650 : TargetOpcode::G_UDIV,
10651 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10652 MIRBuilder.buildInstr(
10653 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
10654 : TargetOpcode::G_UREM,
10655 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10656 MI.eraseFromParent();
10657 return Legalized;
10658}
10659
10662 // Expand %res = G_ABS %a into:
10663 // %v1 = G_ASHR %a, scalar_size-1
10664 // %v2 = G_ADD %a, %v1
10665 // %res = G_XOR %v2, %v1
10666 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
10667 Register OpReg = MI.getOperand(1).getReg();
10668 auto ShiftAmt =
10669 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
10670 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
10671 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
10672 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
10673 MI.eraseFromParent();
10674 return Legalized;
10675}
10676
10679 // Expand %res = G_ABS %a into:
10680 // %v1 = G_CONSTANT 0
10681 // %v2 = G_SUB %v1, %a
10682 // %res = G_SMAX %a, %v2
10683 Register SrcReg = MI.getOperand(1).getReg();
10684 LLT Ty = MRI.getType(SrcReg);
10685 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10686 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
10687 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
10688 MI.eraseFromParent();
10689 return Legalized;
10690}
10691
10694 Register SrcReg = MI.getOperand(1).getReg();
10695 Register DestReg = MI.getOperand(0).getReg();
10696 LLT Ty = MRI.getType(SrcReg), IType = LLT::scalar(1);
10697 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
10698 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
10699 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
10700 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
10701 MI.eraseFromParent();
10702 return Legalized;
10703}
10704
10707 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10708 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10709 "Expected G_ABDS or G_ABDU instruction");
10710
10711 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10712 LLT Ty = MRI.getType(LHS);
10713
10714 // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10715 // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10716 Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);
10717 Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);
10718 CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)
10721 auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);
10722 MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);
10723
10724 MI.eraseFromParent();
10725 return Legalized;
10726}
10727
10730 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10731 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10732 "Expected G_ABDS or G_ABDU instruction");
10733
10734 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10735 LLT Ty = MRI.getType(LHS);
10736
10737 // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))
10738 // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))
10739 Register MaxReg, MinReg;
10740 if (MI.getOpcode() == TargetOpcode::G_ABDS) {
10741 MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);
10742 MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);
10743 } else {
10744 MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);
10745 MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);
10746 }
10747 MIRBuilder.buildSub(DstReg, MaxReg, MinReg);
10748
10749 MI.eraseFromParent();
10750 return Legalized;
10751}
10752
10754 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10755 LLT TyInt =
10756 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10757 Register CastedSrc = SrcReg;
10758
10759 if (!(SrcTy.getScalarType().isAnyScalar() ||
10760 SrcTy.getScalarType().isInteger())) {
10761 auto SrcTyInt =
10762 SrcTy.changeElementType(LLT::integer(SrcTy.getScalarSizeInBits()));
10763 CastedSrc = MIRBuilder.buildBitcast(SrcTyInt, SrcReg).getReg(0);
10764 }
10765
10766 if (MRI.getType(DstReg) != TyInt) {
10767 // Reset sign bit
10768 Register NewDst =
10770 .buildAnd(TyInt, CastedSrc,
10771 MIRBuilder.buildConstant(
10773 DstTy.getScalarSizeInBits())))
10774 .getReg(0);
10775
10776 MIRBuilder.buildBitcast(DstReg, NewDst);
10777 } else
10779 .buildAnd(
10780 DstReg, CastedSrc,
10781 MIRBuilder.buildConstant(
10782 TyInt, APInt::getSignedMaxValue(DstTy.getScalarSizeInBits())))
10783 .getReg(0);
10784
10785 MI.eraseFromParent();
10786 return Legalized;
10787}
10788
10791 Register SrcReg = MI.getOperand(1).getReg();
10792 LLT SrcTy = MRI.getType(SrcReg);
10793 LLT DstTy = MRI.getType(SrcReg);
10794
10795 // The source could be a scalar if the IR type was <1 x sN>.
10796 if (SrcTy.isScalar()) {
10797 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
10798 return UnableToLegalize; // FIXME: handle extension.
10799 // This can be just a plain copy.
10800 Observer.changingInstr(MI);
10801 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
10802 Observer.changedInstr(MI);
10803 return Legalized;
10804 }
10805 return UnableToLegalize;
10806}
10807
10809 MachineFunction &MF = *MI.getMF();
10810 const DataLayout &DL = MIRBuilder.getDataLayout();
10811 LLVMContext &Ctx = MF.getFunction().getContext();
10812 Register ListPtr = MI.getOperand(1).getReg();
10813 LLT PtrTy = MRI.getType(ListPtr);
10814
10815 // LstPtr is a pointer to the head of the list. Get the address
10816 // of the head of the list.
10817 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
10818 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
10819 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
10820 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
10821
10822 const Align A(MI.getOperand(2).getImm());
10823 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
10824 if (A > TLI.getMinStackArgumentAlignment()) {
10825 Register AlignAmt =
10826 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
10827 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
10828 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
10829 VAList = AndDst.getReg(0);
10830 }
10831
10832 // Increment the pointer, VAList, to the next vaarg
10833 // The list should be bumped by the size of element in the current head of
10834 // list.
10835 Register Dst = MI.getOperand(0).getReg();
10836 LLT LLTTy = MRI.getType(Dst);
10837 Type *Ty = getTypeForLLT(LLTTy, Ctx);
10838 auto IncAmt =
10839 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
10840 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
10841
10842 // Store the increment VAList to the legalized pointer
10844 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
10845 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
10846 // Load the actual argument out of the pointer VAList
10847 Align EltAlignment = DL.getABITypeAlign(Ty);
10848 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
10849 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
10850 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
10851
10852 MI.eraseFromParent();
10853 return Legalized;
10854}
10855
10857 [[maybe_unused]] unsigned OpCode = MI.getOpcode();
10858 assert((OpCode == TargetOpcode::G_SMULFIX ||
10859 OpCode == TargetOpcode::G_UMULFIX) &&
10860 "Operator must be either G_SMULFIX or G_UMULFIX!");
10861 auto [Dst, LHS, RHS] = MI.getFirst3Regs();
10862 LLT Ty = MRI.getType(Dst);
10863 unsigned Scale = MI.getOperand(3).getImm();
10864
10865 if (Scale == 0) {
10866 MIRBuilder.buildMul(Dst, LHS, RHS);
10867 MI.eraseFromParent();
10868 return Legalized;
10869 }
10870
10871 // TODO: Port other lowerng paths from SelectionDAG.
10872 LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
10873 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
10874 MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
10875 if (MI.getOpcode() == TargetOpcode::G_SMULFIX) {
10876 ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
10877 ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
10878 } else {
10879 ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
10880 ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
10881 }
10882
10883 auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
10884 if (MI.getOpcode() == TargetOpcode::G_SMULFIX)
10885 Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
10886 else
10887 Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
10888
10889 MIRBuilder.buildTrunc(Dst, Shift);
10890
10891 MI.eraseFromParent();
10892 return Legalized;
10893}
10894
10895// Get a vectorized representation of the memset value operand, GISel edition.
10897 MachineRegisterInfo &MRI = *MIB.getMRI();
10898 unsigned NumBits = Ty.getScalarSizeInBits();
10899 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
10900 if (!Ty.isVector() && ValVRegAndVal) {
10901 APInt Scalar = ValVRegAndVal->Value.trunc(8);
10902 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
10903 return MIB.buildConstant(Ty, SplatVal).getReg(0);
10904 }
10905
10906 // Extend the byte value to the larger type, and then multiply by a magic
10907 // value 0x010101... in order to replicate it across every byte.
10908 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
10909 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
10910 return MIB.buildConstant(Ty, 0).getReg(0);
10911 }
10912
10913 LLT ExtType = Ty.getScalarType();
10914 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
10915 if (NumBits > 8) {
10916 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
10917 auto MagicMI = MIB.buildConstant(ExtType, Magic);
10918 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
10919 }
10920
10921 // For vector types create a G_BUILD_VECTOR.
10922 if (Ty.isVector())
10923 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
10924
10925 return Val;
10926}
10927
10929LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
10930 uint64_t KnownLen, Align Alignment,
10931 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
10932 auto &MF = *MI.getParent()->getParent();
10933 const auto &TLI = *MF.getSubtarget().getTargetLowering();
10934 auto &DL = MF.getDataLayout();
10935 LLVMContext &C = MF.getFunction().getContext();
10936
10937 assert(KnownLen != 0 && "Have a zero length memset length!");
10938 assert(!MemOps.empty() && "Expected at least one memory op");
10939
10940 MachineFrameInfo &MFI = MF.getFrameInfo();
10941 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
10942 const auto &DstMMO = **MI.memoperands_begin();
10943
10944 if (DstAlignCanChange) {
10945 // Get an estimate of the type from the LLT.
10946 Type *IRTy = getTypeForLLT(MemOps[0], C);
10947 Align NewAlign = DL.getABITypeAlign(IRTy);
10948 if (NewAlign > Alignment) {
10949 Alignment = NewAlign;
10950 unsigned FI = FIDef->getOperand(1).getIndex();
10951 // Give the stack frame object a larger alignment if needed.
10952 if (MFI.getObjectAlign(FI) < Alignment)
10953 MFI.setObjectAlignment(FI, Alignment);
10954 }
10955 }
10956
10957 MachineIRBuilder MIB(MI);
10958 // Find the largest store and generate the bit pattern for it.
10959 LLT LargestTy = MemOps[0];
10960 for (unsigned i = 1; i < MemOps.size(); i++)
10961 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
10962 LargestTy = MemOps[i];
10963
10964 // The memset stored value is always defined as an s8, so in order to make it
10965 // work with larger store types we need to repeat the bit pattern across the
10966 // wider type.
10967 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
10968
10969 if (!MemSetValue)
10970 return UnableToLegalize;
10971
10972 // Generate the stores. For each store type in the list, we generate the
10973 // matching store of that type to the destination address.
10974 LLT PtrTy = MRI.getType(Dst);
10975 unsigned DstOff = 0;
10976 unsigned Size = KnownLen;
10977 for (unsigned I = 0; I < MemOps.size(); I++) {
10978 LLT Ty = MemOps[I];
10979 unsigned TySize = Ty.getSizeInBytes();
10980
10981 if (TySize > Size) {
10982 // Issuing a load / store pair that overlaps with the previous pair.
10983 // Adjust the offset accordingly.
10984 assert(I == MemOps.size() - 1 && I != 0);
10985 DstOff -= TySize - Size;
10986 }
10987
10988 // If this store is smaller than the largest store see whether we can get
10989 // the smaller value for free with a truncate.
10990 Register Value = MemSetValue;
10991 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
10992 MVT VT = getMVTForLLT(Ty);
10993 MVT LargestVT = getMVTForLLT(LargestTy);
10994 if (!LargestTy.isVector() && !Ty.isVector() &&
10995 TLI.isTruncateFree(LargestVT, VT))
10996 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
10997 else
10998 Value = getMemsetValue(Val, Ty, MIB);
10999 if (!Value)
11000 return UnableToLegalize;
11001 }
11002
11003 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
11004
11005 Register Ptr = Dst;
11006 if (DstOff != 0) {
11007 auto Offset =
11008 MIB.buildConstant(LLT::scalar(PtrTy.getSizeInBits()), DstOff);
11009 Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);
11010 }
11011
11012 MIB.buildStore(Value, Ptr, *StoreMMO);
11013 DstOff += Ty.getSizeInBytes();
11014 Size -= TySize;
11015 }
11016
11017 MI.eraseFromParent();
11018 return Legalized;
11019}
11020
11022LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
11023 uint64_t KnownLen, Align Alignment,
11024 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11025 auto &MF = *MI.getParent()->getParent();
11026 auto &DL = MF.getDataLayout();
11027 LLVMContext &C = MF.getFunction().getContext();
11028
11029 assert(KnownLen != 0 && "Have a zero length memcpy length!");
11030 assert(!MemOps.empty() && "Expected at least one memory op");
11031
11032 MachineFrameInfo &MFI = MF.getFrameInfo();
11033 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11034
11035 // FIXME: infer better src pointer alignment like SelectionDAG does here.
11036 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
11037 // if the memcpy is in a tail call position.
11038
11039 const auto &DstMMO = **MI.memoperands_begin();
11040 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11041
11042 if (DstAlignCanChange) {
11043 // Get an estimate of the type from the LLT.
11044 Type *IRTy = getTypeForLLT(MemOps[0], C);
11045 Align NewAlign = DL.getABITypeAlign(IRTy);
11046
11047 // Don't promote to an alignment that would require dynamic stack
11048 // realignment.
11049 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11050 if (!TRI->hasStackRealignment(MF))
11051 if (MaybeAlign StackAlign = DL.getStackAlignment())
11052 NewAlign = std::min(NewAlign, *StackAlign);
11053
11054 if (NewAlign > Alignment) {
11055 Alignment = NewAlign;
11056 unsigned FI = FIDef->getOperand(1).getIndex();
11057 // Give the stack frame object a larger alignment if needed.
11058 if (MFI.getObjectAlign(FI) < Alignment)
11059 MFI.setObjectAlignment(FI, Alignment);
11060 }
11061 }
11062
11063 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
11064
11065 MachineIRBuilder MIB(MI);
11066 // Now we need to emit a pair of load and stores for each of the types we've
11067 // collected. I.e. for each type, generate a load from the source pointer of
11068 // that type width, and then generate a corresponding store to the dest buffer
11069 // of that value loaded. This can result in a sequence of loads and stores
11070 // mixed types, depending on what the target specifies as good types to use.
11071 unsigned CurrOffset = 0;
11072 unsigned Size = KnownLen;
11073 for (auto CopyTy : MemOps) {
11074 TypeSize TySize = CopyTy.getSizeInBytes();
11075
11076 // Issuing a load / store pair that overlaps with the previous pair. Adjust
11077 // the offset accordingly.
11078 if (TySize > Size) {
11079 unsigned Overlap = TySize - Size;
11080 assert(Overlap < CurrOffset &&
11081 "overlapping memcpy load/store spans the whole region or more");
11082 CurrOffset -= Overlap;
11083 }
11084
11085 // Construct MMOs for the accesses.
11086 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11087 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11088
11089 // Create the load.
11090 Register LoadPtr = Src;
11092 if (CurrOffset != 0) {
11093 LLT SrcTy = MRI.getType(Src);
11094 Offset =
11095 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset)
11096 .getReg(0);
11097 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11098 }
11099 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
11100
11101 // Create the store.
11102 Register StorePtr = Dst;
11103 if (CurrOffset != 0) {
11104 LLT DstTy = MRI.getType(Dst);
11105 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11106 }
11107 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
11108 CurrOffset += TySize;
11109 Size -= TySize;
11110 }
11111
11112 MI.eraseFromParent();
11113 return Legalized;
11114}
11115
11117LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
11118 uint64_t KnownLen, Align Alignment,
11119 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11120 auto &MF = *MI.getParent()->getParent();
11121 auto &DL = MF.getDataLayout();
11122 LLVMContext &C = MF.getFunction().getContext();
11123
11124 assert(KnownLen != 0 && "Have a zero length memmove length!");
11125 assert(!MemOps.empty() && "Expected at least one memory op");
11126
11127 MachineFrameInfo &MFI = MF.getFrameInfo();
11128 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11129 const auto &DstMMO = **MI.memoperands_begin();
11130 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11131
11132 if (DstAlignCanChange) {
11133 // Get an estimate of the type from the LLT.
11134 Type *IRTy = getTypeForLLT(MemOps[0], C);
11135 Align NewAlign = DL.getABITypeAlign(IRTy);
11136
11137 // Don't promote to an alignment that would require dynamic stack
11138 // realignment.
11139 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11140 if (!TRI->hasStackRealignment(MF))
11141 if (MaybeAlign StackAlign = DL.getStackAlignment())
11142 NewAlign = std::min(NewAlign, *StackAlign);
11143
11144 if (NewAlign > Alignment) {
11145 Alignment = NewAlign;
11146 unsigned FI = FIDef->getOperand(1).getIndex();
11147 // Give the stack frame object a larger alignment if needed.
11148 if (MFI.getObjectAlign(FI) < Alignment)
11149 MFI.setObjectAlignment(FI, Alignment);
11150 }
11151 }
11152
11153 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
11154
11155 MachineIRBuilder MIB(MI);
11156 // Memmove requires that we perform the loads first before issuing the stores.
11157 // Apart from that, this loop is pretty much doing the same thing as the
11158 // memcpy codegen function.
11159 unsigned CurrOffset = 0;
11160 unsigned Size = KnownLen;
11161 SmallVector<Register, 16> LoadVals;
11162 for (auto CopyTy : MemOps) {
11163 TypeSize TySize = CopyTy.getSizeInBytes();
11164
11165 // Issuing a load that overlaps with the previous load. Adjust the offset
11166 // accordingly.
11167 if (TySize > Size) {
11168 unsigned Overlap = TySize - Size;
11169 assert(Overlap < CurrOffset &&
11170 "overlapping memmove load spans the whole region or more");
11171 CurrOffset -= Overlap;
11172 }
11173
11174 // Construct MMO for the load.
11175 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11176
11177 // Create the load.
11178 Register LoadPtr = Src;
11179 if (CurrOffset != 0) {
11180 LLT SrcTy = MRI.getType(Src);
11181 auto Offset =
11182 MIB.buildConstant(LLT::scalar(SrcTy.getSizeInBits()), CurrOffset);
11183 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11184 }
11185 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
11186 CurrOffset += TySize;
11187 Size -= TySize;
11188 }
11189
11190 CurrOffset = 0;
11191 Size = KnownLen;
11192 for (unsigned I = 0; I < MemOps.size(); ++I) {
11193 LLT CopyTy = MemOps[I];
11194 TypeSize TySize = CopyTy.getSizeInBytes();
11195
11196 // Issuing a store that overlaps with the previous store. Adjust the offset
11197 // accordingly.
11198 if (TySize > Size) {
11199 unsigned Overlap = TySize - Size;
11200 assert(Overlap < CurrOffset &&
11201 "overlapping memmove store spans the whole region or more");
11202 CurrOffset -= Overlap;
11203 }
11204
11205 // Now store the values loaded.
11206 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11207
11208 Register StorePtr = Dst;
11209 if (CurrOffset != 0) {
11210 LLT DstTy = MRI.getType(Dst);
11211 auto Offset =
11212 MIB.buildConstant(LLT::scalar(DstTy.getSizeInBits()), CurrOffset);
11213 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11214 }
11215 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
11216 CurrOffset += TySize;
11217 Size -= TySize;
11218 }
11219 MI.eraseFromParent();
11220 return Legalized;
11221}
11222
11224 MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen,
11225 Align Alignment, bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11226 const unsigned Opc = MI.getOpcode();
11227 assert((Opc == TargetOpcode::G_MEMCPY ||
11228 Opc == TargetOpcode::G_MEMCPY_INLINE ||
11229 Opc == TargetOpcode::G_MEMMOVE || Opc == TargetOpcode::G_MEMSET ||
11230 Opc == TargetOpcode::G_MEMSET_INLINE) &&
11231 "Expected memcpy like instruction");
11232
11233 if (KnownLen == 0) {
11234 MI.eraseFromParent();
11235 return Legalized;
11236 }
11237
11238 if (Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMCPY_INLINE) {
11239 return lowerMemcpy(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11240 MemOps);
11241 }
11242 if (Opc == TargetOpcode::G_MEMMOVE)
11243 return lowerMemmove(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11244 MemOps);
11245 if (Opc == TargetOpcode::G_MEMSET || Opc == TargetOpcode::G_MEMSET_INLINE)
11246 return lowerMemset(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11247 MemOps);
11248 return UnableToLegalize;
11249}
11250
11253 Register Dst, Src;
11254 uint64_t KnownLen;
11255 Align Alignment;
11256 bool DstAlignCanChange;
11257 std::vector<LLT> MemOps;
11258 if (!canLowerMemCpyFamily(MI, MRI, MaxLen, Dst, Src, KnownLen, Alignment,
11259 DstAlignCanChange, MemOps))
11260 return UnableToLegalize;
11261 return lowerMemCpyFamily(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11262 MemOps);
11263}
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< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file describes how to lower LLVM calls to machine code calls.
#define GISEL_VECREDUCE_CASES_NONSEQ
Definition Utils.h: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:304
static constexpr roundingMode rmTowardZero
Definition APFloat.h:357
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:353
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:369
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
Definition APFloat.h:1443
APInt bitcastToAPInt() const
Definition APFloat.h:1467
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1234
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1194
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
Definition APFloat.h:1205
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 LegalizeResult lowerFPEXT_BF16(MachineInstr &MI)
LLVM_ABI void moreElementsVectorDst(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Def by performing it with addition...
LLVM_ABI LegalizerHelper::LegalizeResult createAtomicLibcall(MachineInstr &MI) const
LLVM_ABI LegalizeResult lowerFConstant(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerBitreverse(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI)
Lower a vector extract or insert by writing the vector to a stack temporary and reloading the element...
LLVM_ABI LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
Legalize a vector instruction by increasing the number of vector elements involved and ignoring the a...
LLVM_ABI LegalizeResult lowerFunnelShiftWithInverse(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTLS(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStore(GStore &MI)
LLVM_ABI LegalizeResult lowerAbsToCNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastExtractSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
LLVM_ABI LegalizeResult narrowScalarShiftMultiway(MachineInstr &MI, LLT TargetTy)
Multi-way shift legalization: directly split wide shifts into target-sized parts in a single step,...
LLVM_ABI Register lowerRoundInexactToOdd(LLT ResultTy, Register Op)
LLVM_ABI LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
LLVM_ABI Register buildConstantShiftPart(unsigned Opcode, unsigned PartIdx, unsigned NumParts, ArrayRef< Register > SrcParts, const ShiftParams &Params, LLT TargetTy, LLT ShiftAmtTy)
Generates a single output part for constant shifts using direct indexing.
LLVM_ABI void narrowScalarSrc(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by truncating the operand's ty...
LLVM_ABI LegalizeResult fewerElementsVectorPhi(GenericMachineInstr &MI, unsigned NumElts)
LLVM_ABI LegalizeResult lowerFPTOUI(MachineInstr &MI)
const TargetLowering & getTargetLowering() const
LLVM_ABI LegalizeResult narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize an instruction by reducing the width of the underlying scalar type.
LLVM_ABI LegalizeResult narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult bitcastInsertSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
LLVM_ABI LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer, MachineIRBuilder &B, const LibcallLoweringInfo *Libcalls=nullptr)
LLVM_ABI LegalizeResult lowerUnmergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcast(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by replacing the value type.
LLVM_ABI LegalizeResult scalarizeVectorBooleanStore(GStore &MI)
Given a store of a boolean vector, scalarize it.
LLVM_ABI LegalizeResult lowerBitcast(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerInsert(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerReadWriteRegister(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerExtract(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsBitcast(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt, LLT HalfTy, LLT ShiftAmtTy)
LLVM_ABI LegalizeResult lowerISFPCLASS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPOWI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPExtAndTruncMem(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFAbs(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerVectorReduction(MachineInstr &MI)
const LegalizerInfo & getLegalizerInfo() const
Expose LegalizerInfo so the clients can re-use.
LLVM_ABI LegalizeResult reduceLoadStoreWidth(GLoadStore &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult fewerElementsVectorMultiEltType(GenericMachineInstr &MI, unsigned NumElts, std::initializer_list< unsigned > NonVecOpIndices={})
Handles most opcodes.
LLVM_ABI LegalizeResult narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarShiftByConstantMultiway(MachineInstr &MI, const APInt &Amt, LLT TargetTy, LLT ShiftAmtTy)
Optimized path for constant shift amounts using static indexing.
LLVM_ABI void widenScalarSrcUsingFPExt(MachineInstr &MI, LLT WideTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI MachineInstrBuilder createStackStoreLoad(const DstOp &Res, const SrcOp &Val)
Create a store of Val to a stack temporary and return a load as the same type as Res.
LLVM_ABI LegalizeResult lowerVAArg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMODF(MachineInstr &MI)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
@ AlreadyLegal
Instruction was already legal and no change was made to the MachineFunction.
@ UnableToLegalize
Some kind of error has occurred and we could not legalize this instruction.
LLVM_ABI LegalizeResult moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
LLVM_ABI LegalizeResult 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 lowerFPTRUNC_F64_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExt(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult fewerElementsVectorSeqReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Register getDynStackAllocTargetPtr(Register SPReg, Register AllocSize, Align Alignment, LLT PtrTy)
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerUITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerShuffleVector(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerMergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult createMemLibcall(MachineRegisterInfo &MRI, MachineInstr &MI, LostDebugLocObserver &LocObserver) const
Create a libcall to memcpy et al.
LLVM_ABI LegalizeResult lowerVECTOR_COMPRESS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI)
LLVM_ABI void moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by producing a vector with und...
LLVM_ABI LegalizeResult bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_EXTRACT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF32WithSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult createLibcall(const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr) const
Helper function that creates a libcall to the given Name using the given calling convention CC.
LLVM_ABI LegalizeResult bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerDIVREM(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI Register buildVariableShiftPart(unsigned Opcode, Register MainOperand, Register ShiftAmt, LLT TargetTy, Register CarryOperand=Register())
Generates a shift part with carry for variable shifts.
LLVM_ABI void bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a use by inserting a G_BITCAST to Ca...
LLVM_ABI void narrowScalarDst(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx, unsigned ExtOpcode)
LLVM_ABI LegalizeResult libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Legalize an instruction by emiting a runtime library call instead.
LLVM_ABI LegalizeResult lowerStackRestore(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerStackSave(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI void widenScalarDstUsingFPTrunc(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBswap(MachineInstr &MI)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
LLVM_ABI LegalizeResult narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LLVM_ABI Register coerceToInteger(Register Val)
Cast the given value to an LLT::integer with an equivalent size.
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LLVM_ABI LegalizeResult simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType, LostDebugLocObserver &LocObserver) const
LLVM_ABI LegalizeResult legalizeInstrStep(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Replace MI by a sequence of legal instructions that can implement the same operation.
LLVM_ABI LegalizeResult lowerFMinimumMaximum(MachineInstr &MI)
Tracks which library functions to use for a particular subtarget.
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:633
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(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:911
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
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ Libcall
The operation should be implemented as a call to some kind of runtime support library.
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
@ NarrowScalar
The operation should be synthesized from multiple instructions acting on a narrower scalar base-type.
@ MoreElements
The (vector) operation should be implemented by widening the input vector and ignoring the lanes adde...
ConstantMatch< APInt > m_ICst(APInt &Cst)
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
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
Definition Utils.cpp:1517
@ Offset
Definition DWP.cpp:578
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:1972
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:224
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:285
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:1572
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:386
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:1141
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:358
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:332
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h: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:2139
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:233
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp: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:1229
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:374
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
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.