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
522 const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
523 return TLI.supportSwiftError() &&
524 MF.getFunction().getAttributes().hasAttrSomewhere(
525 Attribute::SwiftError);
526}
527
528/// True if an instruction is in tail position in its caller. Intended for
529/// legalizing libcalls as tail calls when possible.
532 const TargetInstrInfo &TII,
533 MachineRegisterInfo &MRI) {
534 MachineBasicBlock &MBB = *MI.getParent();
535 const Function &F = MBB.getParent()->getFunction();
536
537 // Conservatively require the attributes of the call to match those of
538 // the return. Ignore NoAlias and NonNull because they don't affect the
539 // call sequence.
540 AttributeList CallerAttrs = F.getAttributes();
541 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
542 .removeAttribute(Attribute::NoAlias)
543 .removeAttribute(Attribute::NonNull)
544 .hasAttributes())
545 return false;
546
547 // It's not safe to eliminate the sign / zero extension of the return value.
548 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
549 CallerAttrs.hasRetAttr(Attribute::SExt))
550 return false;
551
552 // Only tail call if the following instruction is a standard return or if we
553 // have a `thisreturn` callee, and a sequence like:
554 //
555 // G_MEMCPY %0, %1, %2
556 // $x0 = COPY %0
557 // RET_ReallyLR implicit $x0
558 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
559 if (Next != MBB.instr_end() && Next->isCopy()) {
560 if (MI.getOpcode() == TargetOpcode::G_BZERO)
561 return false;
562
563 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
564 // mempy/etc routines return the same parameter. For other it will be the
565 // returned value.
566 Register VReg = MI.getOperand(0).getReg();
567 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
568 return false;
569
570 Register PReg = Next->getOperand(0).getReg();
571 if (!PReg.isPhysical())
572 return false;
573
574 auto Ret = next_nodbg(Next, MBB.instr_end());
575 if (Ret == MBB.instr_end() || !Ret->isReturn())
576 return false;
577
578 if (Ret->getNumImplicitOperands() != 1)
579 return false;
580
581 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
582 return false;
583
584 // Skip over the COPY that we just validated.
585 Next = Ret;
586 }
587
588 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
589 return false;
590
591 return true;
592}
593
595 const char *Name, const CallLowering::ArgInfo &Result,
597 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
598 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
599
601 Info.CallConv = CC;
602 Info.Callee = MachineOperand::CreateES(Name);
603 Info.OrigRet = Result;
604 if (MI)
605 Info.IsTailCall =
606 (Result.Ty->isVoidTy() ||
607 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
608 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
609 *MIRBuilder.getMRI()) &&
610 // Lowering doesn't support tail calling inside a function with
611 // a swifterror argument yet.
613
614 llvm::append_range(Info.OrigArgs, Args);
615 if (!CLI.lowerCall(MIRBuilder, Info))
617
618 if (MI && Info.LoweredTailCall) {
619 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
620
621 // Check debug locations before removing the return.
622 LocObserver.checkpoint(true);
623
624 // We must have a return following the call (or debug insts) to get past
625 // isLibCallInTailPosition.
626 do {
627 MachineInstr *Next = MI->getNextNode();
628 assert(Next &&
629 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
630 "Expected instr following MI to be return or debug inst?");
631 // We lowered a tail call, so the call is now the return from the block.
632 // Delete the old return.
633 Next->eraseFromParent();
634 } while (MI->getNextNode());
635
636 // We expect to lose the debug location from the return.
637 LocObserver.checkpoint(false);
638 }
640}
641
643 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
645 MachineInstr *MI) const {
646 if (!Libcalls)
648
649 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
650 if (LibcallImpl == RTLIB::Unsupported)
652
654 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
655 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
656}
657
658// Useful for libcalls where all operands have the same type.
661 unsigned Size, Type *OpType,
662 LostDebugLocObserver &LocObserver) const {
663 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
664
665 // FIXME: What does the original arg index mean here?
667 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
668 Args.push_back({MO.getReg(), OpType, 0});
669 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
670 LocObserver, &MI);
671}
672
673LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
674 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
675 LostDebugLocObserver &LocObserver) {
676 MachineFunction &MF = *MI.getMF();
678
679 Register DstSin = MI.getOperand(0).getReg();
680 Register DstCos = MI.getOperand(1).getReg();
681 Register Src = MI.getOperand(2).getReg();
682 LLT DstTy = MRI.getType(DstSin);
683
684 int MemSize = DstTy.getSizeInBytes();
685 Align Alignment = getStackTemporaryAlignment(DstTy);
687 unsigned AddrSpace = DL.getAllocaAddrSpace();
688 MachinePointerInfo PtrInfo;
689
690 Register StackPtrSin =
691 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
692 .getReg(0);
693 Register StackPtrCos =
694 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
695 .getReg(0);
696
697 auto &Ctx = MF.getFunction().getContext();
698 auto LibcallResult = createLibcall(
699 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
700 {{Src, OpType, 0},
701 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
702 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
703 LocObserver, &MI);
704
705 if (LibcallResult != LegalizeResult::Legalized)
707
709 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
711 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
712
713 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
714 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
715 MI.eraseFromParent();
716
718}
719
721LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
722 unsigned Size, Type *OpType,
723 LostDebugLocObserver &LocObserver) {
724 MachineFunction &MF = MIRBuilder.getMF();
725 MachineRegisterInfo &MRI = MF.getRegInfo();
726
727 Register DstFrac = MI.getOperand(0).getReg();
728 Register DstInt = MI.getOperand(1).getReg();
729 Register Src = MI.getOperand(2).getReg();
730 LLT DstTy = MRI.getType(DstFrac);
731
732 int MemSize = DstTy.getSizeInBytes();
734 const DataLayout &DL = MIRBuilder.getDataLayout();
735 unsigned AddrSpace = DL.getAllocaAddrSpace();
736 MachinePointerInfo PtrInfo;
737
738 Register StackPtrInt =
739 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
740 .getReg(0);
741
742 auto &Ctx = MF.getFunction().getContext();
743 auto LibcallResult = createLibcall(
744 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
745 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
746 LocObserver, &MI);
747
748 if (LibcallResult != LegalizeResult::Legalized)
750
752 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
753
754 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
755 MI.eraseFromParent();
756
758}
759
760static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
761 Type *FromType) {
762 auto ToMVT = MVT::getVT(ToType);
763 auto FromMVT = MVT::getVT(FromType);
764
765 switch (Opcode) {
766 case TargetOpcode::G_FPEXT:
767 return RTLIB::getFPEXT(FromMVT, ToMVT);
768 case TargetOpcode::G_FPTRUNC:
769 return RTLIB::getFPROUND(FromMVT, ToMVT);
770 case TargetOpcode::G_FPTOSI:
771 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
772 case TargetOpcode::G_FPTOUI:
773 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
774 case TargetOpcode::G_SITOFP:
775 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
776 case TargetOpcode::G_UITOFP:
777 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
778 }
779 llvm_unreachable("Unsupported libcall function");
780}
781
783 MachineInstr &MI, Type *ToType, Type *FromType,
784 LostDebugLocObserver &LocObserver, bool IsSigned) const {
785 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
786 if (FromType->isIntegerTy()) {
787 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
788 Arg.Flags[0].setSExt();
789 else
790 Arg.Flags[0].setZExt();
791 }
792
793 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
794 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
795 LocObserver, &MI);
796}
797
800 LostDebugLocObserver &LocObserver) const {
801 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
802
804 // Add all the args, except for the last which is an imm denoting 'tail'.
805 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
806 Register Reg = MI.getOperand(i).getReg();
807
808 // Need derive an IR type for call lowering.
809 LLT OpLLT = MRI.getType(Reg);
810 Type *OpTy = nullptr;
811 if (OpLLT.isPointer())
812 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
813 else
814 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
815 Args.push_back({Reg, OpTy, 0});
816 }
817
818 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
819 RTLIB::Libcall RTLibcall;
820 unsigned Opc = MI.getOpcode();
821 switch (Opc) {
822 case TargetOpcode::G_BZERO:
823 RTLibcall = RTLIB::BZERO;
824 break;
825 case TargetOpcode::G_MEMCPY:
826 RTLibcall = RTLIB::MEMCPY;
827 Args[0].Flags[0].setReturned();
828 break;
829 case TargetOpcode::G_MEMMOVE:
830 RTLibcall = RTLIB::MEMMOVE;
831 Args[0].Flags[0].setReturned();
832 break;
833 case TargetOpcode::G_MEMSET:
834 RTLibcall = RTLIB::MEMSET;
835 Args[0].Flags[0].setReturned();
836 break;
837 default:
838 llvm_unreachable("unsupported opcode");
839 }
840
841 if (!Libcalls) // FIXME: Should be mandatory
843
844 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
845
846 // Unsupported libcall on the target.
847 if (RTLibcallImpl == RTLIB::Unsupported) {
848 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
849 << MIRBuilder.getTII().getName(Opc) << "\n");
851 }
852
854 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
855
856 StringRef LibcallName =
858 Info.Callee = MachineOperand::CreateES(LibcallName.data());
859 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
860 Info.IsTailCall =
861 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
862 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI) &&
863 // Lowering doesn't support tail calling inside a function with
864 // a swifterror argument yet.
866
867 llvm::append_range(Info.OrigArgs, Args);
868 if (!CLI.lowerCall(MIRBuilder, Info))
870
871 if (Info.LoweredTailCall) {
872 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
873
874 // Check debug locations before removing the return.
875 LocObserver.checkpoint(true);
876
877 // We must have a return following the call (or debug insts) to get past
878 // isLibCallInTailPosition.
879 do {
880 MachineInstr *Next = MI.getNextNode();
881 assert(Next &&
882 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
883 "Expected instr following MI to be return or debug inst?");
884 // We lowered a tail call, so the call is now the return from the block.
885 // Delete the old return.
886 Next->eraseFromParent();
887 } while (MI.getNextNode());
888
889 // We expect to lose the debug location from the return.
890 LocObserver.checkpoint(false);
891 }
892
894}
895
896static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
897 unsigned Opc = MI.getOpcode();
898 auto &AtomicMI = cast<GMemOperation>(MI);
899 auto &MMO = AtomicMI.getMMO();
900 auto Ordering = MMO.getMergedOrdering();
901 LLT MemType = MMO.getMemoryType();
902 uint64_t MemSize = MemType.getSizeInBytes();
903 if (MemType.isVector())
904 return RTLIB::UNKNOWN_LIBCALL;
905
906#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
907#define LCALL5(A) \
908 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
909 switch (Opc) {
910 case TargetOpcode::G_ATOMIC_CMPXCHG:
911 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
912 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
913 return getOutlineAtomicHelper(LC, Ordering, MemSize);
914 }
915 case TargetOpcode::G_ATOMICRMW_XCHG: {
916 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
917 return getOutlineAtomicHelper(LC, Ordering, MemSize);
918 }
919 case TargetOpcode::G_ATOMICRMW_ADD:
920 case TargetOpcode::G_ATOMICRMW_SUB: {
921 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
922 return getOutlineAtomicHelper(LC, Ordering, MemSize);
923 }
924 case TargetOpcode::G_ATOMICRMW_AND: {
925 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
926 return getOutlineAtomicHelper(LC, Ordering, MemSize);
927 }
928 case TargetOpcode::G_ATOMICRMW_OR: {
929 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
930 return getOutlineAtomicHelper(LC, Ordering, MemSize);
931 }
932 case TargetOpcode::G_ATOMICRMW_XOR: {
933 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
934 return getOutlineAtomicHelper(LC, Ordering, MemSize);
935 }
936 default:
937 return RTLIB::UNKNOWN_LIBCALL;
938 }
939#undef LCALLS
940#undef LCALL5
941}
942
945 auto &Ctx = MIRBuilder.getContext();
946
947 Type *RetTy;
948 SmallVector<Register> RetRegs;
950 unsigned Opc = MI.getOpcode();
951 switch (Opc) {
952 case TargetOpcode::G_ATOMIC_CMPXCHG:
953 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
955 LLT SuccessLLT;
956 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
957 MI.getFirst4RegLLTs();
958 RetRegs.push_back(Ret);
959 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
960 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
961 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
962 NewLLT) = MI.getFirst5RegLLTs();
963 RetRegs.push_back(Success);
964 RetTy = StructType::get(
965 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
966 }
967 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
968 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
969 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
970 break;
971 }
972 case TargetOpcode::G_ATOMICRMW_XCHG:
973 case TargetOpcode::G_ATOMICRMW_ADD:
974 case TargetOpcode::G_ATOMICRMW_SUB:
975 case TargetOpcode::G_ATOMICRMW_AND:
976 case TargetOpcode::G_ATOMICRMW_OR:
977 case TargetOpcode::G_ATOMICRMW_XOR: {
978 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
979 RetRegs.push_back(Ret);
980 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
981 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
982 Val =
983 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
984 .getReg(0);
985 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
986 Val =
987 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
988 .getReg(0);
989 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
990 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
991 break;
992 }
993 default:
994 llvm_unreachable("unsupported opcode");
995 }
996
997 if (!Libcalls) // FIXME: Should be mandatory
999
1000 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
1001 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
1002 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
1003
1004 // Unsupported libcall on the target.
1005 if (RTLibcallImpl == RTLIB::Unsupported) {
1006 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
1007 << MIRBuilder.getTII().getName(Opc) << "\n");
1009 }
1010
1012 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1013
1014 StringRef LibcallName =
1016 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1017 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1018
1019 llvm::append_range(Info.OrigArgs, Args);
1020 if (!CLI.lowerCall(MIRBuilder, Info))
1022
1024}
1025
1026static RTLIB::Libcall
1028 RTLIB::Libcall RTLibcall;
1029 switch (MI.getOpcode()) {
1030 case TargetOpcode::G_GET_FPENV:
1031 RTLibcall = RTLIB::FEGETENV;
1032 break;
1033 case TargetOpcode::G_SET_FPENV:
1034 case TargetOpcode::G_RESET_FPENV:
1035 RTLibcall = RTLIB::FESETENV;
1036 break;
1037 case TargetOpcode::G_GET_FPMODE:
1038 RTLibcall = RTLIB::FEGETMODE;
1039 break;
1040 case TargetOpcode::G_SET_FPMODE:
1041 case TargetOpcode::G_RESET_FPMODE:
1042 RTLibcall = RTLIB::FESETMODE;
1043 break;
1044 default:
1045 llvm_unreachable("Unexpected opcode");
1046 }
1047 return RTLibcall;
1048}
1049
1050// Some library functions that read FP state (fegetmode, fegetenv) write the
1051// state into a region in memory. IR intrinsics that do the same operations
1052// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1053// intrinsics via the library functions, we need to use temporary variable,
1054// for example:
1055//
1056// %0:_(s32) = G_GET_FPMODE
1057//
1058// is transformed to:
1059//
1060// %1:_(p0) = G_FRAME_INDEX %stack.0
1061// BL &fegetmode
1062// %0:_(s32) = G_LOAD % 1
1063//
1065LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1066 LostDebugLocObserver &LocObserver) {
1067 const DataLayout &DL = MIRBuilder.getDataLayout();
1068 auto &MF = MIRBuilder.getMF();
1069 auto &MRI = *MIRBuilder.getMRI();
1070 auto &Ctx = MF.getFunction().getContext();
1071
1072 // Create temporary, where library function will put the read state.
1073 Register Dst = MI.getOperand(0).getReg();
1074 LLT StateTy = MRI.getType(Dst);
1075 TypeSize StateSize = StateTy.getSizeInBytes();
1076 Align TempAlign = getStackTemporaryAlignment(StateTy);
1077 MachinePointerInfo TempPtrInfo;
1078 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1079
1080 // Create a call to library function, with the temporary as an argument.
1081 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1082 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1083 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1084 auto Res = createLibcall(
1085 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1086 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1087 nullptr);
1088 if (Res != LegalizerHelper::Legalized)
1089 return Res;
1090
1091 // Create a load from the temporary.
1092 MachineMemOperand *MMO = MF.getMachineMemOperand(
1093 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1094 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1095
1097}
1098
1099// Similar to `createGetStateLibcall` the function calls a library function
1100// using transient space in stack. In this case the library function reads
1101// content of memory region.
1103LegalizerHelper::createSetStateLibcall(MachineInstr &MI,
1104 LostDebugLocObserver &LocObserver) {
1105 const DataLayout &DL = MIRBuilder.getDataLayout();
1106 auto &MF = MIRBuilder.getMF();
1107 auto &MRI = *MIRBuilder.getMRI();
1108 auto &Ctx = MF.getFunction().getContext();
1109
1110 // Create temporary, where library function will get the new state.
1111 Register Src = MI.getOperand(0).getReg();
1112 LLT StateTy = MRI.getType(Src);
1113 TypeSize StateSize = StateTy.getSizeInBytes();
1114 Align TempAlign = getStackTemporaryAlignment(StateTy);
1115 MachinePointerInfo TempPtrInfo;
1116 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1117
1118 // Put the new state into the temporary.
1119 MachineMemOperand *MMO = MF.getMachineMemOperand(
1120 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1121 MIRBuilder.buildStore(Src, Temp, *MMO);
1122
1123 // Create a call to library function, with the temporary as an argument.
1124 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1125 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1126 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1127 return createLibcall(RTLibcall,
1128 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1129 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1130 LocObserver, nullptr);
1131}
1132
1133/// Returns the corresponding libcall for the given Pred and
1134/// the ICMP predicate that should be generated to compare with #0
1135/// after the libcall.
1136static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1138#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1139 do { \
1140 switch (Size) { \
1141 case 32: \
1142 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1143 case 64: \
1144 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1145 case 128: \
1146 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1147 default: \
1148 llvm_unreachable("unexpected size"); \
1149 } \
1150 } while (0)
1151
1152 // These use the three-way (-1/0/1) compare libcalls, whose result is tested
1153 // against 0 with a signed integer predicate. Unordered (UO) is a boolean.
1154 switch (Pred) {
1155 case CmpInst::FCMP_OEQ:
1156 RTLIBCASE_CMP(FCMP3_PRED_OEQ_F, CmpInst::ICMP_EQ);
1157 case CmpInst::FCMP_UNE:
1158 RTLIBCASE_CMP(FCMP3_PRED_UNE_F, CmpInst::ICMP_NE);
1159 case CmpInst::FCMP_OGE:
1160 RTLIBCASE_CMP(FCMP3_PRED_OGE_F, CmpInst::ICMP_SGE);
1161 case CmpInst::FCMP_OLT:
1162 RTLIBCASE_CMP(FCMP3_PRED_OLT_F, CmpInst::ICMP_SLT);
1163 case CmpInst::FCMP_OLE:
1164 RTLIBCASE_CMP(FCMP3_PRED_OLE_F, CmpInst::ICMP_SLE);
1165 case CmpInst::FCMP_OGT:
1166 RTLIBCASE_CMP(FCMP3_PRED_OGT_F, CmpInst::ICMP_SGT);
1167 case CmpInst::FCMP_UNO:
1169 default:
1170 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1171 }
1172}
1173
1175LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1176 LostDebugLocObserver &LocObserver) {
1177 auto &MF = MIRBuilder.getMF();
1178 auto &Ctx = MF.getFunction().getContext();
1179 const GFCmp *Cmp = cast<GFCmp>(&MI);
1180
1181 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1182 unsigned Size = OpLLT.getSizeInBits();
1183 if ((Size != 32 && Size != 64 && Size != 128) ||
1184 OpLLT != MRI.getType(Cmp->getRHSReg()))
1185 return UnableToLegalize;
1186
1187 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1188
1189 // DstReg type is s32
1190 const Register DstReg = Cmp->getReg(0);
1191 LLT DstTy = MRI.getType(DstReg);
1192 const auto Cond = Cmp->getCond();
1193
1194 // Reference:
1195 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1196 // Generates a libcall followed by ICMP.
1197 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1198 const CmpInst::Predicate ICmpPred,
1199 const DstOp &Res) -> Register {
1200 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1201 LLT TempLLT = LLT::integer(32);
1202 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1203 // Generate libcall, holding result in Temp
1204 const auto Status = createLibcall(
1205 Libcall, {Temp, Type::getInt32Ty(Ctx), 0},
1206 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1207 LocObserver, &MI);
1208 if (Status != Legalized)
1209 return {};
1210
1211 // Compare temp with #0 to get the final result.
1212 return MIRBuilder
1213 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1214 .getReg(0);
1215 };
1216
1217 // Simple case if we have a direct mapping from predicate to libcall
1218 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1219 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1220 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1221 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1222 return Legalized;
1223 }
1224 return UnableToLegalize;
1225 }
1226
1227 // No direct mapping found, should be generated as combination of libcalls.
1228
1229 switch (Cond) {
1230 case CmpInst::FCMP_UEQ: {
1231 // FCMP_UEQ: unordered or equal
1232 // Convert into (FCMP_OEQ || FCMP_UNO).
1233
1234 const auto [OeqLibcall, OeqPred] =
1236 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1237
1238 const auto [UnoLibcall, UnoPred] =
1240 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1241 if (Oeq && Uno)
1242 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1243 else
1244 return UnableToLegalize;
1245
1246 break;
1247 }
1248 case CmpInst::FCMP_ONE: {
1249 // FCMP_ONE: ordered and operands are unequal
1250 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1251
1252 // We inverse the predicate instead of generating a NOT
1253 // to save one instruction.
1254 // On AArch64 isel can even select two cmp into a single ccmp.
1255 const auto [OeqLibcall, OeqPred] =
1257 const auto NotOeq =
1258 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1259
1260 const auto [UnoLibcall, UnoPred] =
1262 const auto NotUno =
1263 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1264
1265 if (NotOeq && NotUno)
1266 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1267 else
1268 return UnableToLegalize;
1269
1270 break;
1271 }
1272 case CmpInst::FCMP_ULT:
1273 case CmpInst::FCMP_UGE:
1274 case CmpInst::FCMP_UGT:
1275 case CmpInst::FCMP_ULE:
1276 case CmpInst::FCMP_ORD: {
1277 // Convert into: !(inverse(Pred))
1278 // E.g. FCMP_ULT becomes !FCMP_OGE
1279 // This is equivalent to the following, but saves some instructions.
1280 // MIRBuilder.buildNot(
1281 // PredTy,
1282 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1283 // Op1, Op2));
1284 const auto [InversedLibcall, InversedPred] =
1286 if (!BuildLibcall(InversedLibcall,
1287 CmpInst::getInversePredicate(InversedPred), DstReg))
1288 return UnableToLegalize;
1289 break;
1290 }
1291 default:
1292 return UnableToLegalize;
1293 }
1294
1295 return Legalized;
1296}
1297
1298// The function is used to legalize operations that set default environment
1299// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1300// On most targets supported in glibc FE_DFL_MODE is defined as
1301// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1302// it is not true, the target must provide custom lowering.
1304LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1305 LostDebugLocObserver &LocObserver) {
1306 const DataLayout &DL = MIRBuilder.getDataLayout();
1307 auto &MF = MIRBuilder.getMF();
1308 auto &Ctx = MF.getFunction().getContext();
1309
1310 // Create an argument for the library function.
1311 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1312 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1313 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1314 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1315 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1316 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1317 MIRBuilder.buildIntToPtr(Dest, DefValue);
1318
1319 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1320 return createLibcall(
1321 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1322 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1323}
1324
1327 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1328
1329 switch (MI.getOpcode()) {
1330 default:
1331 return UnableToLegalize;
1332 case TargetOpcode::G_MUL:
1333 case TargetOpcode::G_SDIV:
1334 case TargetOpcode::G_UDIV:
1335 case TargetOpcode::G_SREM:
1336 case TargetOpcode::G_UREM:
1337 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1338 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1339 unsigned Size = LLTy.getSizeInBits();
1340 Type *HLTy = IntegerType::get(Ctx, Size);
1341 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1342 if (Status != Legalized)
1343 return Status;
1344 break;
1345 }
1346 case TargetOpcode::G_FADD:
1347 case TargetOpcode::G_FSUB:
1348 case TargetOpcode::G_FMUL:
1349 case TargetOpcode::G_FDIV:
1350 case TargetOpcode::G_FMA:
1351 case TargetOpcode::G_FPOW:
1352 case TargetOpcode::G_FREM:
1353 case TargetOpcode::G_FCOS:
1354 case TargetOpcode::G_FSIN:
1355 case TargetOpcode::G_FTAN:
1356 case TargetOpcode::G_FACOS:
1357 case TargetOpcode::G_FASIN:
1358 case TargetOpcode::G_FATAN:
1359 case TargetOpcode::G_FATAN2:
1360 case TargetOpcode::G_FCOSH:
1361 case TargetOpcode::G_FSINH:
1362 case TargetOpcode::G_FTANH:
1363 case TargetOpcode::G_FLOG10:
1364 case TargetOpcode::G_FLOG:
1365 case TargetOpcode::G_FLOG2:
1366 case TargetOpcode::G_FEXP:
1367 case TargetOpcode::G_FEXP2:
1368 case TargetOpcode::G_FEXP10:
1369 case TargetOpcode::G_FCEIL:
1370 case TargetOpcode::G_FFLOOR:
1371 case TargetOpcode::G_FMINNUM:
1372 case TargetOpcode::G_FMAXNUM:
1373 case TargetOpcode::G_FMINIMUMNUM:
1374 case TargetOpcode::G_FMAXIMUMNUM:
1375 case TargetOpcode::G_FSQRT:
1376 case TargetOpcode::G_FRINT:
1377 case TargetOpcode::G_FNEARBYINT:
1378 case TargetOpcode::G_INTRINSIC_TRUNC:
1379 case TargetOpcode::G_INTRINSIC_ROUND:
1380 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1381 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1382 unsigned Size = LLTy.getSizeInBits();
1383 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1384 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1385 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1386 return UnableToLegalize;
1387 }
1388 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1389 if (Status != Legalized)
1390 return Status;
1391 break;
1392 }
1393 case TargetOpcode::G_FSINCOS: {
1394 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1395 unsigned Size = LLTy.getSizeInBits();
1396 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1397 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1398 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1399 return UnableToLegalize;
1400 }
1401 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1402 }
1403 case TargetOpcode::G_FMODF: {
1404 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1405 unsigned Size = LLTy.getSizeInBits();
1406 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
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 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1412 }
1413 case TargetOpcode::G_LROUND:
1414 case TargetOpcode::G_LLROUND:
1415 case TargetOpcode::G_INTRINSIC_LRINT:
1416 case TargetOpcode::G_INTRINSIC_LLRINT: {
1417 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1418 unsigned Size = LLTy.getSizeInBits();
1419 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1420 Type *ITy = IntegerType::get(
1421 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1422 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1423 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1424 return UnableToLegalize;
1425 }
1426 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1428 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1429 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1430 if (Status != Legalized)
1431 return Status;
1432 MI.eraseFromParent();
1433 return Legalized;
1434 }
1435 case TargetOpcode::G_FPOWI:
1436 case TargetOpcode::G_FLDEXP: {
1437 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1438 unsigned Size = LLTy.getSizeInBits();
1439 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1440 Type *ITy = IntegerType::get(
1441 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1442 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1443 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1444 return UnableToLegalize;
1445 }
1446 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1448 {MI.getOperand(1).getReg(), HLTy, 0},
1449 {MI.getOperand(2).getReg(), ITy, 1}};
1450 Args[1].Flags[0].setSExt();
1452 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1453 if (Status != Legalized)
1454 return Status;
1455 break;
1456 }
1457 case TargetOpcode::G_FPEXT:
1458 case TargetOpcode::G_FPTRUNC: {
1459 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1460 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1461 if (!FromTy || !ToTy)
1462 return UnableToLegalize;
1463 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1464 if (Status != Legalized)
1465 return Status;
1466 break;
1467 }
1468 case TargetOpcode::G_FCMP: {
1469 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1470 if (Status != Legalized)
1471 return Status;
1472 MI.eraseFromParent();
1473 return Status;
1474 }
1475 case TargetOpcode::G_FPTOSI:
1476 case TargetOpcode::G_FPTOUI: {
1477 // FIXME: Support other types
1478 Type *FromTy =
1479 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1480 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1481 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1482 return UnableToLegalize;
1484 FromTy, LocObserver);
1485 if (Status != Legalized)
1486 return Status;
1487 break;
1488 }
1489 case TargetOpcode::G_SITOFP:
1490 case TargetOpcode::G_UITOFP: {
1491 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1492 Type *ToTy =
1493 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1494 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1495 return UnableToLegalize;
1496 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1498 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1499 if (Status != Legalized)
1500 return Status;
1501 break;
1502 }
1503 case TargetOpcode::G_ATOMICRMW_XCHG:
1504 case TargetOpcode::G_ATOMICRMW_ADD:
1505 case TargetOpcode::G_ATOMICRMW_SUB:
1506 case TargetOpcode::G_ATOMICRMW_AND:
1507 case TargetOpcode::G_ATOMICRMW_OR:
1508 case TargetOpcode::G_ATOMICRMW_XOR:
1509 case TargetOpcode::G_ATOMIC_CMPXCHG:
1510 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1512 if (Status != Legalized)
1513 return Status;
1514 break;
1515 }
1516 case TargetOpcode::G_BZERO:
1517 case TargetOpcode::G_MEMCPY:
1518 case TargetOpcode::G_MEMMOVE:
1519 case TargetOpcode::G_MEMSET: {
1520 LegalizeResult Result =
1521 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1522 if (Result != Legalized)
1523 return Result;
1524 MI.eraseFromParent();
1525 return Result;
1526 }
1527 case TargetOpcode::G_GET_FPENV:
1528 case TargetOpcode::G_GET_FPMODE: {
1529 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1530 if (Result != Legalized)
1531 return Result;
1532 break;
1533 }
1534 case TargetOpcode::G_SET_FPENV:
1535 case TargetOpcode::G_SET_FPMODE: {
1536 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1537 if (Result != Legalized)
1538 return Result;
1539 break;
1540 }
1541 case TargetOpcode::G_RESET_FPENV:
1542 case TargetOpcode::G_RESET_FPMODE: {
1543 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1544 if (Result != Legalized)
1545 return Result;
1546 break;
1547 }
1548 }
1549
1550 MI.eraseFromParent();
1551 return Legalized;
1552}
1553
1555 unsigned TypeIdx,
1556 LLT NarrowTy) {
1557 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1558 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1559
1560 switch (MI.getOpcode()) {
1561 default:
1562 return UnableToLegalize;
1563 case TargetOpcode::G_IMPLICIT_DEF: {
1564 Register DstReg = MI.getOperand(0).getReg();
1565 LLT DstTy = MRI.getType(DstReg);
1566
1567 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1568 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1569 // FIXME: Although this would also be legal for the general case, it causes
1570 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1571 // combines not being hit). This seems to be a problem related to the
1572 // artifact combiner.
1573 if (SizeOp0 % NarrowSize != 0) {
1574 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1575 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1576 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1577
1578 MI.eraseFromParent();
1579 return Legalized;
1580 }
1581
1582 int NumParts = SizeOp0 / NarrowSize;
1583
1585 for (int i = 0; i < NumParts; ++i)
1586 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1587
1588 if (DstTy.isVector())
1589 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1590 else
1591 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1592 MI.eraseFromParent();
1593 return Legalized;
1594 }
1595 case TargetOpcode::G_CONSTANT: {
1596 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1597 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1598 unsigned TotalSize = Ty.getSizeInBits();
1599 unsigned NarrowSize = NarrowTy.getSizeInBits();
1600 int NumParts = TotalSize / NarrowSize;
1601
1602 SmallVector<Register, 4> PartRegs;
1603 for (int I = 0; I != NumParts; ++I) {
1604 unsigned Offset = I * NarrowSize;
1605 auto K = MIRBuilder.buildConstant(NarrowTy,
1606 Val.lshr(Offset).trunc(NarrowSize));
1607 PartRegs.push_back(K.getReg(0));
1608 }
1609
1610 LLT LeftoverTy;
1611 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1612 SmallVector<Register, 1> LeftoverRegs;
1613 if (LeftoverBits != 0) {
1614 LeftoverTy = LLT::scalar(LeftoverBits);
1615 auto K = MIRBuilder.buildConstant(
1616 LeftoverTy,
1617 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1618 LeftoverRegs.push_back(K.getReg(0));
1619 }
1620
1621 insertParts(MI.getOperand(0).getReg(),
1622 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1623
1624 MI.eraseFromParent();
1625 return Legalized;
1626 }
1627 case TargetOpcode::G_SEXT:
1628 case TargetOpcode::G_ZEXT:
1629 case TargetOpcode::G_ANYEXT:
1630 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1631 case TargetOpcode::G_TRUNC: {
1632 if (TypeIdx != 1)
1633 return UnableToLegalize;
1634
1635 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1636 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1637 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1638 return UnableToLegalize;
1639 }
1640
1641 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1642 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1643 MI.eraseFromParent();
1644 return Legalized;
1645 }
1646 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1647 case TargetOpcode::G_FREEZE: {
1648 if (TypeIdx != 0)
1649 return UnableToLegalize;
1650
1651 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1652 // Should widen scalar first
1653 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1654 return UnableToLegalize;
1655
1656 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1658 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1659 Parts.push_back(
1660 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1661 .getReg(0));
1662 }
1663
1664 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1665 MI.eraseFromParent();
1666 return Legalized;
1667 }
1668 case TargetOpcode::G_ADD:
1669 case TargetOpcode::G_SUB:
1670 case TargetOpcode::G_SADDO:
1671 case TargetOpcode::G_SSUBO:
1672 case TargetOpcode::G_SADDE:
1673 case TargetOpcode::G_SSUBE:
1674 case TargetOpcode::G_UADDO:
1675 case TargetOpcode::G_USUBO:
1676 case TargetOpcode::G_UADDE:
1677 case TargetOpcode::G_USUBE:
1678 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1679 case TargetOpcode::G_MUL:
1680 case TargetOpcode::G_UMULH:
1681 return narrowScalarMul(MI, NarrowTy);
1682 case TargetOpcode::G_EXTRACT:
1683 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1684 case TargetOpcode::G_INSERT:
1685 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1686 case TargetOpcode::G_LOAD: {
1687 auto &LoadMI = cast<GLoad>(MI);
1688 Register DstReg = LoadMI.getDstReg();
1689 LLT DstTy = MRI.getType(DstReg);
1690 if (DstTy.isVector())
1691 return UnableToLegalize;
1692
1693 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1694 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1695 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1696 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1697 LoadMI.eraseFromParent();
1698 return Legalized;
1699 }
1700
1701 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1702 }
1703 case TargetOpcode::G_ZEXTLOAD:
1704 case TargetOpcode::G_SEXTLOAD:
1705 case TargetOpcode::G_FPEXTLOAD: {
1706 auto &LoadMI = cast<GExtLoad>(MI);
1707 Register DstReg = LoadMI.getDstReg();
1708 Register PtrReg = LoadMI.getPointerReg();
1709
1710 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1711 auto &MMO = LoadMI.getMMO();
1712 unsigned MemSize = MMO.getSizeInBits().getValue();
1713
1714 if (MemSize == NarrowSize) {
1715 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1716 } else if (MemSize < NarrowSize) {
1717 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1718 } else if (MemSize > NarrowSize) {
1719 // FIXME: Need to split the load.
1720 return UnableToLegalize;
1721 }
1722
1723 if (isa<GZExtLoad>(LoadMI))
1724 MIRBuilder.buildZExt(DstReg, TmpReg);
1725 else if (isa<GSExtLoad>(LoadMI))
1726 MIRBuilder.buildSExt(DstReg, TmpReg);
1727 else
1728 MIRBuilder.buildFPExt(DstReg, TmpReg);
1729
1730 LoadMI.eraseFromParent();
1731 return Legalized;
1732 }
1733 case TargetOpcode::G_STORE: {
1734 auto &StoreMI = cast<GStore>(MI);
1735
1736 Register SrcReg = StoreMI.getValueReg();
1737 LLT SrcTy = MRI.getType(SrcReg);
1738 if (SrcTy.isVector())
1739 return UnableToLegalize;
1740
1741 int NumParts = SizeOp0 / NarrowSize;
1742 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1743 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1744 if (SrcTy.isVector() && LeftoverBits != 0)
1745 return UnableToLegalize;
1746
1747 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1748 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1749 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1750 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1751 StoreMI.eraseFromParent();
1752 return Legalized;
1753 }
1754
1755 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1756 }
1757 case TargetOpcode::G_FPTRUNCSTORE: {
1758 auto &StoreMI = cast<GFPTruncStore>(MI);
1759 Register SrcReg = StoreMI.getValueReg();
1760 Register PtrReg = StoreMI.getPointerReg();
1761
1762 auto &MMO = StoreMI.getMMO();
1763 unsigned MemSize = MMO.getSizeInBits().getValue();
1764 if (MemSize > NarrowSize) {
1765 return UnableToLegalize;
1766 }
1767
1768 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1769 if (MemSize == NarrowSize) {
1770 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1771 } else if (MemSize < NarrowSize) {
1772 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1773 MMO);
1774 }
1775
1776 StoreMI.eraseFromParent();
1777 return Legalized;
1778 }
1779 case TargetOpcode::G_SELECT:
1780 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1781 case TargetOpcode::G_AND:
1782 case TargetOpcode::G_OR:
1783 case TargetOpcode::G_XOR: {
1784 // Legalize bitwise operation:
1785 // A = BinOp<Ty> B, C
1786 // into:
1787 // B1, ..., BN = G_UNMERGE_VALUES B
1788 // C1, ..., CN = G_UNMERGE_VALUES C
1789 // A1 = BinOp<Ty/N> B1, C2
1790 // ...
1791 // AN = BinOp<Ty/N> BN, CN
1792 // A = G_MERGE_VALUES A1, ..., AN
1793 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1794 }
1795 case TargetOpcode::G_SHL:
1796 case TargetOpcode::G_LSHR:
1797 case TargetOpcode::G_ASHR:
1798 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1799 case TargetOpcode::G_CTLZ:
1800 case TargetOpcode::G_CTLZ_ZERO_POISON:
1801 case TargetOpcode::G_CTTZ:
1802 case TargetOpcode::G_CTTZ_ZERO_POISON:
1803 case TargetOpcode::G_CTLS:
1804 case TargetOpcode::G_CTPOP:
1805 if (TypeIdx == 1)
1806 switch (MI.getOpcode()) {
1807 case TargetOpcode::G_CTLZ:
1808 case TargetOpcode::G_CTLZ_ZERO_POISON:
1809 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1810 case TargetOpcode::G_CTTZ:
1811 case TargetOpcode::G_CTTZ_ZERO_POISON:
1812 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1813 case TargetOpcode::G_CTPOP:
1814 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1815 case TargetOpcode::G_CTLS:
1816 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1817 default:
1818 return UnableToLegalize;
1819 }
1820
1821 Observer.changingInstr(MI);
1822 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1823 Observer.changedInstr(MI);
1824 return Legalized;
1825 case TargetOpcode::G_INTTOPTR:
1826 if (TypeIdx != 1)
1827 return UnableToLegalize;
1828
1829 Observer.changingInstr(MI);
1830 narrowScalarSrc(MI, NarrowTy, 1);
1831 Observer.changedInstr(MI);
1832 return Legalized;
1833 case TargetOpcode::G_PTRTOINT:
1834 if (TypeIdx != 0)
1835 return UnableToLegalize;
1836
1837 Observer.changingInstr(MI);
1838 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1839 Observer.changedInstr(MI);
1840 return Legalized;
1841 case TargetOpcode::G_PHI: {
1842 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1843 // NarrowSize.
1844 if (SizeOp0 % NarrowSize != 0)
1845 return UnableToLegalize;
1846
1847 unsigned NumParts = SizeOp0 / NarrowSize;
1848 SmallVector<Register, 2> DstRegs(NumParts);
1849 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1850 Observer.changingInstr(MI);
1851 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1852 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1853 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1854 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1855 SrcRegs[i / 2], MIRBuilder, MRI);
1856 }
1857 MachineBasicBlock &MBB = *MI.getParent();
1858 MIRBuilder.setInsertPt(MBB, MI);
1859 for (unsigned i = 0; i < NumParts; ++i) {
1860 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1862 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1863 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1864 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1865 }
1866 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1867 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1868 Observer.changedInstr(MI);
1869 MI.eraseFromParent();
1870 return Legalized;
1871 }
1872 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1873 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1874 if (TypeIdx != 2)
1875 return UnableToLegalize;
1876
1877 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1878 Observer.changingInstr(MI);
1879 narrowScalarSrc(MI, NarrowTy, OpIdx);
1880 Observer.changedInstr(MI);
1881 return Legalized;
1882 }
1883 case TargetOpcode::G_ICMP: {
1884 Register LHS = MI.getOperand(2).getReg();
1885 LLT SrcTy = MRI.getType(LHS);
1886 CmpInst::Predicate Pred =
1887 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1888
1889 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1890 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1891 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1892 LHSLeftoverRegs, MIRBuilder, MRI))
1893 return UnableToLegalize;
1894
1895 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1896 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1897 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1898 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1899 return UnableToLegalize;
1900
1901 // We now have the LHS and RHS of the compare split into narrow-type
1902 // registers, plus potentially some leftover type.
1903 Register Dst = MI.getOperand(0).getReg();
1904 LLT ResTy = MRI.getType(Dst);
1905 if (ICmpInst::isEquality(Pred)) {
1906 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1907 // them together. For each equal part, the result should be all 0s. For
1908 // each non-equal part, we'll get at least one 1.
1909 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1911 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1912 auto LHS = std::get<0>(LHSAndRHS);
1913 auto RHS = std::get<1>(LHSAndRHS);
1914 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1915 Xors.push_back(Xor);
1916 }
1917
1918 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1919 // to the desired narrow type so that we can OR them together later.
1920 SmallVector<Register, 4> WidenedXors;
1921 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1922 auto LHS = std::get<0>(LHSAndRHS);
1923 auto RHS = std::get<1>(LHSAndRHS);
1924 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1925 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1926 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1927 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1928 llvm::append_range(Xors, WidenedXors);
1929 }
1930
1931 // Now, for each part we broke up, we know if they are equal/not equal
1932 // based off the G_XOR. We can OR these all together and compare against
1933 // 0 to get the result.
1934 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1935 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1936 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1937 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1938 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1939 } else {
1940 Register CmpIn;
1941 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1942 Register CmpOut;
1943 CmpInst::Predicate PartPred;
1944
1945 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1946 PartPred = Pred;
1947 CmpOut = Dst;
1948 } else {
1949 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1950 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1951 }
1952
1953 if (!CmpIn) {
1954 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1955 RHSPartRegs[I]);
1956 } else {
1957 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1958 RHSPartRegs[I]);
1959 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1960 LHSPartRegs[I], RHSPartRegs[I]);
1961 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1962 }
1963
1964 CmpIn = CmpOut;
1965 }
1966
1967 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1968 Register CmpOut;
1969 CmpInst::Predicate PartPred;
1970
1971 if (I == E - 1) {
1972 PartPred = Pred;
1973 CmpOut = Dst;
1974 } else {
1975 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1976 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1977 }
1978
1979 if (!CmpIn) {
1980 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1981 RHSLeftoverRegs[I]);
1982 } else {
1983 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1984 RHSLeftoverRegs[I]);
1985 auto CmpEq =
1986 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1987 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1988 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1989 }
1990
1991 CmpIn = CmpOut;
1992 }
1993 }
1994 MI.eraseFromParent();
1995 return Legalized;
1996 }
1997 case TargetOpcode::G_FCMP:
1998 if (TypeIdx != 0)
1999 return UnableToLegalize;
2000
2001 Observer.changingInstr(MI);
2002 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
2003 Observer.changedInstr(MI);
2004 return Legalized;
2005
2006 case TargetOpcode::G_SEXT_INREG: {
2007 if (TypeIdx != 0)
2008 return UnableToLegalize;
2009
2010 int64_t SizeInBits = MI.getOperand(2).getImm();
2011
2012 // So long as the new type has more bits than the bits we're extending we
2013 // don't need to break it apart.
2014 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2015 Observer.changingInstr(MI);
2016 // We don't lose any non-extension bits by truncating the src and
2017 // sign-extending the dst.
2018 MachineOperand &MO1 = MI.getOperand(1);
2019 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2020 MO1.setReg(TruncMIB.getReg(0));
2021
2022 MachineOperand &MO2 = MI.getOperand(0);
2023 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2024 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2025 MIRBuilder.buildSExt(MO2, DstExt);
2026 MO2.setReg(DstExt);
2027 Observer.changedInstr(MI);
2028 return Legalized;
2029 }
2030
2031 // Break it apart. Components below the extension point are unmodified. The
2032 // component containing the extension point becomes a narrower SEXT_INREG.
2033 // Components above it are ashr'd from the component containing the
2034 // extension point.
2035 if (SizeOp0 % NarrowSize != 0)
2036 return UnableToLegalize;
2037 int NumParts = SizeOp0 / NarrowSize;
2038
2039 // List the registers where the destination will be scattered.
2041 // List the registers where the source will be split.
2043
2044 // Create all the temporary registers.
2045 for (int i = 0; i < NumParts; ++i) {
2046 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2047
2048 SrcRegs.push_back(SrcReg);
2049 }
2050
2051 // Explode the big arguments into smaller chunks.
2052 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2053
2054 Register AshrCstReg =
2055 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2056 .getReg(0);
2057 Register FullExtensionReg;
2058 Register PartialExtensionReg;
2059
2060 // Do the operation on each small part.
2061 for (int i = 0; i < NumParts; ++i) {
2062 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2063 DstRegs.push_back(SrcRegs[i]);
2064 PartialExtensionReg = DstRegs.back();
2065 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2066 assert(PartialExtensionReg &&
2067 "Expected to visit partial extension before full");
2068 if (FullExtensionReg) {
2069 DstRegs.push_back(FullExtensionReg);
2070 continue;
2071 }
2072 DstRegs.push_back(
2073 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2074 .getReg(0));
2075 FullExtensionReg = DstRegs.back();
2076 } else {
2077 DstRegs.push_back(
2079 .buildInstr(
2080 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2081 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2082 .getReg(0));
2083 PartialExtensionReg = DstRegs.back();
2084 }
2085 }
2086
2087 // Gather the destination registers into the final destination.
2088 Register DstReg = MI.getOperand(0).getReg();
2089 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2090 MI.eraseFromParent();
2091 return Legalized;
2092 }
2093 case TargetOpcode::G_BSWAP:
2094 case TargetOpcode::G_BITREVERSE: {
2095 if (SizeOp0 % NarrowSize != 0)
2096 return UnableToLegalize;
2097
2098 Observer.changingInstr(MI);
2099 SmallVector<Register, 2> SrcRegs, DstRegs;
2100 unsigned NumParts = SizeOp0 / NarrowSize;
2101 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2102 MIRBuilder, MRI);
2103
2104 for (unsigned i = 0; i < NumParts; ++i) {
2105 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2106 {SrcRegs[NumParts - 1 - i]});
2107 DstRegs.push_back(DstPart.getReg(0));
2108 }
2109
2110 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2111
2112 Observer.changedInstr(MI);
2113 MI.eraseFromParent();
2114 return Legalized;
2115 }
2116 case TargetOpcode::G_PTR_ADD:
2117 case TargetOpcode::G_PTRMASK: {
2118 if (TypeIdx != 1)
2119 return UnableToLegalize;
2120 Observer.changingInstr(MI);
2121 narrowScalarSrc(MI, NarrowTy, 2);
2122 Observer.changedInstr(MI);
2123 return Legalized;
2124 }
2125 case TargetOpcode::G_FPTOUI:
2126 case TargetOpcode::G_FPTOSI:
2127 case TargetOpcode::G_FPTOUI_SAT:
2128 case TargetOpcode::G_FPTOSI_SAT:
2129 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2130 case TargetOpcode::G_FPEXT:
2131 if (TypeIdx != 0)
2132 return UnableToLegalize;
2133 Observer.changingInstr(MI);
2134 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2135 Observer.changedInstr(MI);
2136 return Legalized;
2137 case TargetOpcode::G_FLDEXP:
2138 case TargetOpcode::G_STRICT_FLDEXP:
2139 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2140 case TargetOpcode::G_VSCALE: {
2141 Register Dst = MI.getOperand(0).getReg();
2142 LLT Ty = MRI.getType(Dst);
2143
2144 // Assume VSCALE(1) fits into a legal integer
2145 const APInt One(NarrowTy.getSizeInBits(), 1);
2146 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2147 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2148 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2149 MIRBuilder.buildMul(Dst, ZExt, C);
2150
2151 MI.eraseFromParent();
2152 return Legalized;
2153 }
2154 }
2155}
2156
2158 LLT Ty = MRI.getType(Val);
2159 if (Ty.isScalar() && !Ty.isFloat())
2160 return Val;
2161
2162 const DataLayout &DL = MIRBuilder.getDataLayout();
2163 LLT NewTy = LLT::integer(Ty.getSizeInBits());
2164
2165 if (Ty.isFloat())
2166 return MIRBuilder.buildBitcast(NewTy, Val).getReg(0);
2167
2168 if (Ty.isPointer()) {
2169 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2170 return Register();
2171 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2172 }
2173
2174 Register NewVal = Val;
2175
2176 assert(Ty.isVector());
2177 if (Ty.isPointerVector())
2178 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2179 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2180}
2181
2183 unsigned OpIdx, unsigned ExtOpcode) {
2184 MachineOperand &MO = MI.getOperand(OpIdx);
2185 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2186 MO.setReg(ExtB.getReg(0));
2187}
2188
2190 unsigned OpIdx) {
2191 MachineOperand &MO = MI.getOperand(OpIdx);
2192 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2193 MI.getFlags());
2194 MO.setReg(ExtB.getReg(0));
2195}
2196
2198 unsigned OpIdx) {
2199 MachineOperand &MO = MI.getOperand(OpIdx);
2200 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2201 MO.setReg(ExtB.getReg(0));
2202}
2203
2205 unsigned OpIdx, unsigned TruncOpcode) {
2206 MachineOperand &MO = MI.getOperand(OpIdx);
2207 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2208 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2209 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2210 MO.setReg(DstExt);
2211}
2212
2214 unsigned OpIdx) {
2215 MachineOperand &MO = MI.getOperand(OpIdx);
2216 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2217 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2218 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2219 MO.setReg(DstExt);
2220}
2221
2223 unsigned OpIdx, unsigned ExtOpcode) {
2224 MachineOperand &MO = MI.getOperand(OpIdx);
2225 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2226 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2227 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2228 MO.setReg(DstTrunc);
2229}
2230
2232 unsigned OpIdx) {
2233 MachineOperand &MO = MI.getOperand(OpIdx);
2234 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2235 Register Dst = MO.getReg();
2236 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2237 MO.setReg(DstExt);
2238 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2239}
2240
2242 unsigned OpIdx) {
2243 MachineOperand &MO = MI.getOperand(OpIdx);
2244 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2245}
2246
2247void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2248 MachineOperand &Op = MI.getOperand(OpIdx);
2249 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2250}
2251
2252void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2253 MachineOperand &MO = MI.getOperand(OpIdx);
2254 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2255 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2256 MIRBuilder.buildBitcast(MO, CastDst);
2257 MO.setReg(CastDst);
2258}
2259
2261LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2262 LLT WideTy) {
2263 if (TypeIdx != 1)
2264 return UnableToLegalize;
2265
2266 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2267 if (DstTy.isVector())
2268 return UnableToLegalize;
2269
2270 LLT SrcTy = MRI.getType(Src1Reg);
2271 const int DstSize = DstTy.getSizeInBits();
2272 const int SrcSize = SrcTy.getSizeInBits();
2273 const int WideSize = WideTy.getSizeInBits();
2274 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2275
2276 unsigned NumOps = MI.getNumOperands();
2277 unsigned NumSrc = MI.getNumOperands() - 1;
2278 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2279
2280 if (WideSize >= DstSize) {
2281 // Directly pack the bits in the target type.
2282 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2283
2284 for (unsigned I = 2; I != NumOps; ++I) {
2285 const unsigned Offset = (I - 1) * PartSize;
2286
2287 Register SrcReg = MI.getOperand(I).getReg();
2288 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2289
2290 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2291
2292 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2293 MRI.createGenericVirtualRegister(WideTy);
2294
2295 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2296 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2297 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2298 ResultReg = NextResult;
2299 }
2300
2301 if (WideSize > DstSize)
2302 MIRBuilder.buildTrunc(DstReg, ResultReg);
2303 else if (DstTy.isPointer())
2304 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2305 else if (DstTy != WideTy)
2306 MIRBuilder.buildBitcast(DstReg, ResultReg);
2307
2308 MI.eraseFromParent();
2309 return Legalized;
2310 }
2311
2312 // Unmerge the original values to the GCD type, and recombine to the next
2313 // multiple greater than the original type.
2314 //
2315 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2316 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2317 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2318 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2319 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2320 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2321 // %12:_(s12) = G_MERGE_VALUES %10, %11
2322 //
2323 // Padding with undef if necessary:
2324 //
2325 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2326 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2327 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2328 // %7:_(s2) = G_IMPLICIT_DEF
2329 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2330 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2331 // %10:_(s12) = G_MERGE_VALUES %8, %9
2332
2333 const int GCD = std::gcd(SrcSize, WideSize);
2334 LLT GCDTy = WideTy.changeElementSize(GCD);
2335
2336 SmallVector<Register, 8> NewMergeRegs;
2337 SmallVector<Register, 8> Unmerges;
2338 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2339
2340 // Decompose the original operands if they don't evenly divide.
2341 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2342 Register SrcReg = MO.getReg();
2343 if (GCD == SrcSize) {
2344 Unmerges.push_back(SrcReg);
2345 } else {
2346 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2347 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2348 Unmerges.push_back(Unmerge.getReg(J));
2349 }
2350 }
2351
2352 // Pad with undef to the next size that is a multiple of the requested size.
2353 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2354 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2355 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2356 Unmerges.push_back(UndefReg);
2357 }
2358
2359 const int PartsPerGCD = WideSize / GCD;
2360
2361 // Build merges of each piece.
2362 ArrayRef<Register> Slicer(Unmerges);
2363 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2364 auto Merge =
2365 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2366 NewMergeRegs.push_back(Merge.getReg(0));
2367 }
2368
2369 // A truncate may be necessary if the requested type doesn't evenly divide the
2370 // original result type.
2371 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2372 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2373 } else {
2374 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2375 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2376 }
2377
2378 MI.eraseFromParent();
2379 return Legalized;
2380}
2381
2383LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2384 LLT WideTy) {
2385 if (TypeIdx != 0)
2386 return UnableToLegalize;
2387
2388 int NumDst = MI.getNumOperands() - 1;
2389 Register SrcReg = MI.getOperand(NumDst).getReg();
2390 LLT SrcTy = MRI.getType(SrcReg);
2391 if (SrcTy.isVector())
2392 return UnableToLegalize;
2393
2394 Register Dst0Reg = MI.getOperand(0).getReg();
2395 LLT DstTy = MRI.getType(Dst0Reg);
2396 if (!DstTy.isScalar())
2397 return UnableToLegalize;
2398
2399 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2400 if (SrcTy.isPointer()) {
2401 const DataLayout &DL = MIRBuilder.getDataLayout();
2402 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2403 LLVM_DEBUG(
2404 dbgs() << "Not casting non-integral address space integer\n");
2405 return UnableToLegalize;
2406 }
2407
2408 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2409 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2410 }
2411
2412 // Widen SrcTy to WideTy. This does not affect the result, but since the
2413 // user requested this size, it is probably better handled than SrcTy and
2414 // should reduce the total number of legalization artifacts.
2415 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2416 SrcTy = WideTy;
2417 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2418 }
2419
2420 // Theres no unmerge type to target. Directly extract the bits from the
2421 // source type
2422 unsigned DstSize = DstTy.getSizeInBits();
2423
2424 if (SrcTy.isFloat()) {
2425 SrcReg = coerceToInteger(SrcReg);
2426 SrcTy = MRI.getType(SrcReg);
2427 }
2428
2429 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2430 for (int I = 1; I != NumDst; ++I) {
2431 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2432 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2433 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2434 }
2435
2436 MI.eraseFromParent();
2437 return Legalized;
2438 }
2439
2440 // Extend the source to a wider type.
2441 LLT LCMTy = getLCMType(SrcTy, WideTy);
2442
2443 Register WideSrc = SrcReg;
2444 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2445 // TODO: If this is an integral address space, cast to integer and anyext.
2446 if (SrcTy.isPointer()) {
2447 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2448 return UnableToLegalize;
2449 }
2450
2451 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2452 }
2453
2454 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2455
2456 // Create a sequence of unmerges and merges to the original results. Since we
2457 // may have widened the source, we will need to pad the results with dead defs
2458 // to cover the source register.
2459 // e.g. widen s48 to s64:
2460 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2461 //
2462 // =>
2463 // %4:_(s192) = G_ANYEXT %0:_(s96)
2464 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2465 // ; unpack to GCD type, with extra dead defs
2466 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2467 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2468 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2469 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2470 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2471 const LLT GCDTy = getGCDType(WideTy, DstTy);
2472 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2473 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2474
2475 // Directly unmerge to the destination without going through a GCD type
2476 // if possible
2477 if (PartsPerRemerge == 1) {
2478 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2479
2480 for (int I = 0; I != NumUnmerge; ++I) {
2481 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2482
2483 for (int J = 0; J != PartsPerUnmerge; ++J) {
2484 int Idx = I * PartsPerUnmerge + J;
2485 if (Idx < NumDst)
2486 MIB.addDef(MI.getOperand(Idx).getReg());
2487 else {
2488 // Create dead def for excess components.
2489 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2490 }
2491 }
2492
2493 MIB.addUse(Unmerge.getReg(I));
2494 }
2495 } else {
2496 SmallVector<Register, 16> Parts;
2497 for (int J = 0; J != NumUnmerge; ++J)
2498 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2499
2500 SmallVector<Register, 8> RemergeParts;
2501 for (int I = 0; I != NumDst; ++I) {
2502 for (int J = 0; J < PartsPerRemerge; ++J) {
2503 const int Idx = I * PartsPerRemerge + J;
2504 RemergeParts.emplace_back(Parts[Idx]);
2505 }
2506
2507 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2508 RemergeParts.clear();
2509 }
2510 }
2511
2512 MI.eraseFromParent();
2513 return Legalized;
2514}
2515
2517LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2518 LLT WideTy) {
2519 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2520 unsigned Offset = MI.getOperand(2).getImm();
2521
2522 if (TypeIdx == 0) {
2523 if (SrcTy.isVector() || DstTy.isVector())
2524 return UnableToLegalize;
2525
2526 SrcOp Src(SrcReg);
2527 if (SrcTy.isPointer()) {
2528 // Extracts from pointers can be handled only if they are really just
2529 // simple integers.
2530 const DataLayout &DL = MIRBuilder.getDataLayout();
2531 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2532 return UnableToLegalize;
2533
2534 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2535 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2536 SrcTy = SrcAsIntTy;
2537 }
2538
2539 if (DstTy.isPointer())
2540 return UnableToLegalize;
2541
2542 if (Offset == 0) {
2543 // Avoid a shift in the degenerate case.
2544 MIRBuilder.buildTrunc(DstReg,
2545 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2546 MI.eraseFromParent();
2547 return Legalized;
2548 }
2549
2550 // Do a shift in the source type.
2551 LLT ShiftTy = SrcTy;
2552 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2553 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2554 ShiftTy = WideTy;
2555 }
2556
2557 auto LShr = MIRBuilder.buildLShr(
2558 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2559 MIRBuilder.buildTrunc(DstReg, LShr);
2560 MI.eraseFromParent();
2561 return Legalized;
2562 }
2563
2564 if (SrcTy.isScalar()) {
2565 Observer.changingInstr(MI);
2566 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2567 Observer.changedInstr(MI);
2568 return Legalized;
2569 }
2570
2571 if (!SrcTy.isVector())
2572 return UnableToLegalize;
2573
2574 if (DstTy != SrcTy.getElementType())
2575 return UnableToLegalize;
2576
2577 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2578 return UnableToLegalize;
2579
2580 Observer.changingInstr(MI);
2581 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2582
2583 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2584 Offset);
2585 widenScalarDst(MI, WideTy.getScalarType(), 0);
2586 Observer.changedInstr(MI);
2587 return Legalized;
2588}
2589
2591LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2592 LLT WideTy) {
2593 if (TypeIdx != 0 || WideTy.isVector())
2594 return UnableToLegalize;
2595 Observer.changingInstr(MI);
2596 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2597 widenScalarDst(MI, WideTy);
2598 Observer.changedInstr(MI);
2599 return Legalized;
2600}
2601
2603LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2604 LLT WideTy) {
2605 unsigned Opcode;
2606 unsigned ExtOpcode;
2607 std::optional<Register> CarryIn;
2608 switch (MI.getOpcode()) {
2609 default:
2610 llvm_unreachable("Unexpected opcode!");
2611 case TargetOpcode::G_SADDO:
2612 Opcode = TargetOpcode::G_ADD;
2613 ExtOpcode = TargetOpcode::G_SEXT;
2614 break;
2615 case TargetOpcode::G_SSUBO:
2616 Opcode = TargetOpcode::G_SUB;
2617 ExtOpcode = TargetOpcode::G_SEXT;
2618 break;
2619 case TargetOpcode::G_UADDO:
2620 Opcode = TargetOpcode::G_ADD;
2621 ExtOpcode = TargetOpcode::G_ZEXT;
2622 break;
2623 case TargetOpcode::G_USUBO:
2624 Opcode = TargetOpcode::G_SUB;
2625 ExtOpcode = TargetOpcode::G_ZEXT;
2626 break;
2627 case TargetOpcode::G_SADDE:
2628 Opcode = TargetOpcode::G_UADDE;
2629 ExtOpcode = TargetOpcode::G_SEXT;
2630 CarryIn = MI.getOperand(4).getReg();
2631 break;
2632 case TargetOpcode::G_SSUBE:
2633 Opcode = TargetOpcode::G_USUBE;
2634 ExtOpcode = TargetOpcode::G_SEXT;
2635 CarryIn = MI.getOperand(4).getReg();
2636 break;
2637 case TargetOpcode::G_UADDE:
2638 Opcode = TargetOpcode::G_UADDE;
2639 ExtOpcode = TargetOpcode::G_ZEXT;
2640 CarryIn = MI.getOperand(4).getReg();
2641 break;
2642 case TargetOpcode::G_USUBE:
2643 Opcode = TargetOpcode::G_USUBE;
2644 ExtOpcode = TargetOpcode::G_ZEXT;
2645 CarryIn = MI.getOperand(4).getReg();
2646 break;
2647 }
2648
2649 if (TypeIdx == 1) {
2650 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2651
2652 Observer.changingInstr(MI);
2653 if (CarryIn)
2654 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2655 widenScalarDst(MI, WideTy, 1);
2656
2657 Observer.changedInstr(MI);
2658 return Legalized;
2659 }
2660
2661 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2662 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2663 // Do the arithmetic in the larger type.
2664 Register NewOp;
2665 if (CarryIn) {
2666 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2667 NewOp = MIRBuilder
2668 .buildInstr(Opcode, {WideTy, CarryOutTy},
2669 {LHSExt, RHSExt, *CarryIn})
2670 .getReg(0);
2671 } else {
2672 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2673 }
2674 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2675 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2676 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2677 // There is no overflow if the ExtOp is the same as NewOp.
2678 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2679 // Now trunc the NewOp to the original result.
2680 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2681 MI.eraseFromParent();
2682 return Legalized;
2683}
2684
2686LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2687 LLT WideTy) {
2688 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2689 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2690 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2691 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2692 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2693 // We can convert this to:
2694 // 1. Any extend iN to iM
2695 // 2. SHL by M-N
2696 // 3. [US][ADD|SUB|SHL]SAT
2697 // 4. L/ASHR by M-N
2698 //
2699 // It may be more efficient to lower this to a min and a max operation in
2700 // the higher precision arithmetic if the promoted operation isn't legal,
2701 // but this decision is up to the target's lowering request.
2702 Register DstReg = MI.getOperand(0).getReg();
2703
2704 unsigned NewBits = WideTy.getScalarSizeInBits();
2705 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2706
2707 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2708 // must not left shift the RHS to preserve the shift amount.
2709 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2710 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2711 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2712 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2713 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2714 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2715
2716 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2717 {ShiftL, ShiftR}, MI.getFlags());
2718
2719 // Use a shift that will preserve the number of sign bits when the trunc is
2720 // folded away.
2721 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2722 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2723
2724 MIRBuilder.buildTrunc(DstReg, Result);
2725 MI.eraseFromParent();
2726 return Legalized;
2727}
2728
2730LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2731 LLT WideTy) {
2732 if (TypeIdx == 1) {
2733 Observer.changingInstr(MI);
2734 widenScalarDst(MI, WideTy, 1);
2735 Observer.changedInstr(MI);
2736 return Legalized;
2737 }
2738
2739 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2740 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2741 LLT SrcTy = MRI.getType(LHS);
2742 LLT OverflowTy = MRI.getType(OriginalOverflow);
2743 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2744
2745 // To determine if the result overflowed in the larger type, we extend the
2746 // input to the larger type, do the multiply (checking if it overflows),
2747 // then also check the high bits of the result to see if overflow happened
2748 // there.
2749 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2750 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2751 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2752
2753 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2754 // so we don't need to check the overflow result of larger type Mulo.
2755 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2756
2757 unsigned MulOpc =
2758 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2759
2760 MachineInstrBuilder Mulo;
2761 if (WideMulCanOverflow)
2762 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2763 {LeftOperand, RightOperand});
2764 else
2765 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2766
2767 auto Mul = Mulo->getOperand(0);
2768 MIRBuilder.buildTrunc(Result, Mul);
2769
2770 MachineInstrBuilder ExtResult;
2771 // Overflow occurred if it occurred in the larger type, or if the high part
2772 // of the result does not zero/sign-extend the low part. Check this second
2773 // possibility first.
2774 if (IsSigned) {
2775 // For signed, overflow occurred when the high part does not sign-extend
2776 // the low part.
2777 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2778 } else {
2779 // Unsigned overflow occurred when the high part does not zero-extend the
2780 // low part.
2781 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2782 }
2783
2784 if (WideMulCanOverflow) {
2785 auto Overflow =
2786 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2787 // Finally check if the multiplication in the larger type itself overflowed.
2788 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2789 } else {
2790 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2791 }
2792 MI.eraseFromParent();
2793 return Legalized;
2794}
2795
2798 unsigned Opcode = MI.getOpcode();
2799 switch (Opcode) {
2800 default:
2801 return UnableToLegalize;
2802 case TargetOpcode::G_ATOMICRMW_XCHG:
2803 case TargetOpcode::G_ATOMICRMW_ADD:
2804 case TargetOpcode::G_ATOMICRMW_SUB:
2805 case TargetOpcode::G_ATOMICRMW_AND:
2806 case TargetOpcode::G_ATOMICRMW_OR:
2807 case TargetOpcode::G_ATOMICRMW_XOR:
2808 case TargetOpcode::G_ATOMICRMW_MIN:
2809 case TargetOpcode::G_ATOMICRMW_MAX:
2810 case TargetOpcode::G_ATOMICRMW_UMIN:
2811 case TargetOpcode::G_ATOMICRMW_UMAX:
2812 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2813 Observer.changingInstr(MI);
2814 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2815 widenScalarDst(MI, WideTy, 0);
2816 Observer.changedInstr(MI);
2817 return Legalized;
2818 case TargetOpcode::G_ATOMIC_CMPXCHG:
2819 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2820 Observer.changingInstr(MI);
2821 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2822 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2823 widenScalarDst(MI, WideTy, 0);
2824 Observer.changedInstr(MI);
2825 return Legalized;
2826 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2827 if (TypeIdx == 0) {
2828 Observer.changingInstr(MI);
2829 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2830 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2831 widenScalarDst(MI, WideTy, 0);
2832 Observer.changedInstr(MI);
2833 return Legalized;
2834 }
2835 assert(TypeIdx == 1 &&
2836 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2837 Observer.changingInstr(MI);
2838 widenScalarDst(MI, WideTy, 1);
2839 Observer.changedInstr(MI);
2840 return Legalized;
2841 case TargetOpcode::G_EXTRACT:
2842 return widenScalarExtract(MI, TypeIdx, WideTy);
2843 case TargetOpcode::G_INSERT:
2844 return widenScalarInsert(MI, TypeIdx, WideTy);
2845 case TargetOpcode::G_MERGE_VALUES:
2846 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2847 case TargetOpcode::G_UNMERGE_VALUES:
2848 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2849 case TargetOpcode::G_SADDO:
2850 case TargetOpcode::G_SSUBO:
2851 case TargetOpcode::G_UADDO:
2852 case TargetOpcode::G_USUBO:
2853 case TargetOpcode::G_SADDE:
2854 case TargetOpcode::G_SSUBE:
2855 case TargetOpcode::G_UADDE:
2856 case TargetOpcode::G_USUBE:
2857 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2858 case TargetOpcode::G_UMULO:
2859 case TargetOpcode::G_SMULO:
2860 return widenScalarMulo(MI, TypeIdx, WideTy);
2861 case TargetOpcode::G_SADDSAT:
2862 case TargetOpcode::G_SSUBSAT:
2863 case TargetOpcode::G_SSHLSAT:
2864 case TargetOpcode::G_UADDSAT:
2865 case TargetOpcode::G_USUBSAT:
2866 case TargetOpcode::G_USHLSAT:
2867 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2868 case TargetOpcode::G_CTTZ:
2869 case TargetOpcode::G_CTTZ_ZERO_POISON:
2870 case TargetOpcode::G_CTLZ:
2871 case TargetOpcode::G_CTLZ_ZERO_POISON:
2872 case TargetOpcode::G_CTLS:
2873 case TargetOpcode::G_CTPOP: {
2874 if (TypeIdx == 0) {
2875 Observer.changingInstr(MI);
2876 widenScalarDst(MI, WideTy, 0);
2877 Observer.changedInstr(MI);
2878 return Legalized;
2879 }
2880
2881 Register SrcReg = MI.getOperand(1).getReg();
2882
2883 // First extend the input.
2884 unsigned ExtOpc;
2885 switch (Opcode) {
2886 case TargetOpcode::G_CTTZ:
2887 case TargetOpcode::G_CTTZ_ZERO_POISON:
2888 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2889 ExtOpc = TargetOpcode::G_ANYEXT;
2890 break;
2891 case TargetOpcode::G_CTLS:
2892 ExtOpc = TargetOpcode::G_SEXT;
2893 break;
2894 default:
2895 ExtOpc = TargetOpcode::G_ZEXT;
2896 }
2897
2898 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2899 LLT CurTy = MRI.getType(SrcReg);
2900 unsigned NewOpc = Opcode;
2901 if (NewOpc == TargetOpcode::G_CTTZ) {
2902 // The count is the same in the larger type except if the original
2903 // value was zero. This can be handled by setting the bit just off
2904 // the top of the original type.
2905 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2906 CurTy.getScalarSizeInBits());
2907 MIBSrc = MIRBuilder.buildOr(
2908 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2909 // Now we know the operand is non-zero, use the more relaxed opcode.
2910 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2911 }
2912
2913 unsigned SizeDiff =
2914 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2915
2916 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2917 // An optimization where the result is the CTLZ after the left shift by
2918 // (Difference in widety and current ty), that is,
2919 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2920 // Result = ctlz MIBSrc
2921 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2922 MIRBuilder.buildConstant(WideTy, SizeDiff));
2923 }
2924
2925 // Perform the operation at the larger size.
2926 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2927 // This is already the correct result for CTPOP and CTTZs
2928 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2929 // The correct result is NewOp - (Difference in widety and current ty).
2930 // At this stage SUB is guaranteed to be positive no-wrap,
2931 // that to be used in further KnownBits optimizations for CTLZ.
2932 MIBNewOp = MIRBuilder.buildSub(
2933 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2934 Opcode == TargetOpcode::G_CTLZ
2935 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2936 : std::nullopt);
2937 }
2938
2939 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2940 MI.eraseFromParent();
2941 return Legalized;
2942 }
2943 case TargetOpcode::G_BSWAP: {
2944 Observer.changingInstr(MI);
2945 Register DstReg = MI.getOperand(0).getReg();
2946
2947 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2948 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2949 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2950 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2951
2952 MI.getOperand(0).setReg(DstExt);
2953
2954 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2955
2956 LLT Ty = MRI.getType(DstReg);
2957 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2958 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2959 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2960
2961 MIRBuilder.buildTrunc(DstReg, ShrReg);
2962 Observer.changedInstr(MI);
2963 return Legalized;
2964 }
2965 case TargetOpcode::G_BITREVERSE: {
2966 Observer.changingInstr(MI);
2967
2968 Register DstReg = MI.getOperand(0).getReg();
2969 LLT Ty = MRI.getType(DstReg);
2970 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2971
2972 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2973 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2974 MI.getOperand(0).setReg(DstExt);
2975 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2976
2977 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2978 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2979 MIRBuilder.buildTrunc(DstReg, Shift);
2980 Observer.changedInstr(MI);
2981 return Legalized;
2982 }
2983 case TargetOpcode::G_FREEZE:
2984 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2985 Observer.changingInstr(MI);
2986 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2987 widenScalarDst(MI, WideTy);
2988 Observer.changedInstr(MI);
2989 return Legalized;
2990
2991 case TargetOpcode::G_ABS:
2992 Observer.changingInstr(MI);
2993 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2994 widenScalarDst(MI, WideTy);
2995 Observer.changedInstr(MI);
2996 return Legalized;
2997
2998 case TargetOpcode::G_ADD:
2999 case TargetOpcode::G_AND:
3000 case TargetOpcode::G_MUL:
3001 case TargetOpcode::G_OR:
3002 case TargetOpcode::G_XOR:
3003 case TargetOpcode::G_SUB:
3004 case TargetOpcode::G_SHUFFLE_VECTOR:
3005 // Perform operation at larger width (any extension is fines here, high bits
3006 // don't affect the result) and then truncate the result back to the
3007 // original type.
3008 Observer.changingInstr(MI);
3009 // The G_ANYEXTs below leave the new high bits unconstrained, so no-wrap and
3010 // disjoint claims proved at the narrow width no longer hold. Paths that
3011 // widen with value-preserving G_ZEXT/G_SEXT keep their flags.
3014 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3015 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3016 widenScalarDst(MI, WideTy);
3017 Observer.changedInstr(MI);
3018 return Legalized;
3019
3020 case TargetOpcode::G_SBFX:
3021 case TargetOpcode::G_UBFX:
3022 Observer.changingInstr(MI);
3023
3024 if (TypeIdx == 0) {
3025 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3026 widenScalarDst(MI, WideTy);
3027 } else {
3028 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3029 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3030 }
3031
3032 Observer.changedInstr(MI);
3033 return Legalized;
3034
3035 case TargetOpcode::G_SHL:
3036 Observer.changingInstr(MI);
3037
3038 if (TypeIdx == 0) {
3039 // Widening the result with G_ANYEXT invalidates the no-wrap flags, as in
3040 // the G_ADD/G_SUB/G_MUL case above. TypeIdx 1 widens only the shift
3041 // amount, which is value-preserving, so it keeps them.
3043 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3044 widenScalarDst(MI, WideTy);
3045 } else {
3046 assert(TypeIdx == 1);
3047 // The "number of bits to shift" operand must preserve its value as an
3048 // unsigned integer:
3049 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3050 }
3051
3052 Observer.changedInstr(MI);
3053 return Legalized;
3054
3055 case TargetOpcode::G_ROTR:
3056 case TargetOpcode::G_ROTL:
3057 if (TypeIdx != 1)
3058 return UnableToLegalize;
3059
3060 Observer.changingInstr(MI);
3061 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3062 Observer.changedInstr(MI);
3063 return Legalized;
3064
3065 case TargetOpcode::G_SDIV:
3066 case TargetOpcode::G_SREM:
3067 case TargetOpcode::G_SMIN:
3068 case TargetOpcode::G_SMAX:
3069 case TargetOpcode::G_ABDS:
3070 Observer.changingInstr(MI);
3071 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3072 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3073 widenScalarDst(MI, WideTy);
3074 Observer.changedInstr(MI);
3075 return Legalized;
3076
3077 case TargetOpcode::G_SDIVREM:
3078 Observer.changingInstr(MI);
3079 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3080 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3081 widenScalarDst(MI, WideTy);
3082 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3083 widenScalarDst(MI, WideTy, 1);
3084 Observer.changedInstr(MI);
3085 return Legalized;
3086
3087 case TargetOpcode::G_ASHR:
3088 case TargetOpcode::G_LSHR:
3089 Observer.changingInstr(MI);
3090
3091 if (TypeIdx == 0) {
3092 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3093 : TargetOpcode::G_ZEXT;
3094
3095 widenScalarSrc(MI, WideTy, 1, CvtOp);
3096 widenScalarDst(MI, WideTy);
3097 } else {
3098 assert(TypeIdx == 1);
3099 // The "number of bits to shift" operand must preserve its value as an
3100 // unsigned integer:
3101 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3102 }
3103
3104 Observer.changedInstr(MI);
3105 return Legalized;
3106 case TargetOpcode::G_UDIV:
3107 case TargetOpcode::G_UREM:
3108 case TargetOpcode::G_ABDU:
3109 Observer.changingInstr(MI);
3110 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3111 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3112 widenScalarDst(MI, WideTy);
3113 Observer.changedInstr(MI);
3114 return Legalized;
3115 case TargetOpcode::G_UDIVREM:
3116 Observer.changingInstr(MI);
3117 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3118 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3119 widenScalarDst(MI, WideTy);
3120 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3121 widenScalarDst(MI, WideTy, 1);
3122 Observer.changedInstr(MI);
3123 return Legalized;
3124 case TargetOpcode::G_UMIN:
3125 case TargetOpcode::G_UMAX: {
3126 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3127
3128 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3129 unsigned ExtOpc =
3130 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3131 getApproximateEVTForLLT(WideTy, Ctx))
3132 ? TargetOpcode::G_SEXT
3133 : TargetOpcode::G_ZEXT;
3134
3135 Observer.changingInstr(MI);
3136 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3137 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3138 widenScalarDst(MI, WideTy);
3139 Observer.changedInstr(MI);
3140 return Legalized;
3141 }
3142
3143 case TargetOpcode::G_SELECT:
3144 Observer.changingInstr(MI);
3145 if (TypeIdx == 0) {
3146 // Perform operation at larger width (any extension is fine here, high
3147 // bits don't affect the result) and then truncate the result back to the
3148 // original type.
3149 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3150 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3151 widenScalarDst(MI, WideTy);
3152 } else {
3153 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3154 // Explicit extension is required here since high bits affect the result.
3155 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3156 }
3157 Observer.changedInstr(MI);
3158 return Legalized;
3159
3160 case TargetOpcode::G_FPEXT:
3161 if (TypeIdx != 1)
3162 return UnableToLegalize;
3163
3164 Observer.changingInstr(MI);
3165 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3166 Observer.changedInstr(MI);
3167 return Legalized;
3168 case TargetOpcode::G_FPTOSI:
3169 case TargetOpcode::G_FPTOUI:
3170 case TargetOpcode::G_INTRINSIC_LRINT:
3171 case TargetOpcode::G_INTRINSIC_LLRINT:
3172 case TargetOpcode::G_IS_FPCLASS:
3173 Observer.changingInstr(MI);
3174
3175 if (TypeIdx == 0)
3176 widenScalarDst(MI, WideTy);
3177 else
3178 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3179
3180 Observer.changedInstr(MI);
3181 return Legalized;
3182 case TargetOpcode::G_SITOFP:
3183 Observer.changingInstr(MI);
3184
3185 if (TypeIdx == 0)
3186 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3187 else
3188 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3189
3190 Observer.changedInstr(MI);
3191 return Legalized;
3192 case TargetOpcode::G_UITOFP:
3193 Observer.changingInstr(MI);
3194
3195 if (TypeIdx == 0)
3196 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3197 else
3198 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3199
3200 Observer.changedInstr(MI);
3201 return Legalized;
3202 case TargetOpcode::G_FPTOSI_SAT:
3203 case TargetOpcode::G_FPTOUI_SAT:
3204 Observer.changingInstr(MI);
3205
3206 if (TypeIdx == 0) {
3207 Register OldDst = MI.getOperand(0).getReg();
3208 LLT Ty = MRI.getType(OldDst);
3209 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3210 Register NewDst;
3211 MI.getOperand(0).setReg(ExtReg);
3212 uint64_t ShortBits = Ty.getScalarSizeInBits();
3213 uint64_t WideBits = WideTy.getScalarSizeInBits();
3214 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3215 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3216 // z = i16 fptosi_sat(a)
3217 // ->
3218 // x = i32 fptosi_sat(a)
3219 // y = smin(x, 32767)
3220 // z = smax(y, -32768)
3221 auto MaxVal = MIRBuilder.buildConstant(
3222 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3223 auto MinVal = MIRBuilder.buildConstant(
3224 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3225 Register MidReg =
3226 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3227 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3228 } else {
3229 // z = i16 fptoui_sat(a)
3230 // ->
3231 // x = i32 fptoui_sat(a)
3232 // y = smin(x, 65535)
3233 auto MaxVal = MIRBuilder.buildConstant(
3234 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3235 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3236 }
3237 MIRBuilder.buildTrunc(OldDst, NewDst);
3238 } else
3239 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3240
3241 Observer.changedInstr(MI);
3242 return Legalized;
3243 case TargetOpcode::G_LOAD:
3244 case TargetOpcode::G_SEXTLOAD:
3245 case TargetOpcode::G_ZEXTLOAD:
3246 case TargetOpcode::G_FPEXTLOAD:
3247 Observer.changingInstr(MI);
3248 widenScalarDst(MI, WideTy);
3249 Observer.changedInstr(MI);
3250 return Legalized;
3251
3252 case TargetOpcode::G_STORE: {
3253 if (TypeIdx != 0)
3254 return UnableToLegalize;
3255
3256 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3257 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3258 if (!Ty.isScalar()) {
3259 // We need to widen the vector element type.
3260 Observer.changingInstr(MI);
3261 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3262 // We also need to adjust the MMO to turn this into a truncating store.
3263 MachineMemOperand &MMO = **MI.memoperands_begin();
3264 MachineFunction &MF = MIRBuilder.getMF();
3265 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3266 MI.setMemRefs(MF, {NewMMO});
3267 Observer.changedInstr(MI);
3268 return Legalized;
3269 }
3270
3271 Observer.changingInstr(MI);
3272
3273 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3274 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3275 widenScalarSrc(MI, WideTy, 0, ExtType);
3276
3277 Observer.changedInstr(MI);
3278 return Legalized;
3279 }
3280 case TargetOpcode::G_FPTRUNCSTORE:
3281 if (TypeIdx != 0)
3282 return UnableToLegalize;
3283 Observer.changingInstr(MI);
3284 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3285 Observer.changedInstr(MI);
3286 return Legalized;
3287 case TargetOpcode::G_CONSTANT: {
3288 MachineOperand &SrcMO = MI.getOperand(1);
3289 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3290 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3291 MRI.getType(MI.getOperand(0).getReg()));
3292 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3293 ExtOpc == TargetOpcode::G_ANYEXT) &&
3294 "Illegal Extend");
3295 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3296 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3297 ? SrcVal.sext(WideTy.getSizeInBits())
3298 : SrcVal.zext(WideTy.getSizeInBits());
3299 Observer.changingInstr(MI);
3300 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3301
3302 widenScalarDst(MI, WideTy);
3303 Observer.changedInstr(MI);
3304 return Legalized;
3305 }
3306 case TargetOpcode::G_FCONSTANT: {
3307 // To avoid changing the bits of the constant due to extension to a larger
3308 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3309 MachineOperand &SrcMO = MI.getOperand(1);
3310 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3311 MIRBuilder.setInstrAndDebugLoc(MI);
3312 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3313 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3314 MI.eraseFromParent();
3315 return Legalized;
3316 }
3317 case TargetOpcode::G_IMPLICIT_DEF: {
3318 Observer.changingInstr(MI);
3319 widenScalarDst(MI, WideTy);
3320 Observer.changedInstr(MI);
3321 return Legalized;
3322 }
3323 case TargetOpcode::G_BRCOND:
3324 Observer.changingInstr(MI);
3325 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3326 Observer.changedInstr(MI);
3327 return Legalized;
3328
3329 case TargetOpcode::G_FCMP:
3330 Observer.changingInstr(MI);
3331 if (TypeIdx == 0)
3332 widenScalarDst(MI, WideTy);
3333 else {
3334 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3335 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3336 }
3337 Observer.changedInstr(MI);
3338 return Legalized;
3339
3340 case TargetOpcode::G_ICMP:
3341 Observer.changingInstr(MI);
3342 if (TypeIdx == 0)
3343 widenScalarDst(MI, WideTy);
3344 else {
3345 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3346 CmpInst::Predicate Pred =
3347 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3348
3349 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3350 unsigned ExtOpcode =
3351 (CmpInst::isSigned(Pred) ||
3352 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3353 getApproximateEVTForLLT(WideTy, Ctx)))
3354 ? TargetOpcode::G_SEXT
3355 : TargetOpcode::G_ZEXT;
3356 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3357 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3358 }
3359 Observer.changedInstr(MI);
3360 return Legalized;
3361
3362 case TargetOpcode::G_PTR_ADD:
3363 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3364 Observer.changingInstr(MI);
3365 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3366 Observer.changedInstr(MI);
3367 return Legalized;
3368
3369 case TargetOpcode::G_PHI: {
3370 assert(TypeIdx == 0 && "Expecting only Idx 0");
3371
3372 Observer.changingInstr(MI);
3373 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3374 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3375 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3376 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3377 }
3378
3379 MachineBasicBlock &MBB = *MI.getParent();
3380 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3381 widenScalarDst(MI, WideTy);
3382 Observer.changedInstr(MI);
3383 return Legalized;
3384 }
3385 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3386 if (TypeIdx == 0) {
3387 Register VecReg = MI.getOperand(1).getReg();
3388 LLT VecTy = MRI.getType(VecReg);
3389 Observer.changingInstr(MI);
3390
3391 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3392 TargetOpcode::G_ANYEXT);
3393
3394 widenScalarDst(MI, WideTy, 0);
3395 Observer.changedInstr(MI);
3396 return Legalized;
3397 }
3398
3399 if (TypeIdx != 2)
3400 return UnableToLegalize;
3401 Observer.changingInstr(MI);
3402 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3403 Observer.changedInstr(MI);
3404 return Legalized;
3405 }
3406 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3407 if (TypeIdx == 0) {
3408 Observer.changingInstr(MI);
3409 const LLT WideEltTy = WideTy.getElementType();
3410
3411 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3412 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3413 widenScalarDst(MI, WideTy, 0);
3414 Observer.changedInstr(MI);
3415 return Legalized;
3416 }
3417
3418 if (TypeIdx == 1) {
3419 Observer.changingInstr(MI);
3420
3421 Register VecReg = MI.getOperand(1).getReg();
3422 LLT VecTy = MRI.getType(VecReg);
3423 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3424
3425 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3426 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3427 widenScalarDst(MI, WideVecTy, 0);
3428 Observer.changedInstr(MI);
3429 return Legalized;
3430 }
3431
3432 if (TypeIdx == 2) {
3433 Observer.changingInstr(MI);
3434 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3435 Observer.changedInstr(MI);
3436 return Legalized;
3437 }
3438
3439 return UnableToLegalize;
3440 }
3441 case TargetOpcode::G_FADD:
3442 case TargetOpcode::G_FMUL:
3443 case TargetOpcode::G_FSUB:
3444 case TargetOpcode::G_FMA:
3445 case TargetOpcode::G_FMAD:
3446 case TargetOpcode::G_FNEG:
3447 case TargetOpcode::G_FABS:
3448 case TargetOpcode::G_FCANONICALIZE:
3449 case TargetOpcode::G_FMINNUM:
3450 case TargetOpcode::G_FMAXNUM:
3451 case TargetOpcode::G_FMINNUM_IEEE:
3452 case TargetOpcode::G_FMAXNUM_IEEE:
3453 case TargetOpcode::G_FMINIMUM:
3454 case TargetOpcode::G_FMAXIMUM:
3455 case TargetOpcode::G_FMINIMUMNUM:
3456 case TargetOpcode::G_FMAXIMUMNUM:
3457 case TargetOpcode::G_FDIV:
3458 case TargetOpcode::G_FREM:
3459 case TargetOpcode::G_FCEIL:
3460 case TargetOpcode::G_FFLOOR:
3461 case TargetOpcode::G_FCOS:
3462 case TargetOpcode::G_FSIN:
3463 case TargetOpcode::G_FTAN:
3464 case TargetOpcode::G_FACOS:
3465 case TargetOpcode::G_FASIN:
3466 case TargetOpcode::G_FATAN:
3467 case TargetOpcode::G_FATAN2:
3468 case TargetOpcode::G_FCOSH:
3469 case TargetOpcode::G_FSINH:
3470 case TargetOpcode::G_FTANH:
3471 case TargetOpcode::G_FLOG10:
3472 case TargetOpcode::G_FLOG:
3473 case TargetOpcode::G_FLOG2:
3474 case TargetOpcode::G_FRINT:
3475 case TargetOpcode::G_FNEARBYINT:
3476 case TargetOpcode::G_FSQRT:
3477 case TargetOpcode::G_FEXP:
3478 case TargetOpcode::G_FEXP2:
3479 case TargetOpcode::G_FEXP10:
3480 case TargetOpcode::G_FPOW:
3481 case TargetOpcode::G_INTRINSIC_TRUNC:
3482 case TargetOpcode::G_INTRINSIC_ROUND:
3483 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3484 assert(TypeIdx == 0);
3485 Observer.changingInstr(MI);
3486
3487 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3488 widenScalarSrcUsingFPExt(MI, WideTy, I);
3489
3490 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3491 Observer.changedInstr(MI);
3492 return Legalized;
3493 case TargetOpcode::G_FMODF: {
3494 Observer.changingInstr(MI);
3495 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3496
3497 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3498 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3499 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3500 Observer.changedInstr(MI);
3501 return Legalized;
3502 }
3503 case TargetOpcode::G_FPOWI:
3504 case TargetOpcode::G_FLDEXP:
3505 case TargetOpcode::G_STRICT_FLDEXP: {
3506 if (TypeIdx == 0) {
3507 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3508 return UnableToLegalize;
3509
3510 Observer.changingInstr(MI);
3511 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3512 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3513 Observer.changedInstr(MI);
3514 return Legalized;
3515 }
3516
3517 if (TypeIdx == 1) {
3518 // For some reason SelectionDAG tries to promote to a libcall without
3519 // actually changing the integer type for promotion.
3520 Observer.changingInstr(MI);
3521 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3522 Observer.changedInstr(MI);
3523 return Legalized;
3524 }
3525
3526 return UnableToLegalize;
3527 }
3528 case TargetOpcode::G_FFREXP: {
3529 Observer.changingInstr(MI);
3530
3531 if (TypeIdx == 0) {
3532 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3533 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3534 } else {
3535 widenScalarDst(MI, WideTy, 1);
3536 }
3537
3538 Observer.changedInstr(MI);
3539 return Legalized;
3540 }
3541 case TargetOpcode::G_LROUND:
3542 case TargetOpcode::G_LLROUND:
3543 Observer.changingInstr(MI);
3544
3545 if (TypeIdx == 0)
3546 widenScalarDst(MI, WideTy);
3547 else
3548 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3549
3550 Observer.changedInstr(MI);
3551 return Legalized;
3552
3553 case TargetOpcode::G_INTTOPTR:
3554 if (TypeIdx != 1)
3555 return UnableToLegalize;
3556
3557 Observer.changingInstr(MI);
3558 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3559 Observer.changedInstr(MI);
3560 return Legalized;
3561 case TargetOpcode::G_PTRTOINT:
3562 if (TypeIdx != 0)
3563 return UnableToLegalize;
3564
3565 Observer.changingInstr(MI);
3566 widenScalarDst(MI, WideTy, 0);
3567 Observer.changedInstr(MI);
3568 return Legalized;
3569 case TargetOpcode::G_BUILD_VECTOR: {
3570 Observer.changingInstr(MI);
3571
3572 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3573 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3574 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3575
3576 // Avoid changing the result vector type if the source element type was
3577 // requested.
3578 if (TypeIdx == 1) {
3579 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3580 } else {
3581 widenScalarDst(MI, WideTy, 0);
3582 }
3583
3584 Observer.changedInstr(MI);
3585 return Legalized;
3586 }
3587 case TargetOpcode::G_SEXT_INREG:
3588 if (TypeIdx != 0)
3589 return UnableToLegalize;
3590
3591 Observer.changingInstr(MI);
3592 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3593 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3594 Observer.changedInstr(MI);
3595 return Legalized;
3596 case TargetOpcode::G_PTRMASK: {
3597 if (TypeIdx != 1)
3598 return UnableToLegalize;
3599 Observer.changingInstr(MI);
3600 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3601 Observer.changedInstr(MI);
3602 return Legalized;
3603 }
3604 case TargetOpcode::G_VECREDUCE_ADD: {
3605 if (TypeIdx != 1)
3606 return UnableToLegalize;
3607 Observer.changingInstr(MI);
3608 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3609 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3610 Observer.changedInstr(MI);
3611 return Legalized;
3612 }
3613 case TargetOpcode::G_VECREDUCE_FADD:
3614 case TargetOpcode::G_VECREDUCE_FMUL:
3615 case TargetOpcode::G_VECREDUCE_FMIN:
3616 case TargetOpcode::G_VECREDUCE_FMAX:
3617 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3618 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3619 if (TypeIdx != 0)
3620 return UnableToLegalize;
3621 Observer.changingInstr(MI);
3622 Register VecReg = MI.getOperand(1).getReg();
3623 LLT VecTy = MRI.getType(VecReg);
3624 LLT WideVecTy = VecTy.changeElementType(WideTy);
3625 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3626 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3627 Observer.changedInstr(MI);
3628 return Legalized;
3629 }
3630 case TargetOpcode::G_VSCALE: {
3631 MachineOperand &SrcMO = MI.getOperand(1);
3632 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3633 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3634 // The CImm is always a signed value
3635 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3636 Observer.changingInstr(MI);
3637 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3638 widenScalarDst(MI, WideTy);
3639 Observer.changedInstr(MI);
3640 return Legalized;
3641 }
3642 case TargetOpcode::G_SPLAT_VECTOR: {
3643 if (TypeIdx != 1)
3644 return UnableToLegalize;
3645
3646 Observer.changingInstr(MI);
3647 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3648 Observer.changedInstr(MI);
3649 return Legalized;
3650 }
3651 case TargetOpcode::G_INSERT_SUBVECTOR: {
3652 if (TypeIdx != 0)
3653 return UnableToLegalize;
3654
3656 Register BigVec = IS.getBigVec();
3657 Register SubVec = IS.getSubVec();
3658
3659 LLT SubVecTy = MRI.getType(SubVec);
3660 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3661
3662 // Widen the G_INSERT_SUBVECTOR
3663 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3664 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3665 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3666 IS.getIndexImm());
3667
3668 // Truncate back down
3669 auto SplatZero = MIRBuilder.buildSplatVector(
3670 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3671 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3672 SplatZero);
3673
3674 MI.eraseFromParent();
3675
3676 return Legalized;
3677 }
3678 case TargetOpcode::G_BITCAST:
3679 if (WideTy.isVector())
3680 return UnableToLegalize;
3681 Observer.changingInstr(MI);
3682 if (TypeIdx == 0)
3683 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3684 else
3685 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3686 Observer.changedInstr(MI);
3687
3688 Register Dst = MI.getOperand(0).getReg();
3689 Register Src = MI.getOperand(1).getReg();
3690 if (MRI.getType(Dst) == MRI.getType(Src)) {
3691 Observer.changingAllUsesOfReg(MRI, Dst);
3692 MRI.replaceRegWith(Dst, Src);
3693 Observer.finishedChangingAllUsesOfReg();
3694 MI.eraseFromParent();
3695 }
3696
3697 return Legalized;
3698 }
3699}
3700
3702 MachineIRBuilder &B, Register Src, LLT Ty) {
3703 auto Unmerge = B.buildUnmerge(Ty, Src);
3704 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3705 Pieces.push_back(Unmerge.getReg(I));
3706}
3707
3708static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3709 MachineIRBuilder &MIRBuilder) {
3710 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3711 MachineFunction &MF = MIRBuilder.getMF();
3712 const DataLayout &DL = MIRBuilder.getDataLayout();
3713 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3714 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3715 LLT DstLLT = MRI.getType(DstReg);
3716
3717 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3718
3719 auto Addr = MIRBuilder.buildConstantPool(
3720 AddrPtrTy,
3721 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3722
3723 MachineMemOperand *MMO =
3725 MachineMemOperand::MOLoad, DstLLT, Alignment);
3726
3727 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3728}
3729
3732 const MachineOperand &ConstOperand = MI.getOperand(1);
3733 const Constant *ConstantVal = ConstOperand.getCImm();
3734
3735 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3736 MI.eraseFromParent();
3737
3738 return Legalized;
3739}
3740
3743 const MachineOperand &ConstOperand = MI.getOperand(1);
3744 const Constant *ConstantVal = ConstOperand.getFPImm();
3745
3746 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3747 MI.eraseFromParent();
3748
3749 return Legalized;
3750}
3751
3754 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3755 if (SrcTy.isVector()) {
3756 LLT SrcEltTy = SrcTy.getElementType();
3758
3759 if (DstTy.isVector()) {
3760 int NumDstElt = DstTy.getNumElements();
3761 int NumSrcElt = SrcTy.getNumElements();
3762
3763 LLT DstEltTy = DstTy.getElementType();
3764 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3765 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3766
3767 // If there's an element size mismatch, insert intermediate casts to match
3768 // the result element type.
3769 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3770 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3771 //
3772 // =>
3773 //
3774 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3775 // %3:_(<2 x s8>) = G_BITCAST %2
3776 // %4:_(<2 x s8>) = G_BITCAST %3
3777 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3778 DstCastTy = DstTy.changeVectorElementCount(
3779 ElementCount::getFixed(NumDstElt / NumSrcElt));
3780 SrcPartTy = SrcEltTy;
3781 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3782 //
3783 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3784 //
3785 // =>
3786 //
3787 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3788 // %3:_(s16) = G_BITCAST %2
3789 // %4:_(s16) = G_BITCAST %3
3790 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3791 SrcPartTy = SrcTy.changeVectorElementCount(
3792 ElementCount::getFixed(NumSrcElt / NumDstElt));
3793 DstCastTy = DstEltTy;
3794 }
3795
3796 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3797 for (Register &SrcReg : SrcRegs)
3798 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3799 } else
3800 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3801
3802 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3803 MI.eraseFromParent();
3804 return Legalized;
3805 }
3806
3807 if (DstTy.isVector()) {
3809 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3810 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3811 MI.eraseFromParent();
3812 return Legalized;
3813 }
3814
3815 return UnableToLegalize;
3816}
3817
3818/// Figure out the bit offset into a register when coercing a vector index for
3819/// the wide element type. This is only for the case when promoting vector to
3820/// one with larger elements.
3821//
3822///
3823/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3824/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3826 Register Idx,
3827 unsigned NewEltSize,
3828 unsigned OldEltSize) {
3829 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3830 LLT IdxTy = B.getMRI()->getType(Idx);
3831
3832 // Now figure out the amount we need to shift to get the target bits.
3833 auto OffsetMask = B.buildConstant(
3834 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3835 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3836 return B.buildShl(IdxTy, OffsetIdx,
3837 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3838}
3839
3840/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3841/// is casting to a vector with a smaller element size, perform multiple element
3842/// extracts and merge the results. If this is coercing to a vector with larger
3843/// elements, index the bitcasted vector and extract the target element with bit
3844/// operations. This is intended to force the indexing in the native register
3845/// size for architectures that can dynamically index the register file.
3848 LLT CastTy) {
3849 if (TypeIdx != 1)
3850 return UnableToLegalize;
3851
3852 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3853
3854 LLT SrcEltTy = SrcVecTy.getElementType();
3855 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3856 unsigned OldNumElts = SrcVecTy.getNumElements();
3857
3858 LLT NewEltTy = CastTy.getScalarType();
3859 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3860
3861 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3862 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3863 if (NewNumElts > OldNumElts) {
3864 // Decreasing the vector element size
3865 //
3866 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3867 // =>
3868 // v4i32:castx = bitcast x:v2i64
3869 //
3870 // i64 = bitcast
3871 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3872 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3873 //
3874 if (NewNumElts % OldNumElts != 0)
3875 return UnableToLegalize;
3876
3877 // Type of the intermediate result vector.
3878 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3879 LLT MidTy =
3880 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3881
3882 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3883
3884 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3885 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3886
3887 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3888 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3889 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3890 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3891 NewOps[I] = Elt.getReg(0);
3892 }
3893
3894 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3895 MIRBuilder.buildBitcast(Dst, NewVec);
3896 MI.eraseFromParent();
3897 return Legalized;
3898 }
3899
3900 if (NewNumElts < OldNumElts) {
3901 if (NewEltSize % OldEltSize != 0)
3902 return UnableToLegalize;
3903
3904 // This only depends on powers of 2 because we use bit tricks to figure out
3905 // the bit offset we need to shift to get the target element. A general
3906 // expansion could emit division/multiply.
3907 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3908 return UnableToLegalize;
3909
3910 // Increasing the vector element size.
3911 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3912 //
3913 // =>
3914 //
3915 // %cast = G_BITCAST %vec
3916 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3917 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3918 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3919 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3920 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3921 // %elt = G_TRUNC %elt_bits
3922
3923 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3924 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3925
3926 // Divide to get the index in the wider element type.
3927 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3928
3929 Register WideElt = CastVec;
3930 if (CastTy.isVector()) {
3931 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3932 ScaledIdx).getReg(0);
3933 }
3934
3935 // Compute the bit offset into the register of the target element.
3937 MIRBuilder, Idx, NewEltSize, OldEltSize);
3938
3939 // Shift the wide element to get the target element.
3940 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3941 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3942 MI.eraseFromParent();
3943 return Legalized;
3944 }
3945
3946 return UnableToLegalize;
3947}
3948
3949/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3950/// TargetReg, while preserving other bits in \p TargetReg.
3951///
3952/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3954 Register TargetReg, Register InsertReg,
3955 Register OffsetBits) {
3956 LLT TargetTy = B.getMRI()->getType(TargetReg);
3957 LLT InsertTy = B.getMRI()->getType(InsertReg);
3958 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3959 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3960
3961 // Produce a bitmask of the value to insert
3962 auto EltMask = B.buildConstant(
3963 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3964 InsertTy.getSizeInBits()));
3965 // Shift it into position
3966 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3967 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3968
3969 // Clear out the bits in the wide element
3970 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3971
3972 // The value to insert has all zeros already, so stick it into the masked
3973 // wide element.
3974 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3975}
3976
3977/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3978/// is increasing the element size, perform the indexing in the target element
3979/// type, and use bit operations to insert at the element position. This is
3980/// intended for architectures that can dynamically index the register file and
3981/// want to force indexing in the native register size.
3984 LLT CastTy) {
3985 if (TypeIdx != 0)
3986 return UnableToLegalize;
3987
3988 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3989 MI.getFirst4RegLLTs();
3990 LLT VecTy = DstTy;
3991
3992 LLT VecEltTy = VecTy.getElementType();
3993 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3994 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3995 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3996
3997 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3998 unsigned OldNumElts = VecTy.getNumElements();
3999
4000 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
4001 if (NewNumElts < OldNumElts) {
4002 if (NewEltSize % OldEltSize != 0)
4003 return UnableToLegalize;
4004
4005 // This only depends on powers of 2 because we use bit tricks to figure out
4006 // the bit offset we need to shift to get the target element. A general
4007 // expansion could emit division/multiply.
4008 if (!isPowerOf2_32(NewEltSize / OldEltSize))
4009 return UnableToLegalize;
4010
4011 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4012 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4013
4014 // Divide to get the index in the wider element type.
4015 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4016
4017 Register ExtractedElt = CastVec;
4018 if (CastTy.isVector()) {
4019 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4020 ScaledIdx).getReg(0);
4021 }
4022
4023 // Compute the bit offset into the register of the target element.
4025 MIRBuilder, Idx, NewEltSize, OldEltSize);
4026
4027 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
4028 Val, OffsetBits);
4029 if (CastTy.isVector()) {
4030 InsertedElt = MIRBuilder.buildInsertVectorElement(
4031 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
4032 }
4033
4034 MIRBuilder.buildBitcast(Dst, InsertedElt);
4035 MI.eraseFromParent();
4036 return Legalized;
4037 }
4038
4039 return UnableToLegalize;
4040}
4041
4042// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4043// those that have smaller than legal operands.
4044//
4045// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4046//
4047// ===>
4048//
4049// s32 = G_BITCAST <4 x s8>
4050// s32 = G_BITCAST <4 x s8>
4051// s32 = G_BITCAST <4 x s8>
4052// s32 = G_BITCAST <4 x s8>
4053// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4054// <16 x s8> = G_BITCAST <4 x s32>
4057 LLT CastTy) {
4058 // Convert it to CONCAT instruction
4059 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4060 if (!ConcatMI) {
4061 return UnableToLegalize;
4062 }
4063
4064 // Check if bitcast is Legal
4065 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4066 LLT SrcScalTy = CastTy.getScalarType();
4067
4068 // Check if the build vector is Legal
4069 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4070 return UnableToLegalize;
4071 }
4072
4073 // Bitcast the sources
4074 SmallVector<Register> BitcastRegs;
4075 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4076 BitcastRegs.push_back(
4077 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4078 .getReg(0));
4079 }
4080
4081 // Build the scalar values into a vector
4082 Register BuildReg =
4083 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4084 MIRBuilder.buildBitcast(DstReg, BuildReg);
4085
4086 MI.eraseFromParent();
4087 return Legalized;
4088}
4089
4090// This bitcasts a shuffle vector to a different type currently of the same
4091// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4092// will be used instead.
4093//
4094// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4095// ===>
4096// <4 x s64> = G_PTRTOINT <4 x p0>
4097// <4 x s64> = G_PTRTOINT <4 x p0>
4098// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4099// <16 x p0> = G_INTTOPTR <16 x s64>
4102 LLT CastTy) {
4103 auto ShuffleMI = cast<GShuffleVector>(&MI);
4104 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4105 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4106
4107 // We currently only handle vectors of the same size.
4108 if (TypeIdx != 0 ||
4109 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4110 CastTy.getElementCount() != DstTy.getElementCount())
4111 return UnableToLegalize;
4112
4113 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4114
4115 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4116 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4117 auto Shuf =
4118 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4119 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4120
4121 MI.eraseFromParent();
4122 return Legalized;
4123}
4124
4125/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4126///
4127/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4128///
4129/// ===>
4130///
4131/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4132/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4133/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4136 LLT CastTy) {
4137 auto ES = cast<GExtractSubvector>(&MI);
4138
4139 if (!CastTy.isVector())
4140 return UnableToLegalize;
4141
4142 if (TypeIdx != 0)
4143 return UnableToLegalize;
4144
4145 Register Dst = ES->getReg(0);
4146 Register Src = ES->getSrcVec();
4147 uint64_t Idx = ES->getIndexImm();
4148
4149 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4150
4151 LLT DstTy = MRI.getType(Dst);
4152 LLT SrcTy = MRI.getType(Src);
4153 ElementCount DstTyEC = DstTy.getElementCount();
4154 ElementCount SrcTyEC = SrcTy.getElementCount();
4155 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4156 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4157
4158 if (DstTy == CastTy)
4159 return Legalized;
4160
4161 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4162 return UnableToLegalize;
4163
4164 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4165 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4166 if (CastEltSize < DstEltSize)
4167 return UnableToLegalize;
4168
4169 auto AdjustAmt = CastEltSize / DstEltSize;
4170 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4171 SrcTyMinElts % AdjustAmt != 0)
4172 return UnableToLegalize;
4173
4174 Idx /= AdjustAmt;
4175 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4176 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4177 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4178 MIRBuilder.buildBitcast(Dst, PromotedES);
4179
4180 ES->eraseFromParent();
4181 return Legalized;
4182}
4183
4184/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4185///
4186/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4187/// <vscale x 8 x i1>,
4188/// N
4189///
4190/// ===>
4191///
4192/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4193/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4194/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4195/// <vscale x 1 x i8>, N / 8
4196/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4199 LLT CastTy) {
4200 auto ES = cast<GInsertSubvector>(&MI);
4201
4202 if (!CastTy.isVector())
4203 return UnableToLegalize;
4204
4205 if (TypeIdx != 0)
4206 return UnableToLegalize;
4207
4208 Register Dst = ES->getReg(0);
4209 Register BigVec = ES->getBigVec();
4210 Register SubVec = ES->getSubVec();
4211 uint64_t Idx = ES->getIndexImm();
4212
4213 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4214
4215 LLT DstTy = MRI.getType(Dst);
4216 LLT BigVecTy = MRI.getType(BigVec);
4217 LLT SubVecTy = MRI.getType(SubVec);
4218
4219 if (DstTy == CastTy)
4220 return Legalized;
4221
4222 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4223 return UnableToLegalize;
4224
4225 ElementCount DstTyEC = DstTy.getElementCount();
4226 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4227 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4228 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4229 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4230 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4231
4232 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4233 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4234 if (CastEltSize < DstEltSize)
4235 return UnableToLegalize;
4236
4237 auto AdjustAmt = CastEltSize / DstEltSize;
4238 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4239 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4240 return UnableToLegalize;
4241
4242 Idx /= AdjustAmt;
4243 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4244 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4245 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4246 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4247 auto PromotedIS =
4248 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4249 MIRBuilder.buildBitcast(Dst, PromotedIS);
4250
4251 ES->eraseFromParent();
4252 return Legalized;
4253}
4254
4256 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4257 Register DstReg = LoadMI.getDstReg();
4258 Register PtrReg = LoadMI.getPointerReg();
4259 LLT DstTy = MRI.getType(DstReg);
4260 MachineMemOperand &MMO = LoadMI.getMMO();
4261 LLT MemTy = MMO.getMemoryType();
4262 MachineFunction &MF = MIRBuilder.getMF();
4263
4264 LLT EltTy = MemTy.getScalarType();
4265
4266 unsigned MemSizeInBits = MemTy.getSizeInBits();
4267 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4268
4269 if (MemSizeInBits != MemStoreSizeInBits) {
4270 if (MemTy.isVector())
4271 return UnableToLegalize;
4272
4273 // Promote to a byte-sized load if not loading an integral number of
4274 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4275 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4276 MachineMemOperand *NewMMO =
4277 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4278
4279 Register LoadReg = DstReg;
4280 LLT LoadTy = DstTy;
4281
4282 // If this wasn't already an extending load, we need to widen the result
4283 // register to avoid creating a load with a narrower result than the source.
4284 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4285 LoadTy = WideMemTy;
4286 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4287 }
4288
4289 if (isa<GSExtLoad>(LoadMI)) {
4290 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4291 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4292 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4293 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4294 // The extra bits are guaranteed to be zero, since we stored them that
4295 // way. A zext load from Wide thus automatically gives zext from MemVT.
4296 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4297 } else {
4298 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4299 }
4300
4301 if (DstTy != LoadTy)
4302 MIRBuilder.buildTrunc(DstReg, LoadReg);
4303
4304 LoadMI.eraseFromParent();
4305 return Legalized;
4306 }
4307
4308 // Big endian lowering not implemented.
4309 if (MIRBuilder.getDataLayout().isBigEndian())
4310 return UnableToLegalize;
4311
4312 // This load needs splitting into power of 2 sized loads.
4313 //
4314 // Our strategy here is to generate anyextending loads for the smaller
4315 // types up to next power-2 result type, and then combine the two larger
4316 // result values together, before truncating back down to the non-pow-2
4317 // type.
4318 // E.g. v1 = i24 load =>
4319 // v2 = i32 zextload (2 byte)
4320 // v3 = i32 load (1 byte)
4321 // v4 = i32 shl v3, 16
4322 // v5 = i32 or v4, v2
4323 // v1 = i24 trunc v5
4324 // By doing this we generate the correct truncate which should get
4325 // combined away as an artifact with a matching extend.
4326
4327 uint64_t LargeSplitSize, SmallSplitSize;
4328
4329 if (!isPowerOf2_32(MemSizeInBits)) {
4330 // This load needs splitting into power of 2 sized loads.
4331 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4332 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4333 } else {
4334 // This is already a power of 2, but we still need to split this in half.
4335 //
4336 // Assume we're being asked to decompose an unaligned load.
4337 // TODO: If this requires multiple splits, handle them all at once.
4338 auto &Ctx = MF.getFunction().getContext();
4339 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4340 return UnableToLegalize;
4341
4342 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4343 }
4344
4345 if (MemTy.isVector()) {
4346 // TODO: Handle vector extloads
4347 if (MemTy != DstTy)
4348 return UnableToLegalize;
4349
4350 Align Alignment = LoadMI.getAlign();
4351 // Given an alignment larger than the size of the memory, we can increase
4352 // the size of the load without needing to scalarize it.
4353 if (Alignment.value() * 8 > MemSizeInBits &&
4355 LLT MoreTy = DstTy.changeVectorElementCount(
4357 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4358 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4359 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4360 NewLoad.getReg(0));
4361 LoadMI.eraseFromParent();
4362 return Legalized;
4363 }
4364
4365 // TODO: We can do better than scalarizing the vector and at least split it
4366 // in half.
4367 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4368 }
4369
4370 MachineMemOperand *LargeMMO =
4371 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4372 MachineMemOperand *SmallMMO =
4373 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4374
4375 LLT PtrTy = MRI.getType(PtrReg);
4376 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4377
4378 LLT AnyExtTy;
4379 LLT OffsetCstRes;
4380 if (EltTy.isPointer()) {
4381 AnyExtTy = LLT::scalar(AnyExtSize);
4382 OffsetCstRes = LLT::scalar(PtrTy.getSizeInBits());
4383 } else {
4384 AnyExtTy = DstTy.changeElementSize(AnyExtSize);
4385 OffsetCstRes = DstTy.changeElementSize(PtrTy.getSizeInBits());
4386 }
4387
4388 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4389 PtrReg, *LargeMMO);
4390
4391 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4392 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4393 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4394 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4395 SmallPtr, *SmallMMO);
4396
4397 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4398 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4399
4400 if (AnyExtTy == DstTy)
4401 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4402 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4403 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4404 MIRBuilder.buildTrunc(DstReg, {Or});
4405 } else {
4406 assert(DstTy.isPointer() && "expected pointer");
4407 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4408
4409 // FIXME: We currently consider this to be illegal for non-integral address
4410 // spaces, but we need still need a way to reinterpret the bits.
4411 MIRBuilder.buildIntToPtr(DstReg, Or);
4412 }
4413
4414 LoadMI.eraseFromParent();
4415 return Legalized;
4416}
4417
4419 // Lower a non-power of 2 store into multiple pow-2 stores.
4420 // E.g. split an i24 store into an i16 store + i8 store.
4421 // We do this by first extending the stored value to the next largest power
4422 // of 2 type, and then using truncating stores to store the components.
4423 // By doing this, likewise with G_LOAD, generate an extend that can be
4424 // artifact-combined away instead of leaving behind extracts.
4425 Register SrcReg = StoreMI.getValueReg();
4426 Register PtrReg = StoreMI.getPointerReg();
4427 LLT SrcTy = MRI.getType(SrcReg);
4428 MachineFunction &MF = MIRBuilder.getMF();
4429 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4430 LLT MemTy = MMO.getMemoryType();
4431
4432 unsigned StoreWidth = MemTy.getSizeInBits();
4433 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4434
4435 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4436 // Promote to a byte-sized store with upper bits zero if not
4437 // storing an integral number of bytes. For example, promote
4438 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4439 LLT WideTy = LLT::integer(StoreSizeInBits);
4440
4441 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4442 // Avoid creating a store with a narrower source than result.
4443 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4444 SrcTy = WideTy;
4445 }
4446
4447 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4448
4449 MachineMemOperand *NewMMO =
4450 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4451 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4452 StoreMI.eraseFromParent();
4453 return Legalized;
4454 }
4455
4456 if (MemTy.isVector()) {
4457 if (MemTy != SrcTy)
4458 return scalarizeVectorBooleanStore(StoreMI);
4459
4460 // TODO: We can do better than scalarizing the vector and at least split it
4461 // in half.
4462 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4463 }
4464
4465 unsigned MemSizeInBits = MemTy.getSizeInBits();
4466 uint64_t LargeSplitSize, SmallSplitSize;
4467
4468 if (!isPowerOf2_32(MemSizeInBits)) {
4469 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4470 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4471 } else {
4472 auto &Ctx = MF.getFunction().getContext();
4473 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4474 return UnableToLegalize; // Don't know what we're being asked to do.
4475
4476 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4477 }
4478
4479 // Extend to the next pow-2. If this store was itself the result of lowering,
4480 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4481 // that's wider than the stored size.
4482 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4483 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4484
4485 if (SrcTy.isPointer()) {
4486 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4487 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4488 }
4489
4490 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4491
4492 // Obtain the smaller value by shifting away the larger value.
4493 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4494 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4495
4496 // Generate the PtrAdd and truncating stores.
4497 LLT PtrTy = MRI.getType(PtrReg);
4498 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4499 LargeSplitSize / 8);
4500 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4501
4502 MachineMemOperand *LargeMMO =
4503 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4504 MachineMemOperand *SmallMMO =
4505 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4506 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4507 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4508 StoreMI.eraseFromParent();
4509 return Legalized;
4510}
4511
4514 Register SrcReg = StoreMI.getValueReg();
4515 Register PtrReg = StoreMI.getPointerReg();
4516 LLT SrcTy = MRI.getType(SrcReg);
4517 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4518 LLT MemTy = MMO.getMemoryType();
4519 LLT MemScalarTy = MemTy.getElementType();
4520 MachineFunction &MF = MIRBuilder.getMF();
4521
4522 assert(SrcTy.isVector() && "Expect a vector store type");
4523
4524 if (!MemScalarTy.isByteSized()) {
4525 // We need to build an integer scalar of the vector bit pattern.
4526 // It's not legal for us to add padding when storing a vector.
4527 unsigned NumBits = MemTy.getSizeInBits();
4528 LLT IntTy = LLT::integer(NumBits);
4529 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4530 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4531
4532 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4533 auto Elt = MIRBuilder.buildExtractVectorElement(
4534 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4535 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4536 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4537 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4538 ? (MemTy.getNumElements() - 1) - I
4539 : I;
4540 auto ShiftAmt = MIRBuilder.buildConstant(
4541 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4542 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4543 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4544 }
4545 auto PtrInfo = MMO.getPointerInfo();
4546 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4547 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4548 StoreMI.eraseFromParent();
4549 return Legalized;
4550 }
4551
4552 // TODO: implement simple scalarization.
4553 return UnableToLegalize;
4554}
4555
4557LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4558 switch (MI.getOpcode()) {
4559 case TargetOpcode::G_LOAD: {
4560 if (TypeIdx != 0)
4561 return UnableToLegalize;
4562 MachineMemOperand &MMO = **MI.memoperands_begin();
4563
4564 // Not sure how to interpret a bitcast of an extending load.
4565 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4566 return UnableToLegalize;
4567
4568 Observer.changingInstr(MI);
4569 bitcastDst(MI, CastTy, 0);
4570 MMO.setType(CastTy);
4571 // The range metadata is no longer valid when reinterpreted as a different
4572 // type.
4573 MMO.clearRanges();
4574 Observer.changedInstr(MI);
4575 return Legalized;
4576 }
4577 case TargetOpcode::G_STORE: {
4578 if (TypeIdx != 0)
4579 return UnableToLegalize;
4580
4581 MachineMemOperand &MMO = **MI.memoperands_begin();
4582
4583 // Not sure how to interpret a bitcast of a truncating store.
4584 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4585 return UnableToLegalize;
4586
4587 Observer.changingInstr(MI);
4588 bitcastSrc(MI, CastTy, 0);
4589 MMO.setType(CastTy);
4590 Observer.changedInstr(MI);
4591 return Legalized;
4592 }
4593 case TargetOpcode::G_SELECT: {
4594 if (TypeIdx != 0)
4595 return UnableToLegalize;
4596
4597 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4598 LLVM_DEBUG(
4599 dbgs() << "bitcast action not implemented for vector select\n");
4600 return UnableToLegalize;
4601 }
4602
4603 Observer.changingInstr(MI);
4604 bitcastSrc(MI, CastTy, 2);
4605 bitcastSrc(MI, CastTy, 3);
4606 bitcastDst(MI, CastTy, 0);
4607 Observer.changedInstr(MI);
4608 return Legalized;
4609 }
4610 case TargetOpcode::G_AND:
4611 case TargetOpcode::G_OR:
4612 case TargetOpcode::G_XOR: {
4613 Observer.changingInstr(MI);
4614 bitcastSrc(MI, CastTy, 1);
4615 bitcastSrc(MI, CastTy, 2);
4616 bitcastDst(MI, CastTy, 0);
4617 Observer.changedInstr(MI);
4618 return Legalized;
4619 }
4620 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4621 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4622 case TargetOpcode::G_INSERT_VECTOR_ELT:
4623 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4624 case TargetOpcode::G_CONCAT_VECTORS:
4625 return bitcastConcatVector(MI, TypeIdx, CastTy);
4626 case TargetOpcode::G_SHUFFLE_VECTOR:
4627 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4628 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4629 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4630 case TargetOpcode::G_INSERT_SUBVECTOR:
4631 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4632 default:
4633 return UnableToLegalize;
4634 }
4635}
4636
4637// Legalize an instruction by changing the opcode in place.
4638void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4640 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4642}
4643
4645LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4646 using namespace TargetOpcode;
4647 switch(MI.getOpcode()) {
4648 default:
4649 return UnableToLegalize;
4650 case TargetOpcode::G_FCONSTANT:
4651 return lowerFConstant(MI);
4652 case TargetOpcode::G_BITCAST:
4653 return lowerBitcast(MI);
4654 case TargetOpcode::G_SREM:
4655 case TargetOpcode::G_UREM: {
4656 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4657 auto Quot =
4658 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4659 {MI.getOperand(1), MI.getOperand(2)});
4660
4661 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4662 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4663 MI.eraseFromParent();
4664 return Legalized;
4665 }
4666 case TargetOpcode::G_SADDO:
4667 case TargetOpcode::G_SSUBO:
4668 return lowerSADDO_SSUBO(MI);
4669 case TargetOpcode::G_SADDE:
4670 return lowerSADDE(MI);
4671 case TargetOpcode::G_SSUBE:
4672 return lowerSSUBE(MI);
4673 case TargetOpcode::G_UMULH:
4674 case TargetOpcode::G_SMULH:
4675 return lowerSMULH_UMULH(MI);
4676 case TargetOpcode::G_SMULO:
4677 case TargetOpcode::G_UMULO: {
4678 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4679 // result.
4680 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4681 LLT Ty = MRI.getType(Res);
4682
4683 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4684 ? TargetOpcode::G_SMULH
4685 : TargetOpcode::G_UMULH;
4686
4687 Observer.changingInstr(MI);
4688 const auto &TII = MIRBuilder.getTII();
4689 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4690 MI.removeOperand(1);
4691 Observer.changedInstr(MI);
4692
4693 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4694 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4695
4696 // Move insert point forward so we can use the Res register if needed.
4697 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4698
4699 // For *signed* multiply, overflow is detected by checking:
4700 // (hi != (lo >> bitwidth-1))
4701 if (Opcode == TargetOpcode::G_SMULH) {
4702 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4703 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4704 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4705 } else {
4706 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4707 }
4708 return Legalized;
4709 }
4710 case TargetOpcode::G_FNEG: {
4711 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4712 LLT TyInt =
4713 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4714 Register CastedSubByReg = SubByReg;
4715
4716 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4717 !SubByRegTy.getScalarType().isInteger()) {
4718 auto BitcastDst = SubByRegTy.changeElementType(
4719 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4720 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4721 }
4722
4723 auto SignMask = MIRBuilder.buildConstant(
4724 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4725
4726 if (ResTy != TyInt) {
4727 Register NewDst =
4728 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4729 MIRBuilder.buildBitcast(Res, NewDst);
4730 } else
4731 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4732
4733 MI.eraseFromParent();
4734 return Legalized;
4735 }
4736 case TargetOpcode::G_FSUB:
4737 case TargetOpcode::G_STRICT_FSUB: {
4738 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4739 LLT Ty = MRI.getType(Res);
4740
4741 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4742 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4743
4744 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4745 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4746 else
4747 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4748
4749 MI.eraseFromParent();
4750 return Legalized;
4751 }
4752 case TargetOpcode::G_FMAD:
4753 return lowerFMad(MI);
4754 case TargetOpcode::G_FFLOOR:
4755 return lowerFFloor(MI);
4756 case TargetOpcode::G_LROUND:
4757 case TargetOpcode::G_LLROUND: {
4758 Register DstReg = MI.getOperand(0).getReg();
4759 Register SrcReg = MI.getOperand(1).getReg();
4760 LLT SrcTy = MRI.getType(SrcReg);
4761 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4762 {SrcReg});
4763 MIRBuilder.buildFPTOSI(DstReg, Round);
4764 MI.eraseFromParent();
4765 return Legalized;
4766 }
4767 case TargetOpcode::G_INTRINSIC_ROUND:
4768 return lowerIntrinsicRound(MI);
4769 case TargetOpcode::G_FRINT: {
4770 // Since round even is the assumed rounding mode for unconstrained FP
4771 // operations, rint and roundeven are the same operation.
4772 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4773 return Legalized;
4774 }
4775 case TargetOpcode::G_INTRINSIC_LRINT:
4776 case TargetOpcode::G_INTRINSIC_LLRINT: {
4777 Register DstReg = MI.getOperand(0).getReg();
4778 Register SrcReg = MI.getOperand(1).getReg();
4779 LLT SrcTy = MRI.getType(SrcReg);
4780 auto Round =
4781 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4782 MIRBuilder.buildFPTOSI(DstReg, Round);
4783 MI.eraseFromParent();
4784 return Legalized;
4785 }
4786 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4787 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4788 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4789 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4790 **MI.memoperands_begin());
4791 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4792 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4793 MI.eraseFromParent();
4794 return Legalized;
4795 }
4796 case TargetOpcode::G_LOAD:
4797 case TargetOpcode::G_SEXTLOAD:
4798 case TargetOpcode::G_ZEXTLOAD:
4799 return lowerLoad(cast<GAnyLoad>(MI));
4800 case TargetOpcode::G_STORE:
4801 return lowerStore(cast<GStore>(MI));
4802 case TargetOpcode::G_CTLZ_ZERO_POISON:
4803 case TargetOpcode::G_CTTZ_ZERO_POISON:
4804 case TargetOpcode::G_CTLZ:
4805 case TargetOpcode::G_CTTZ:
4806 case TargetOpcode::G_CTPOP:
4807 case TargetOpcode::G_CTLS:
4808 return lowerBitCount(MI);
4809 case G_UADDO: {
4810 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4811
4812 Register NewRes = MRI.cloneVirtualRegister(Res);
4813
4814 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4815 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4816
4817 MIRBuilder.buildCopy(Res, NewRes);
4818
4819 MI.eraseFromParent();
4820 return Legalized;
4821 }
4822 case G_UADDE: {
4823 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4824 const LLT CondTy = MRI.getType(CarryOut);
4825 const LLT Ty = MRI.getType(Res);
4826
4827 Register NewRes = MRI.cloneVirtualRegister(Res);
4828
4829 // Initial add of the two operands.
4830 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4831
4832 // Initial check for carry.
4833 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4834
4835 // Add the sum and the carry.
4836 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4837 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4838
4839 // Second check for carry. We can only carry if the initial sum is all 1s
4840 // and the carry is set, resulting in a new sum of 0.
4841 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4842 auto ResEqZero =
4843 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4844 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4845 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4846
4847 MIRBuilder.buildCopy(Res, NewRes);
4848
4849 MI.eraseFromParent();
4850 return Legalized;
4851 }
4852 case G_USUBO: {
4853 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4854
4855 MIRBuilder.buildSub(Res, LHS, RHS);
4856 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4857
4858 MI.eraseFromParent();
4859 return Legalized;
4860 }
4861 case G_USUBE: {
4862 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4863 const LLT CondTy = MRI.getType(BorrowOut);
4864 const LLT Ty = MRI.getType(Res);
4865
4866 // Initial subtract of the two operands.
4867 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4868
4869 // Initial check for borrow.
4870 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4871
4872 // Subtract the borrow from the first subtract.
4873 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4874 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4875
4876 // Second check for borrow. We can only borrow if the initial difference is
4877 // 0 and the borrow is set, resulting in a new difference of all 1s.
4878 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4879 auto TmpResEqZero =
4880 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4881 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4882 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4883
4884 MI.eraseFromParent();
4885 return Legalized;
4886 }
4887 case G_UITOFP:
4888 return lowerUITOFP(MI);
4889 case G_SITOFP:
4890 return lowerSITOFP(MI);
4891 case G_FPTOUI:
4892 return lowerFPTOUI(MI);
4893 case G_FPTOSI:
4894 return lowerFPTOSI(MI);
4895 case G_FPTOUI_SAT:
4896 case G_FPTOSI_SAT:
4897 return lowerFPTOINT_SAT(MI);
4898 case G_FPEXT:
4899 return lowerFPEXT(MI);
4900 case G_FPTRUNC:
4901 return lowerFPTRUNC(MI);
4902 case G_FPOWI:
4903 return lowerFPOWI(MI);
4904 case G_FMODF:
4905 return lowerFMODF(MI);
4906 case G_SMIN:
4907 case G_SMAX:
4908 case G_UMIN:
4909 case G_UMAX:
4910 return lowerMinMax(MI);
4911 case G_SCMP:
4912 case G_UCMP:
4913 return lowerThreewayCompare(MI);
4914 case G_FCOPYSIGN:
4915 return lowerFCopySign(MI);
4916 case G_FMINNUM:
4917 case G_FMAXNUM:
4918 case G_FMINIMUMNUM:
4919 case G_FMAXIMUMNUM:
4920 return lowerFMinNumMaxNum(MI);
4921 case G_FMINIMUM:
4922 case G_FMAXIMUM:
4923 return lowerFMinimumMaximum(MI);
4924 case G_MERGE_VALUES:
4925 return lowerMergeValues(MI);
4926 case G_UNMERGE_VALUES:
4927 return lowerUnmergeValues(MI);
4928 case TargetOpcode::G_SEXT_INREG: {
4929 assert(MI.getOperand(2).isImm() && "Expected immediate");
4930 int64_t SizeInBits = MI.getOperand(2).getImm();
4931
4932 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4933 LLT DstTy = MRI.getType(DstReg);
4934 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4935
4936 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4937 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4938 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4939 MI.eraseFromParent();
4940 return Legalized;
4941 }
4942 case G_EXTRACT_VECTOR_ELT:
4943 case G_INSERT_VECTOR_ELT:
4945 case G_SHUFFLE_VECTOR:
4946 return lowerShuffleVector(MI);
4947 case G_VECTOR_COMPRESS:
4948 return lowerVECTOR_COMPRESS(MI);
4949 case G_DYN_STACKALLOC:
4950 return lowerDynStackAlloc(MI);
4951 case G_INSERT_SUBVECTOR: {
4952 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
4953 MRI.getType(MI.getOperand(2).getReg()).isScalable())
4954 return UnableToLegalize;
4955
4956 // Check that subvector is half size of main vector
4957 Register Vector = MI.getOperand(1).getReg();
4958 Register Subvector = MI.getOperand(2).getReg();
4959 auto InsertionPointImm = MI.getOperand(3).getImm();
4960
4961 LLT VectorTy = MRI.getType(Vector);
4962 LLT DstTy = MRI.getType(Subvector);
4963 // If so, -> concat(subvector, extract(half of vector))
4964 // (Operands can be either way round depending on insertion point
4965 if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
4966 bool InsertInLowHalf = InsertionPointImm == 0;
4967 auto Extract = MIRBuilder.buildExtractSubvector(
4968 DstTy, Vector,
4969 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
4970
4971 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
4972 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
4973
4974 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
4975 {LowHalf, HighHalf});
4976 MI.eraseFromParent();
4977 return Legalized;
4978 }
4979 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
4980 else {
4981 // Extend subvector to same size as vector
4982 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
4983 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
4984
4985 // Calculate mask required for this shuffle
4986 SmallVector<int> Mask;
4987 for (int i = 0; i < VectorTy.getNumElements(); i++) {
4988 // If this index is within bounds, put subvector's index into mask
4989 if (i >= InsertionPointImm &&
4990 i < InsertionPointImm + DstTy.getNumElements())
4991 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
4992 else
4993 Mask.push_back(i);
4994 }
4995
4996 // Build shuffle
4997 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
4998 Mask);
4999 MI.eraseFromParent();
5000 return Legalized;
5001 }
5002 }
5003 case G_EXTRACT_SUBVECTOR: {
5004 Register DstReg = MI.getOperand(0).getReg();
5005 Register SrcReg = MI.getOperand(1).getReg();
5006 uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
5007
5008 LLT SrcTy = MRI.getType(SrcReg);
5009 LLT DstTy = MRI.getType(DstReg);
5010
5011 if (SrcTy.isScalable() || DstTy.isScalable())
5012 return UnableToLegalize;
5013
5014 if (SrcTy.getScalarType() != DstTy.getScalarType())
5015 return UnableToLegalize;
5016
5017 // extract_subvector = build_vector(extract_element, extract_element, ...)
5018 SmallVector<Register> ExtractedElements;
5019 for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
5020 ExtractedElements.push_back(
5022 .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
5023 ExtractionPointImm + i)
5024 .getReg(0));
5025 }
5026
5027 MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
5028 MI.eraseFromParent();
5029 return Legalized;
5030 }
5031 case G_STACKSAVE:
5032 return lowerStackSave(MI);
5033 case G_STACKRESTORE:
5034 return lowerStackRestore(MI);
5035 case G_EXTRACT:
5036 return lowerExtract(MI);
5037 case G_INSERT:
5038 return lowerInsert(MI);
5039 case G_BSWAP:
5040 return lowerBswap(MI);
5041 case G_BITREVERSE:
5042 return lowerBitreverse(MI);
5043 case G_READ_REGISTER:
5044 case G_WRITE_REGISTER:
5045 return lowerReadWriteRegister(MI);
5046 case G_UADDSAT:
5047 case G_USUBSAT: {
5048 // Try to make a reasonable guess about which lowering strategy to use. The
5049 // target can override this with custom lowering and calling the
5050 // implementation functions.
5051 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5052 if (LI.isLegalOrCustom({G_UMIN, Ty}))
5053 return lowerAddSubSatToMinMax(MI);
5055 }
5056 case G_SADDSAT:
5057 case G_SSUBSAT: {
5058 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5059
5060 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5061 // since it's a shorter expansion. However, we would need to figure out the
5062 // preferred boolean type for the carry out for the query.
5063 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5064 return lowerAddSubSatToMinMax(MI);
5066 }
5067 case G_SSHLSAT:
5068 case G_USHLSAT:
5069 return lowerShlSat(MI);
5070 case G_TRUNC_SSAT_S:
5071 case G_TRUNC_USAT_U:
5072 case G_TRUNC_SSAT_U:
5073 return lowerTruncSat(MI);
5074 case G_ABS:
5075 return lowerAbsToAddXor(MI);
5076 case G_ABDS:
5077 case G_ABDU: {
5078 bool IsSigned = MI.getOpcode() == G_ABDS;
5079 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5080 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5081 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5082 return lowerAbsDiffToMinMax(MI);
5083 }
5084 return lowerAbsDiffToSelect(MI);
5085 }
5086 case G_FABS:
5087 return lowerFAbs(MI);
5088 case G_SELECT:
5089 return lowerSelect(MI);
5090 case G_IS_FPCLASS:
5091 return lowerISFPCLASS(MI);
5092 case G_SDIVREM:
5093 case G_UDIVREM:
5094 return lowerDIVREM(MI);
5095 case G_FSHL:
5096 case G_FSHR:
5097 return lowerFunnelShift(MI);
5098 case G_ROTL:
5099 case G_ROTR:
5100 return lowerRotate(MI);
5101 case G_MEMSET:
5102 case G_MEMCPY:
5103 case G_MEMMOVE:
5104 case G_MEMCPY_INLINE:
5105 case G_MEMSET_INLINE:
5106 return lowerMemCpyFamily(MI);
5107 case G_ZEXT:
5108 case G_SEXT:
5109 case G_ANYEXT:
5110 return lowerEXT(MI);
5111 case G_TRUNC:
5112 return lowerTRUNC(MI);
5114 return lowerVectorReduction(MI);
5115 case G_VAARG:
5116 return lowerVAArg(MI);
5117 case G_ATOMICRMW_SUB: {
5118 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5119 const LLT ValTy = MRI.getType(Val);
5120 MachineMemOperand *MMO = *MI.memoperands_begin();
5121
5122 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5123 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5124 MI.eraseFromParent();
5125 return Legalized;
5126 }
5127 case G_SMULFIX:
5128 case G_UMULFIX:
5129 case G_SMULFIXSAT:
5130 case G_UMULFIXSAT:
5131 return lowerMulfix(MI);
5132 }
5133}
5134
5136 Align MinAlign) const {
5137 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5138 // datalayout for the preferred alignment. Also there should be a target hook
5139 // for this to allow targets to reduce the alignment and ignore the
5140 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5141 // the type.
5142 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5143}
5144
5147 MachinePointerInfo &PtrInfo) {
5148 MachineFunction &MF = MIRBuilder.getMF();
5149 const DataLayout &DL = MIRBuilder.getDataLayout();
5150 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5151
5152 unsigned AddrSpace = DL.getAllocaAddrSpace();
5153 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5154
5155 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5156 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5157}
5158
5160 const SrcOp &Val) {
5161 LLT SrcTy = Val.getLLTTy(MRI);
5162 Align StackTypeAlign =
5163 std::max(getStackTemporaryAlignment(SrcTy),
5165 MachinePointerInfo PtrInfo;
5166 auto StackTemp =
5167 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5168
5169 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5170 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5171}
5172
5174 LLT VecTy) {
5175 LLT IdxTy = B.getMRI()->getType(IdxReg);
5176 unsigned NElts = VecTy.getNumElements();
5177
5178 int64_t IdxVal;
5179 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5180 if (IdxVal < VecTy.getNumElements())
5181 return IdxReg;
5182 // If a constant index would be out of bounds, clamp it as well.
5183 }
5184
5185 if (isPowerOf2_32(NElts)) {
5187 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5188 }
5189
5190 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5191 .getReg(0);
5192}
5193
5195 Register Index) {
5196 LLT EltTy = VecTy.getElementType();
5197
5198 // Calculate the element offset and add it to the pointer.
5199 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5200 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5201 "Converting bits to bytes lost precision");
5202
5203 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5204
5205 // Convert index to the correct size for the address space.
5206 const DataLayout &DL = MIRBuilder.getDataLayout();
5207 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5208 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5209 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5210 if (IdxTy != MRI.getType(Index))
5211 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5212
5213 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5214 MIRBuilder.buildConstant(IdxTy, EltSize));
5215
5216 LLT PtrTy = MRI.getType(VecPtr);
5217 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5218}
5219
5220#ifndef NDEBUG
5221/// Check that all vector operands have same number of elements. Other operands
5222/// should be listed in NonVecOp.
5225 std::initializer_list<unsigned> NonVecOpIndices) {
5226 if (MI.getNumMemOperands() != 0)
5227 return false;
5228
5229 LLT VecTy = MRI.getType(MI.getReg(0));
5230 if (!VecTy.isVector())
5231 return false;
5232 unsigned NumElts = VecTy.getNumElements();
5233
5234 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5235 MachineOperand &Op = MI.getOperand(OpIdx);
5236 if (!Op.isReg()) {
5237 if (!is_contained(NonVecOpIndices, OpIdx))
5238 return false;
5239 continue;
5240 }
5241
5242 LLT Ty = MRI.getType(Op.getReg());
5243 if (!Ty.isVector()) {
5244 if (!is_contained(NonVecOpIndices, OpIdx))
5245 return false;
5246 continue;
5247 }
5248
5249 if (Ty.getNumElements() != NumElts)
5250 return false;
5251 }
5252
5253 return true;
5254}
5255#endif
5256
5257/// Fill \p DstOps with DstOps that have same number of elements combined as
5258/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5259/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5260/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5261static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5262 unsigned NumElts) {
5263 LLT LeftoverTy;
5264 assert(Ty.isVector() && "Expected vector type");
5265 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5266 int NumParts, NumLeftover;
5267 std::tie(NumParts, NumLeftover) =
5268 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5269
5270 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5271 for (int i = 0; i < NumParts; ++i) {
5272 DstOps.push_back(NarrowTy);
5273 }
5274
5275 if (LeftoverTy.isValid()) {
5276 assert(NumLeftover == 1 && "expected exactly one leftover");
5277 DstOps.push_back(LeftoverTy);
5278 }
5279}
5280
5281/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5282/// made from \p Op depending on operand type.
5284 MachineOperand &Op) {
5285 for (unsigned i = 0; i < N; ++i) {
5286 if (Op.isReg())
5287 Ops.push_back(Op.getReg());
5288 else if (Op.isImm())
5289 Ops.push_back(Op.getImm());
5290 else if (Op.isPredicate())
5291 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5292 else
5293 llvm_unreachable("Unsupported type");
5294 }
5295}
5296
5297// Handle splitting vector operations which need to have the same number of
5298// elements in each type index, but each type index may have a different element
5299// type.
5300//
5301// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5302// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5303// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5304//
5305// Also handles some irregular breakdown cases, e.g.
5306// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5307// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5308// s64 = G_SHL s64, s32
5311 GenericMachineInstr &MI, unsigned NumElts,
5312 std::initializer_list<unsigned> NonVecOpIndices) {
5313 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5314 "Non-compatible opcode or not specified non-vector operands");
5315 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5316
5317 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5318 unsigned NumDefs = MI.getNumDefs();
5319
5320 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5321 // Build instructions with DstOps to use instruction found by CSE directly.
5322 // CSE copies found instruction into given vreg when building with vreg dest.
5323 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5324 // Output registers will be taken from created instructions.
5325 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5326 for (unsigned i = 0; i < NumDefs; ++i) {
5327 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5328 }
5329
5330 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5331 // Operands listed in NonVecOpIndices will be used as is without splitting;
5332 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5333 // scalar condition (op 1), immediate in sext_inreg (op 2).
5334 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5335 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5336 ++UseIdx, ++UseNo) {
5337 if (is_contained(NonVecOpIndices, UseIdx)) {
5338 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5339 MI.getOperand(UseIdx));
5340 } else {
5341 SmallVector<Register, 8> SplitPieces;
5342 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5343 MRI);
5344 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5345 }
5346 }
5347
5348 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5349
5350 // Take i-th piece of each input operand split and build sub-vector/scalar
5351 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5352 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5354 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5355 Defs.push_back(OutputOpsPieces[DstNo][i]);
5356
5358 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5359 Uses.push_back(InputOpsPieces[InputNo][i]);
5360
5361 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5362 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5363 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5364 }
5365
5366 // Merge small outputs into MI's output for each def operand.
5367 if (NumLeftovers) {
5368 for (unsigned i = 0; i < NumDefs; ++i)
5369 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5370 } else {
5371 for (unsigned i = 0; i < NumDefs; ++i)
5372 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5373 }
5374
5375 MI.eraseFromParent();
5376 return Legalized;
5377}
5378
5381 unsigned NumElts) {
5382 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5383
5384 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5385 unsigned NumDefs = MI.getNumDefs();
5386
5387 SmallVector<DstOp, 8> OutputOpsPieces;
5388 SmallVector<Register, 8> OutputRegs;
5389 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5390
5391 // Instructions that perform register split will be inserted in basic block
5392 // where register is defined (basic block is in the next operand).
5393 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5394 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5395 UseIdx += 2, ++UseNo) {
5396 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5397 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5398 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5399 MIRBuilder, MRI);
5400 }
5401
5402 // Build PHIs with fewer elements.
5403 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5404 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5405 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5406 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5407 Phi.addDef(
5408 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5409 OutputRegs.push_back(Phi.getReg(0));
5410
5411 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5412 Phi.addUse(InputOpsPieces[j][i]);
5413 Phi.add(MI.getOperand(1 + j * 2 + 1));
5414 }
5415 }
5416
5417 // Set the insert point after the existing PHIs
5418 MachineBasicBlock &MBB = *MI.getParent();
5419 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5420
5421 // Merge small outputs into MI's def.
5422 if (NumLeftovers) {
5423 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5424 } else {
5425 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5426 }
5427
5428 MI.eraseFromParent();
5429 return Legalized;
5430}
5431
5434 unsigned TypeIdx,
5435 LLT NarrowTy) {
5436 const int NumDst = MI.getNumOperands() - 1;
5437 const Register SrcReg = MI.getOperand(NumDst).getReg();
5438 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5439 LLT SrcTy = MRI.getType(SrcReg);
5440
5441 if (TypeIdx != 1 || NarrowTy == DstTy)
5442 return UnableToLegalize;
5443
5444 // Requires compatible types. Otherwise SrcReg should have been defined by
5445 // merge-like instruction that would get artifact combined. Most likely
5446 // instruction that defines SrcReg has to perform more/fewer elements
5447 // legalization compatible with NarrowTy.
5448 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5449 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5450
5451 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5452 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5453 return UnableToLegalize;
5454
5455 // This is most likely DstTy (smaller then register size) packed in SrcTy
5456 // (larger then register size) and since unmerge was not combined it will be
5457 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5458 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5459
5460 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5461 //
5462 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5463 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5464 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5465 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5466 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5467 const int PartsPerUnmerge = NumDst / NumUnmerge;
5468
5469 for (int I = 0; I != NumUnmerge; ++I) {
5470 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5471
5472 for (int J = 0; J != PartsPerUnmerge; ++J)
5473 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5474 MIB.addUse(Unmerge.getReg(I));
5475 }
5476
5477 MI.eraseFromParent();
5478 return Legalized;
5479}
5480
5483 LLT NarrowTy) {
5484 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5485 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5486 // that should have been artifact combined. Most likely instruction that uses
5487 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5488 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5489 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5490 if (NarrowTy == SrcTy)
5491 return UnableToLegalize;
5492
5493 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5494 // is for old mir tests. Since the changes to more/fewer elements it should no
5495 // longer be possible to generate MIR like this when starting from llvm-ir
5496 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5497 if (TypeIdx == 1) {
5498 assert(SrcTy.isVector() && "Expected vector types");
5499 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5500 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5501 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5502 return UnableToLegalize;
5503 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5504 //
5505 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5506 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5507 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5508 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5509 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5510 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5511
5513 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5514 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5515 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5516 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5517 Elts.push_back(Unmerge.getReg(j));
5518 }
5519
5520 SmallVector<Register, 8> NarrowTyElts;
5521 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5522 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5523 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5524 ++i, Offset += NumNarrowTyElts) {
5525 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5526 NarrowTyElts.push_back(
5527 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5528 }
5529
5530 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5531 MI.eraseFromParent();
5532 return Legalized;
5533 }
5534
5535 assert(TypeIdx == 0 && "Bad type index");
5536 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5537 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5538 return UnableToLegalize;
5539
5540 // This is most likely SrcTy (smaller then register size) packed in DstTy
5541 // (larger then register size) and since merge was not combined it will be
5542 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5543 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5544
5545 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5546 //
5547 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5548 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5549 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5550 SmallVector<Register, 8> NarrowTyElts;
5551 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5552 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5553 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5554 for (unsigned i = 0; i < NumParts; ++i) {
5556 for (unsigned j = 0; j < NumElts; ++j)
5557 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5558 NarrowTyElts.push_back(
5559 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5560 }
5561
5562 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5563 MI.eraseFromParent();
5564 return Legalized;
5565}
5566
5569 unsigned TypeIdx,
5570 LLT NarrowVecTy) {
5571 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5572 Register InsertVal;
5573 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5574
5575 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5576 if (IsInsert)
5577 InsertVal = MI.getOperand(2).getReg();
5578
5579 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5580 LLT VecTy = MRI.getType(SrcVec);
5581
5582 // If the index is a constant, we can really break this down as you would
5583 // expect, and index into the target size pieces.
5584 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5585 if (MaybeCst) {
5586 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5587 // Avoid out of bounds indexing the pieces.
5588 if (IdxVal >= VecTy.getNumElements()) {
5589 MIRBuilder.buildUndef(DstReg);
5590 MI.eraseFromParent();
5591 return Legalized;
5592 }
5593
5594 if (!NarrowVecTy.isVector()) {
5595 SmallVector<Register, 8> SplitPieces;
5596 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5597 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5598 if (IsInsert) {
5599 SplitPieces[IdxVal] = InsertVal;
5600 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5601 } else {
5602 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5603 }
5604 } else {
5605 SmallVector<Register, 8> VecParts;
5606 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5607
5608 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5609 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5610 TargetOpcode::G_ANYEXT);
5611
5612 unsigned NewNumElts = NarrowVecTy.getNumElements();
5613
5614 LLT IdxTy = MRI.getType(Idx);
5615 int64_t PartIdx = IdxVal / NewNumElts;
5616 auto NewIdx =
5617 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5618
5619 if (IsInsert) {
5620 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5621
5622 // Use the adjusted index to insert into one of the subvectors.
5623 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5624 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5625 VecParts[PartIdx] = InsertPart.getReg(0);
5626
5627 // Recombine the inserted subvector with the others to reform the result
5628 // vector.
5629 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5630 } else {
5631 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5632 }
5633 }
5634
5635 MI.eraseFromParent();
5636 return Legalized;
5637 }
5638
5639 // With a variable index, we can't perform the operation in a smaller type, so
5640 // we're forced to expand this.
5641 //
5642 // TODO: We could emit a chain of compare/select to figure out which piece to
5643 // index.
5645}
5646
5649 LLT NarrowTy) {
5650 // FIXME: Don't know how to handle secondary types yet.
5651 if (TypeIdx != 0)
5652 return UnableToLegalize;
5653
5654 if (!NarrowTy.isByteSized()) {
5655 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5656 return UnableToLegalize;
5657 }
5658
5659 // This implementation doesn't work for atomics. Give up instead of doing
5660 // something invalid.
5661 if (LdStMI.isAtomic())
5662 return UnableToLegalize;
5663
5664 bool IsLoad = isa<GLoad>(LdStMI);
5665 Register ValReg = LdStMI.getReg(0);
5666 Register AddrReg = LdStMI.getPointerReg();
5667 LLT ValTy = MRI.getType(ValReg);
5668
5669 // FIXME: Do we need a distinct NarrowMemory legalize action?
5670 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5671 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5672 return UnableToLegalize;
5673 }
5674
5675 int NumParts = -1;
5676 int NumLeftover = -1;
5677 LLT LeftoverTy;
5678 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5679 if (IsLoad) {
5680 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5681 } else {
5682 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5683 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5684 NumParts = NarrowRegs.size();
5685 NumLeftover = NarrowLeftoverRegs.size();
5686 }
5687 }
5688
5689 if (NumParts == -1)
5690 return UnableToLegalize;
5691
5692 LLT PtrTy = MRI.getType(AddrReg);
5693 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5694
5695 unsigned TotalSize = ValTy.getSizeInBits();
5696
5697 // Split the load/store into PartTy sized pieces starting at Offset. If this
5698 // is a load, return the new registers in ValRegs. For a store, each elements
5699 // of ValRegs should be PartTy. Returns the next offset that needs to be
5700 // handled.
5701 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5702 auto MMO = LdStMI.getMMO();
5703 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5704 unsigned NumParts, unsigned Offset) -> unsigned {
5705 MachineFunction &MF = MIRBuilder.getMF();
5706 unsigned PartSize = PartTy.getSizeInBits();
5707 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5708 ++Idx) {
5709 unsigned ByteOffset = Offset / 8;
5710 Register NewAddrReg;
5711
5712 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5713 ByteOffset);
5714
5715 MachineMemOperand *NewMMO =
5716 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5717
5718 if (IsLoad) {
5719 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5720 ValRegs.push_back(Dst);
5721 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5722 } else {
5723 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5724 }
5725 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5726 }
5727
5728 return Offset;
5729 };
5730
5731 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5732 unsigned HandledOffset =
5733 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5734
5735 // Handle the rest of the register if this isn't an even type breakdown.
5736 if (LeftoverTy.isValid())
5737 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5738
5739 if (IsLoad) {
5740 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5741 LeftoverTy, NarrowLeftoverRegs);
5742 }
5743
5744 LdStMI.eraseFromParent();
5745 return Legalized;
5746}
5747
5750 LLT NarrowTy) {
5751 using namespace TargetOpcode;
5753 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5754
5755 switch (MI.getOpcode()) {
5756 case G_IMPLICIT_DEF:
5757 case G_TRUNC:
5758 case G_AND:
5759 case G_OR:
5760 case G_XOR:
5761 case G_ADD:
5762 case G_SUB:
5763 case G_MUL:
5764 case G_PTR_ADD:
5765 case G_SMULH:
5766 case G_UMULH:
5767 case G_FADD:
5768 case G_FMUL:
5769 case G_FSUB:
5770 case G_FNEG:
5771 case G_FABS:
5772 case G_FCANONICALIZE:
5773 case G_FDIV:
5774 case G_FREM:
5775 case G_FMA:
5776 case G_FMAD:
5777 case G_FPOW:
5778 case G_FEXP:
5779 case G_FEXP2:
5780 case G_FEXP10:
5781 case G_FLOG:
5782 case G_FLOG2:
5783 case G_FLOG10:
5784 case G_FLDEXP:
5785 case G_FNEARBYINT:
5786 case G_FCEIL:
5787 case G_FFLOOR:
5788 case G_FRINT:
5789 case G_INTRINSIC_LRINT:
5790 case G_INTRINSIC_LLRINT:
5791 case G_INTRINSIC_ROUND:
5792 case G_INTRINSIC_ROUNDEVEN:
5793 case G_LROUND:
5794 case G_LLROUND:
5795 case G_INTRINSIC_TRUNC:
5796 case G_FMODF:
5797 case G_FCOS:
5798 case G_FSIN:
5799 case G_FTAN:
5800 case G_FACOS:
5801 case G_FASIN:
5802 case G_FATAN:
5803 case G_FATAN2:
5804 case G_FCOSH:
5805 case G_FSINH:
5806 case G_FTANH:
5807 case G_FSQRT:
5808 case G_BSWAP:
5809 case G_BITREVERSE:
5810 case G_SDIV:
5811 case G_UDIV:
5812 case G_SREM:
5813 case G_UREM:
5814 case G_SDIVREM:
5815 case G_UDIVREM:
5816 case G_SMIN:
5817 case G_SMAX:
5818 case G_UMIN:
5819 case G_UMAX:
5820 case G_ABS:
5821 case G_FMINNUM:
5822 case G_FMAXNUM:
5823 case G_FMINNUM_IEEE:
5824 case G_FMAXNUM_IEEE:
5825 case G_FMINIMUM:
5826 case G_FMAXIMUM:
5827 case G_FMINIMUMNUM:
5828 case G_FMAXIMUMNUM:
5829 case G_FSHL:
5830 case G_FSHR:
5831 case G_ROTL:
5832 case G_ROTR:
5833 case G_FREEZE:
5834 case G_SADDSAT:
5835 case G_SSUBSAT:
5836 case G_UADDSAT:
5837 case G_USUBSAT:
5838 case G_UMULO:
5839 case G_SMULO:
5840 case G_SHL:
5841 case G_LSHR:
5842 case G_ASHR:
5843 case G_SSHLSAT:
5844 case G_USHLSAT:
5845 case G_CTLZ:
5846 case G_CTLZ_ZERO_POISON:
5847 case G_CTTZ:
5848 case G_CTTZ_ZERO_POISON:
5849 case G_CTPOP:
5850 case G_CTLS:
5851 case G_FCOPYSIGN:
5852 case G_ZEXT:
5853 case G_SEXT:
5854 case G_ANYEXT:
5855 case G_FPEXT:
5856 case G_FPTRUNC:
5857 case G_SITOFP:
5858 case G_UITOFP:
5859 case G_FPTOSI:
5860 case G_FPTOUI:
5861 case G_FPTOSI_SAT:
5862 case G_FPTOUI_SAT:
5863 case G_INTTOPTR:
5864 case G_PTRTOINT:
5865 case G_ADDRSPACE_CAST:
5866 case G_UADDO:
5867 case G_USUBO:
5868 case G_UADDE:
5869 case G_USUBE:
5870 case G_SADDO:
5871 case G_SSUBO:
5872 case G_SADDE:
5873 case G_SSUBE:
5874 case G_STRICT_FADD:
5875 case G_STRICT_FSUB:
5876 case G_STRICT_FMUL:
5877 case G_STRICT_FMA:
5878 case G_STRICT_FLDEXP:
5879 case G_FFREXP:
5880 case G_TRUNC_SSAT_S:
5881 case G_TRUNC_SSAT_U:
5882 case G_TRUNC_USAT_U:
5883 return fewerElementsVectorMultiEltType(GMI, NumElts);
5884 case G_ICMP:
5885 case G_FCMP:
5886 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5887 case G_IS_FPCLASS:
5888 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5889 case G_SELECT:
5890 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5891 return fewerElementsVectorMultiEltType(GMI, NumElts);
5892 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5893 case G_PHI:
5894 return fewerElementsVectorPhi(GMI, NumElts);
5895 case G_UNMERGE_VALUES:
5896 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5897 case G_BUILD_VECTOR:
5898 assert(TypeIdx == 0 && "not a vector type index");
5899 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5900 case G_CONCAT_VECTORS:
5901 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5902 return UnableToLegalize;
5903 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5904 case G_EXTRACT_SUBVECTOR: {
5905 Register DstReg = MI.getOperand(0).getReg();
5906 LLT DstTy = MRI.getType(DstReg);
5907 Register SrcReg = MI.getOperand(1).getReg();
5908 uint64_t InsertionPointImm = MI.getOperand(2).getImm();
5909
5910 // If Dst > NarrowTy bits, then cannot legalize
5911 if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
5912 return UnableToLegalize;
5913
5914 // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
5915 if (!DstTy.getElementCount().isKnownMultipleOf(NarrowTy.getElementCount()))
5916 return UnableToLegalize;
5917
5918 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5919 uint64_t RequiredSubvectorIndex =
5920 InsertionPointImm / NarrowTy.getNumElements();
5921 // If Dst and Narrow are both same size, convert to a copy
5922 if (DstTy.getNumElements() == NarrowTy.getNumElements())
5923 MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
5924 else
5925 MIRBuilder.buildExtractSubvector(
5926 DstReg, Unmerge.getReg(RequiredSubvectorIndex),
5927 InsertionPointImm % NarrowTy.getNumElements());
5928
5929 MI.eraseFromParent();
5930 return Legalized;
5931 }
5932 case G_EXTRACT_VECTOR_ELT:
5933 case G_INSERT_VECTOR_ELT:
5934 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5935 case G_LOAD:
5936 case G_STORE:
5937 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5938 case G_SEXT_INREG:
5939 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5941 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5942 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5943 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5944 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5945 case G_SHUFFLE_VECTOR:
5946 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5947 case G_FPOWI:
5948 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5949 case G_BITCAST:
5950 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5951 case G_INTRINSIC_FPTRUNC_ROUND:
5952 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5953 default:
5954 return UnableToLegalize;
5955 }
5956}
5957
5960 LLT NarrowTy) {
5961 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5962 "Not a bitcast operation");
5963
5964 if (TypeIdx != 0)
5965 return UnableToLegalize;
5966
5967 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5968
5969 unsigned NewElemCount =
5970 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5971 SmallVector<Register> SrcVRegs, BitcastVRegs;
5972 if (NewElemCount == 1) {
5973 LLT SrcNarrowTy = SrcTy.getElementType();
5974
5975 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
5976 getUnmergeResults(SrcVRegs, *Unmerge);
5977 } else {
5978 LLT SrcNarrowTy =
5980
5981 // Split the Src and Dst Reg into smaller registers
5982 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5983 return UnableToLegalize;
5984 }
5985
5986 // Build new smaller bitcast instructions
5987 // Not supporting Leftover types for now but will have to
5988 for (Register Reg : SrcVRegs)
5989 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
5990
5991 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5992 MI.eraseFromParent();
5993 return Legalized;
5994}
5995
5997 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5998 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5999 if (TypeIdx != 0)
6000 return UnableToLegalize;
6001
6002 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
6003 MI.getFirst3RegLLTs();
6004 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6005 // The shuffle should be canonicalized by now.
6006 if (DstTy != Src1Ty)
6007 return UnableToLegalize;
6008 if (DstTy != Src2Ty)
6009 return UnableToLegalize;
6010
6011 if (!isPowerOf2_32(DstTy.getNumElements()))
6012 return UnableToLegalize;
6013
6014 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
6015 // Further legalization attempts will be needed to do split further.
6016 NarrowTy =
6017 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
6018 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
6019
6020 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
6021 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
6022 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
6023 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
6024 SplitSrc2Regs[1]};
6025
6026 Register Hi, Lo;
6027
6028 // If Lo or Hi uses elements from at most two of the four input vectors, then
6029 // express it as a vector shuffle of those two inputs. Otherwise extract the
6030 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
6032 for (unsigned High = 0; High < 2; ++High) {
6033 Register &Output = High ? Hi : Lo;
6034
6035 // Build a shuffle mask for the output, discovering on the fly which
6036 // input vectors to use as shuffle operands (recorded in InputUsed).
6037 // If building a suitable shuffle vector proves too hard, then bail
6038 // out with useBuildVector set.
6039 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
6040 unsigned FirstMaskIdx = High * NewElts;
6041 bool UseBuildVector = false;
6042 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6043 // The mask element. This indexes into the input.
6044 int Idx = Mask[FirstMaskIdx + MaskOffset];
6045
6046 // The input vector this mask element indexes into.
6047 unsigned Input = (unsigned)Idx / NewElts;
6048
6049 if (Input >= std::size(Inputs)) {
6050 // The mask element does not index into any input vector.
6051 Ops.push_back(-1);
6052 continue;
6053 }
6054
6055 // Turn the index into an offset from the start of the input vector.
6056 Idx -= Input * NewElts;
6057
6058 // Find or create a shuffle vector operand to hold this input.
6059 unsigned OpNo;
6060 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
6061 if (InputUsed[OpNo] == Input) {
6062 // This input vector is already an operand.
6063 break;
6064 } else if (InputUsed[OpNo] == -1U) {
6065 // Create a new operand for this input vector.
6066 InputUsed[OpNo] = Input;
6067 break;
6068 }
6069 }
6070
6071 if (OpNo >= std::size(InputUsed)) {
6072 // More than two input vectors used! Give up on trying to create a
6073 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
6074 UseBuildVector = true;
6075 break;
6076 }
6077
6078 // Add the mask index for the new shuffle vector.
6079 Ops.push_back(Idx + OpNo * NewElts);
6080 }
6081
6082 if (UseBuildVector) {
6083 LLT EltTy = NarrowTy.getElementType();
6085
6086 // Extract the input elements by hand.
6087 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6088 // The mask element. This indexes into the input.
6089 int Idx = Mask[FirstMaskIdx + MaskOffset];
6090
6091 // The input vector this mask element indexes into.
6092 unsigned Input = (unsigned)Idx / NewElts;
6093
6094 if (Input >= std::size(Inputs)) {
6095 // The mask element is "undef" or indexes off the end of the input.
6096 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6097 continue;
6098 }
6099
6100 // Turn the index into an offset from the start of the input vector.
6101 Idx -= Input * NewElts;
6102
6103 // Extract the vector element by hand.
6104 SVOps.push_back(MIRBuilder
6105 .buildExtractVectorElement(
6106 EltTy, Inputs[Input],
6107 MIRBuilder.buildConstant(LLT::integer(32), Idx))
6108 .getReg(0));
6109 }
6110
6111 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6112 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6113 } else if (InputUsed[0] == -1U) {
6114 // No input vectors were used! The result is undefined.
6115 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6116 } else if (NewElts == 1) {
6117 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6118 } else {
6119 Register Op0 = Inputs[InputUsed[0]];
6120 // If only one input was used, use an undefined vector for the other.
6121 Register Op1 = InputUsed[1] == -1U
6122 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6123 : Inputs[InputUsed[1]];
6124 // At least one input vector was used. Create a new shuffle vector.
6125 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6126 }
6127
6128 Ops.clear();
6129 }
6130
6131 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6132 MI.eraseFromParent();
6133 return Legalized;
6134}
6135
6137 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6138 auto &RdxMI = cast<GVecReduce>(MI);
6139
6140 if (TypeIdx != 1)
6141 return UnableToLegalize;
6142
6143 // The semantics of the normal non-sequential reductions allow us to freely
6144 // re-associate the operation.
6145 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6146
6147 if (NarrowTy.isVector() &&
6148 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6149 return UnableToLegalize;
6150
6151 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6152 SmallVector<Register> SplitSrcs;
6153 // If NarrowTy is a scalar then we're being asked to scalarize.
6154 const unsigned NumParts =
6155 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6156 : SrcTy.getNumElements();
6157
6158 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6159 if (NarrowTy.isScalar()) {
6160 if (DstTy != NarrowTy)
6161 return UnableToLegalize; // FIXME: handle implicit extensions.
6162
6163 if (isPowerOf2_32(NumParts)) {
6164 // Generate a tree of scalar operations to reduce the critical path.
6165 SmallVector<Register> PartialResults;
6166 unsigned NumPartsLeft = NumParts;
6167 while (NumPartsLeft > 1) {
6168 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6169 PartialResults.emplace_back(
6171 .buildInstr(ScalarOpc, {NarrowTy},
6172 {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
6173 .getReg(0));
6174 }
6175 SplitSrcs = PartialResults;
6176 PartialResults.clear();
6177 NumPartsLeft = SplitSrcs.size();
6178 }
6179 assert(SplitSrcs.size() == 1);
6180 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6181 MI.eraseFromParent();
6182 return Legalized;
6183 }
6184 // If we can't generate a tree, then just do sequential operations.
6185 Register Acc = SplitSrcs[0];
6186 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6187 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
6188 .getReg(0);
6189 MIRBuilder.buildCopy(DstReg, Acc);
6190 MI.eraseFromParent();
6191 return Legalized;
6192 }
6193 SmallVector<Register> PartialReductions;
6194 for (unsigned Part = 0; Part < NumParts; ++Part) {
6195 PartialReductions.push_back(
6196 MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
6197 .getReg(0));
6198 }
6199
6200 // If the types involved are powers of 2, we can generate intermediate vector
6201 // ops, before generating a final reduction operation.
6202 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6203 isPowerOf2_32(NarrowTy.getNumElements())) {
6204 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6205 }
6206
6207 Register Acc = PartialReductions[0];
6208 for (unsigned Part = 1; Part < NumParts; ++Part) {
6209 if (Part == NumParts - 1) {
6210 MIRBuilder.buildInstr(ScalarOpc, {DstReg},
6211 {Acc, PartialReductions[Part]});
6212 } else {
6213 Acc = MIRBuilder
6214 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
6215 .getReg(0);
6216 }
6217 }
6218 MI.eraseFromParent();
6219 return Legalized;
6220}
6221
6224 unsigned int TypeIdx,
6225 LLT NarrowTy) {
6226 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6227 MI.getFirst3RegLLTs();
6228 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6229 DstTy != NarrowTy)
6230 return UnableToLegalize;
6231
6232 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6233 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6234 "Unexpected vecreduce opcode");
6235 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6236 ? TargetOpcode::G_FADD
6237 : TargetOpcode::G_FMUL;
6238
6239 SmallVector<Register> SplitSrcs;
6240 unsigned NumParts = SrcTy.getNumElements();
6241 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6242 Register Acc = ScalarReg;
6243 for (unsigned i = 0; i < NumParts; i++)
6244 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
6245 .getReg(0);
6246
6247 MIRBuilder.buildCopy(DstReg, Acc);
6248 MI.eraseFromParent();
6249 return Legalized;
6250}
6251
6253LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6254 LLT SrcTy, LLT NarrowTy,
6255 unsigned ScalarOpc) {
6256 SmallVector<Register> SplitSrcs;
6257 // Split the sources into NarrowTy size pieces.
6258 extractParts(SrcReg, NarrowTy,
6259 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6260 MIRBuilder, MRI);
6261 // We're going to do a tree reduction using vector operations until we have
6262 // one NarrowTy size value left.
6263 while (SplitSrcs.size() > 1) {
6264 SmallVector<Register> PartialRdxs;
6265 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6266 Register LHS = SplitSrcs[Idx];
6267 Register RHS = SplitSrcs[Idx + 1];
6268 // Create the intermediate vector op.
6269 Register Res =
6270 MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
6271 PartialRdxs.push_back(Res);
6272 }
6273 SplitSrcs = std::move(PartialRdxs);
6274 }
6275 // Finally generate the requested NarrowTy based reduction.
6276 Observer.changingInstr(MI);
6277 MI.getOperand(1).setReg(SplitSrcs[0]);
6278 Observer.changedInstr(MI);
6279 return Legalized;
6280}
6281
6284 const LLT HalfTy, const LLT AmtTy) {
6285
6286 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6287 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6288 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6289
6290 if (Amt.isZero()) {
6291 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6292 MI.eraseFromParent();
6293 return Legalized;
6294 }
6295
6296 LLT NVT = HalfTy;
6297 unsigned NVTBits = HalfTy.getSizeInBits();
6298 unsigned VTBits = 2 * NVTBits;
6299
6300 SrcOp Lo(Register(0)), Hi(Register(0));
6301 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6302 if (Amt.ugt(VTBits)) {
6303 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6304 } else if (Amt.ugt(NVTBits)) {
6305 Lo = MIRBuilder.buildConstant(NVT, 0);
6306 Hi = MIRBuilder.buildShl(NVT, InL,
6307 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6308 } else if (Amt == NVTBits) {
6309 Lo = MIRBuilder.buildConstant(NVT, 0);
6310 Hi = InL;
6311 } else {
6312 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6313 auto OrLHS =
6314 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6315 auto OrRHS = MIRBuilder.buildLShr(
6316 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6317 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6318 }
6319 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6320 if (Amt.ugt(VTBits)) {
6321 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6322 } else if (Amt.ugt(NVTBits)) {
6323 Lo = MIRBuilder.buildLShr(NVT, InH,
6324 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6325 Hi = MIRBuilder.buildConstant(NVT, 0);
6326 } else if (Amt == NVTBits) {
6327 Lo = InH;
6328 Hi = MIRBuilder.buildConstant(NVT, 0);
6329 } else {
6330 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6331
6332 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6333 auto OrRHS = MIRBuilder.buildShl(
6334 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6335
6336 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6337 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6338 }
6339 } else {
6340 if (Amt.ugt(VTBits)) {
6341 Hi = Lo = MIRBuilder.buildAShr(
6342 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6343 } else if (Amt.ugt(NVTBits)) {
6344 Lo = MIRBuilder.buildAShr(NVT, InH,
6345 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6346 Hi = MIRBuilder.buildAShr(NVT, InH,
6347 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6348 } else if (Amt == NVTBits) {
6349 Lo = InH;
6350 Hi = MIRBuilder.buildAShr(NVT, InH,
6351 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6352 } else {
6353 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6354
6355 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6356 auto OrRHS = MIRBuilder.buildShl(
6357 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6358
6359 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6360 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6361 }
6362 }
6363
6364 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6365 MI.eraseFromParent();
6366
6367 return Legalized;
6368}
6369
6372 LLT RequestedTy) {
6373 if (TypeIdx == 1) {
6374 Observer.changingInstr(MI);
6375 narrowScalarSrc(MI, RequestedTy, 2);
6376 Observer.changedInstr(MI);
6377 return Legalized;
6378 }
6379
6380 Register DstReg = MI.getOperand(0).getReg();
6381 LLT DstTy = MRI.getType(DstReg);
6382 if (DstTy.isVector())
6383 return UnableToLegalize;
6384
6385 Register Amt = MI.getOperand(2).getReg();
6386 LLT ShiftAmtTy = MRI.getType(Amt);
6387 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6388 if (DstEltSize % 2 != 0)
6389 return UnableToLegalize;
6390
6391 // Check if we should use multi-way splitting instead of recursive binary
6392 // splitting.
6393 //
6394 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6395 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6396 // and dependency chains created by usual binary splitting approach
6397 // (128->64->32).
6398 //
6399 // The >= 8 parts threshold ensures we only use this optimization when binary
6400 // splitting would require multiple recursive passes, avoiding overhead for
6401 // simple 2-way splits where binary approach is sufficient.
6402 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6403 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6404 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6405 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6406 // steps).
6407 if (NumParts >= 8)
6408 return narrowScalarShiftMultiway(MI, RequestedTy);
6409 }
6410
6411 // Fall back to binary splitting:
6412 // Ignore the input type. We can only go to exactly half the size of the
6413 // input. If that isn't small enough, the resulting pieces will be further
6414 // legalized.
6415 const unsigned NewBitSize = DstEltSize / 2;
6416 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6417 const LLT CondTy = LLT::integer(1);
6418
6419 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6420 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6421 ShiftAmtTy);
6422 }
6423
6424 // TODO: Expand with known bits.
6425
6426 // Handle the fully general expansion by an unknown amount.
6427 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6428
6429 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6430 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6431 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6432
6433 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6434 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6435
6436 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6437 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6438 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6439
6440 Register ResultRegs[2];
6441 switch (MI.getOpcode()) {
6442 case TargetOpcode::G_SHL: {
6443 // Short: ShAmt < NewBitSize
6444 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6445
6446 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6447 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6448 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6449
6450 // Long: ShAmt >= NewBitSize
6451 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6452 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6453
6454 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6455 auto Hi = MIRBuilder.buildSelect(
6456 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6457
6458 ResultRegs[0] = Lo.getReg(0);
6459 ResultRegs[1] = Hi.getReg(0);
6460 break;
6461 }
6462 case TargetOpcode::G_LSHR:
6463 case TargetOpcode::G_ASHR: {
6464 // Short: ShAmt < NewBitSize
6465 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6466
6467 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6468 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6469 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6470
6471 // Long: ShAmt >= NewBitSize
6473 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6474 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6475 } else {
6476 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6477 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6478 }
6479 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6480 {InH, AmtExcess}); // Lo from Hi part.
6481
6482 auto Lo = MIRBuilder.buildSelect(
6483 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6484
6485 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6486
6487 ResultRegs[0] = Lo.getReg(0);
6488 ResultRegs[1] = Hi.getReg(0);
6489 break;
6490 }
6491 default:
6492 llvm_unreachable("not a shift");
6493 }
6494
6495 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6496 MI.eraseFromParent();
6497 return Legalized;
6498}
6499
6501 unsigned PartIdx,
6502 unsigned NumParts,
6503 ArrayRef<Register> SrcParts,
6504 const ShiftParams &Params,
6505 LLT TargetTy, LLT ShiftAmtTy) {
6506 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6507 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6508 assert(WordShiftConst && BitShiftConst && "Expected constants");
6509
6510 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6511 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6512 const bool NeedsInterWordShift = ShiftBits != 0;
6513
6514 switch (Opcode) {
6515 case TargetOpcode::G_SHL: {
6516 // Data moves from lower indices to higher indices
6517 // If this part would come from a source beyond our range, it's zero
6518 if (PartIdx < ShiftWords)
6519 return Params.Zero;
6520
6521 unsigned SrcIdx = PartIdx - ShiftWords;
6522 if (!NeedsInterWordShift)
6523 return SrcParts[SrcIdx];
6524
6525 // Combine shifted main part with carry from previous part
6526 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6527 if (SrcIdx > 0) {
6528 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6529 Params.InvBitShift);
6530 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6531 }
6532 return Hi.getReg(0);
6533 }
6534
6535 case TargetOpcode::G_LSHR: {
6536 unsigned SrcIdx = PartIdx + ShiftWords;
6537 if (SrcIdx >= NumParts)
6538 return Params.Zero;
6539 if (!NeedsInterWordShift)
6540 return SrcParts[SrcIdx];
6541
6542 // Combine shifted main part with carry from next part
6543 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6544 if (SrcIdx + 1 < NumParts) {
6545 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6546 Params.InvBitShift);
6547 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6548 }
6549 return Lo.getReg(0);
6550 }
6551
6552 case TargetOpcode::G_ASHR: {
6553 // Like LSHR but preserves sign bit
6554 unsigned SrcIdx = PartIdx + ShiftWords;
6555 if (SrcIdx >= NumParts)
6556 return Params.SignBit;
6557 if (!NeedsInterWordShift)
6558 return SrcParts[SrcIdx];
6559
6560 // Only the original MSB part uses arithmetic shift to preserve sign. All
6561 // other parts use logical shift since they're just moving data bits.
6562 auto Lo =
6563 (SrcIdx == NumParts - 1)
6564 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6565 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6566 Register HiSrc =
6567 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6568 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6569 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6570 }
6571
6572 default:
6573 llvm_unreachable("not a shift");
6574 }
6575}
6576
6578 Register MainOperand,
6579 Register ShiftAmt,
6580 LLT TargetTy,
6581 Register CarryOperand) {
6582 // This helper generates a single output part for variable shifts by combining
6583 // the main operand (shifted by BitShift) with carry bits from an adjacent
6584 // part.
6585
6586 // For G_ASHR, individual parts don't have their own sign bit, only the
6587 // complete value does. So we use LSHR for the main operand shift in ASHR
6588 // context.
6589 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6590 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6591 : Opcode;
6592
6593 // Perform the primary shift on the main operand
6594 Register MainShifted =
6595 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6596 .getReg(0);
6597
6598 // No carry operand available
6599 if (!CarryOperand.isValid())
6600 return MainShifted;
6601
6602 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6603 // so carry bits aren't needed.
6604 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6605 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6606 LLT BoolTy = LLT::scalar(1);
6607 auto IsZeroBitShift =
6608 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6609
6610 // Extract bits from the adjacent part that will "carry over" into this part.
6611 // The carry direction is opposite to the main shift direction, so we can
6612 // align the two shifted values before combining them with OR.
6613
6614 // Determine the carry shift opcode (opposite direction)
6615 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6616 : TargetOpcode::G_SHL;
6617
6618 // Calculate inverse shift amount: BitWidth - ShiftAmt
6619 auto TargetBitsConst =
6620 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6621 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6622
6623 // Shift the carry operand
6624 Register CarryBits =
6626 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6627 .getReg(0);
6628
6629 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6630 // TargetBits which would be poison for the individual carry shift operation).
6631 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6632 Register SafeCarryBits =
6633 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6634 .getReg(0);
6635
6636 // Combine the main shifted part with the carry bits
6637 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6638}
6639
6642 const APInt &Amt,
6643 LLT TargetTy,
6644 LLT ShiftAmtTy) {
6645 // Any wide shift can be decomposed into WordShift + BitShift components.
6646 // When shift amount is known constant, directly compute the decomposition
6647 // values and generate constant registers.
6648 Register DstReg = MI.getOperand(0).getReg();
6649 Register SrcReg = MI.getOperand(1).getReg();
6650 LLT DstTy = MRI.getType(DstReg);
6651
6652 const unsigned DstBits = DstTy.getScalarSizeInBits();
6653 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6654 const unsigned NumParts = DstBits / TargetBits;
6655
6656 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6657
6658 // When the shift amount is known at compile time, we just calculate which
6659 // source parts contribute to each output part.
6660
6661 SmallVector<Register, 8> SrcParts;
6662 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6663
6664 if (Amt.isZero()) {
6665 // No shift needed, just copy
6666 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6667 MI.eraseFromParent();
6668 return Legalized;
6669 }
6670
6671 ShiftParams Params;
6672 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6673 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6674
6675 // Generate constants and values needed by all shift types
6676 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6677 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6678 Params.InvBitShift =
6679 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6680 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6681
6682 // For ASHR, we need the sign-extended value to fill shifted-out positions
6683 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6684 Params.SignBit =
6686 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6687 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6688 .getReg(0);
6689
6690 SmallVector<Register, 8> DstParts(NumParts);
6691 for (unsigned I = 0; I < NumParts; ++I)
6692 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6693 Params, TargetTy, ShiftAmtTy);
6694
6695 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6696 MI.eraseFromParent();
6697 return Legalized;
6698}
6699
6702 Register DstReg = MI.getOperand(0).getReg();
6703 Register SrcReg = MI.getOperand(1).getReg();
6704 Register AmtReg = MI.getOperand(2).getReg();
6705 LLT DstTy = MRI.getType(DstReg);
6706 LLT ShiftAmtTy = MRI.getType(AmtReg);
6707
6708 const unsigned DstBits = DstTy.getScalarSizeInBits();
6709 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6710 const unsigned NumParts = DstBits / TargetBits;
6711
6712 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6713 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6714
6715 // If the shift amount is known at compile time, we can use direct indexing
6716 // instead of generating select chains in the general case.
6717 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6718 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6719 ShiftAmtTy);
6720
6721 // For runtime-variable shift amounts, we must generate a more complex
6722 // sequence that handles all possible shift values using select chains.
6723
6724 // Split the input into target-sized pieces
6725 SmallVector<Register, 8> SrcParts;
6726 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6727
6728 // Shifting by zero should be a no-op.
6729 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6730 LLT BoolTy = LLT::scalar(1);
6731 auto IsZeroShift =
6732 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6733
6734 // Any wide shift can be decomposed into two components:
6735 // 1. WordShift: number of complete target-sized words to shift
6736 // 2. BitShift: number of bits to shift within each word
6737 //
6738 // Example: 128-bit >> 50 with 32-bit target:
6739 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6740 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6741 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6742 auto TargetBitsLog2Const =
6743 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6744 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6745
6746 Register WordShift =
6747 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6748 Register BitShift =
6749 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6750
6751 // Fill values:
6752 // - SHL/LSHR: fill with zeros
6753 // - ASHR: fill with sign-extended MSB
6754 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6755
6756 Register FillValue;
6757 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6758 auto TargetBitsMinusOneConst =
6759 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6760 FillValue = MIRBuilder
6761 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6762 TargetBitsMinusOneConst)
6763 .getReg(0);
6764 } else {
6765 FillValue = ZeroReg;
6766 }
6767
6768 SmallVector<Register, 8> DstParts(NumParts);
6769
6770 // For each output part, generate a select chain that chooses the correct
6771 // result based on the runtime WordShift value. This handles all possible
6772 // word shift amounts by pre-calculating what each would produce.
6773 for (unsigned I = 0; I < NumParts; ++I) {
6774 // Initialize with appropriate default value for this shift type
6775 Register InBoundsResult = FillValue;
6776
6777 // clang-format off
6778 // Build a branchless select chain by pre-computing results for all possible
6779 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6780 //
6781 // K=0: select(WordShift==0, result0, FillValue)
6782 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6783 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6784 // clang-format on
6785 for (unsigned K = 0; K < NumParts; ++K) {
6786 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6787 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6788 WordShift, WordShiftKConst);
6789
6790 // Calculate source indices for this word shift
6791 //
6792 // For 4-part 128-bit value with K=1 word shift:
6793 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6794 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6795 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6796 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6797 int MainSrcIdx;
6798 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6799
6800 switch (MI.getOpcode()) {
6801 case TargetOpcode::G_SHL:
6802 MainSrcIdx = (int)I - (int)K;
6803 CarrySrcIdx = MainSrcIdx - 1;
6804 break;
6805 case TargetOpcode::G_LSHR:
6806 case TargetOpcode::G_ASHR:
6807 MainSrcIdx = (int)I + (int)K;
6808 CarrySrcIdx = MainSrcIdx + 1;
6809 break;
6810 default:
6811 llvm_unreachable("Not a shift");
6812 }
6813
6814 // Check bounds and build the result for this word shift
6815 Register ResultForK;
6816 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6817 Register MainOp = SrcParts[MainSrcIdx];
6818 Register CarryOp;
6819
6820 // Determine carry operand with bounds checking
6821 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6822 CarryOp = SrcParts[CarrySrcIdx];
6823 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6824 CarrySrcIdx >= (int)NumParts)
6825 CarryOp = FillValue; // Use sign extension
6826
6827 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6828 TargetTy, CarryOp);
6829 } else {
6830 // Out of bounds - use fill value for this k
6831 ResultForK = FillValue;
6832 }
6833
6834 // Select this result if WordShift equals k
6835 InBoundsResult =
6837 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6838 .getReg(0);
6839 }
6840
6841 // Handle zero-shift special case: if shift is 0, use original input
6842 DstParts[I] =
6844 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6845 .getReg(0);
6846 }
6847
6848 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6849 MI.eraseFromParent();
6850 return Legalized;
6851}
6852
6855 LLT MoreTy) {
6856 assert(TypeIdx == 0 && "Expecting only Idx 0");
6857
6858 Observer.changingInstr(MI);
6859 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6860 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6861 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6862 moreElementsVectorSrc(MI, MoreTy, I);
6863 }
6864
6865 MachineBasicBlock &MBB = *MI.getParent();
6866 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6867 moreElementsVectorDst(MI, MoreTy, 0);
6868 Observer.changedInstr(MI);
6869 return Legalized;
6870}
6871
6872MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6873 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6874 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6875
6876 switch (Opcode) {
6877 default:
6879 "getNeutralElementForVecReduce called with invalid opcode!");
6880 case TargetOpcode::G_VECREDUCE_ADD:
6881 case TargetOpcode::G_VECREDUCE_OR:
6882 case TargetOpcode::G_VECREDUCE_XOR:
6883 case TargetOpcode::G_VECREDUCE_UMAX:
6884 return MIRBuilder.buildConstant(Ty, 0);
6885 case TargetOpcode::G_VECREDUCE_MUL:
6886 return MIRBuilder.buildConstant(Ty, 1);
6887 case TargetOpcode::G_VECREDUCE_AND:
6888 case TargetOpcode::G_VECREDUCE_UMIN:
6890 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6891 case TargetOpcode::G_VECREDUCE_SMAX:
6893 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6894 case TargetOpcode::G_VECREDUCE_SMIN:
6896 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6897 case TargetOpcode::G_VECREDUCE_FADD:
6898 return MIRBuilder.buildFConstant(Ty, -0.0);
6899 case TargetOpcode::G_VECREDUCE_FMUL:
6900 return MIRBuilder.buildFConstant(Ty, 1.0);
6901 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6902 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6903 assert(false && "getNeutralElementForVecReduce unimplemented for "
6904 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6905 }
6906 llvm_unreachable("switch expected to return!");
6907}
6908
6911 LLT MoreTy) {
6912 unsigned Opc = MI.getOpcode();
6913 switch (Opc) {
6914 case TargetOpcode::G_IMPLICIT_DEF:
6915 case TargetOpcode::G_LOAD: {
6916 if (TypeIdx != 0)
6917 return UnableToLegalize;
6918 Observer.changingInstr(MI);
6919 moreElementsVectorDst(MI, MoreTy, 0);
6920 Observer.changedInstr(MI);
6921 return Legalized;
6922 }
6923 case TargetOpcode::G_STORE:
6924 if (TypeIdx != 0)
6925 return UnableToLegalize;
6926 Observer.changingInstr(MI);
6927 moreElementsVectorSrc(MI, MoreTy, 0);
6928 Observer.changedInstr(MI);
6929 return Legalized;
6930 case TargetOpcode::G_AND:
6931 case TargetOpcode::G_OR:
6932 case TargetOpcode::G_XOR:
6933 case TargetOpcode::G_ADD:
6934 case TargetOpcode::G_SUB:
6935 case TargetOpcode::G_MUL:
6936 case TargetOpcode::G_FADD:
6937 case TargetOpcode::G_FSUB:
6938 case TargetOpcode::G_FMUL:
6939 case TargetOpcode::G_FDIV:
6940 case TargetOpcode::G_FCOPYSIGN:
6941 case TargetOpcode::G_UADDSAT:
6942 case TargetOpcode::G_USUBSAT:
6943 case TargetOpcode::G_SADDSAT:
6944 case TargetOpcode::G_SSUBSAT:
6945 case TargetOpcode::G_SMIN:
6946 case TargetOpcode::G_SMAX:
6947 case TargetOpcode::G_UMIN:
6948 case TargetOpcode::G_UMAX:
6949 case TargetOpcode::G_FMINNUM:
6950 case TargetOpcode::G_FMAXNUM:
6951 case TargetOpcode::G_FMINNUM_IEEE:
6952 case TargetOpcode::G_FMAXNUM_IEEE:
6953 case TargetOpcode::G_FMINIMUM:
6954 case TargetOpcode::G_FMAXIMUM:
6955 case TargetOpcode::G_FMINIMUMNUM:
6956 case TargetOpcode::G_FMAXIMUMNUM:
6957 case TargetOpcode::G_STRICT_FADD:
6958 case TargetOpcode::G_STRICT_FSUB:
6959 case TargetOpcode::G_STRICT_FMUL: {
6960 Observer.changingInstr(MI);
6961 moreElementsVectorSrc(MI, MoreTy, 1);
6962 moreElementsVectorSrc(MI, MoreTy, 2);
6963 moreElementsVectorDst(MI, MoreTy, 0);
6964 Observer.changedInstr(MI);
6965 return Legalized;
6966 }
6967 case TargetOpcode::G_SHL:
6968 case TargetOpcode::G_ASHR:
6969 case TargetOpcode::G_LSHR: {
6970 Observer.changingInstr(MI);
6971 moreElementsVectorSrc(MI, MoreTy, 1);
6972 // The shift operand may have a different scalar type from the source and
6973 // destination operands.
6974 LLT ShiftMoreTy = MoreTy.changeElementType(
6975 MRI.getType(MI.getOperand(2).getReg()).getElementType());
6976 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
6977 moreElementsVectorDst(MI, MoreTy, 0);
6978 Observer.changedInstr(MI);
6979 return Legalized;
6980 }
6981 case TargetOpcode::G_FMA:
6982 case TargetOpcode::G_STRICT_FMA:
6983 case TargetOpcode::G_FSHR:
6984 case TargetOpcode::G_FSHL: {
6985 Observer.changingInstr(MI);
6986 moreElementsVectorSrc(MI, MoreTy, 1);
6987 moreElementsVectorSrc(MI, MoreTy, 2);
6988 moreElementsVectorSrc(MI, MoreTy, 3);
6989 moreElementsVectorDst(MI, MoreTy, 0);
6990 Observer.changedInstr(MI);
6991 return Legalized;
6992 }
6993 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
6994 case TargetOpcode::G_EXTRACT:
6995 if (TypeIdx != 1)
6996 return UnableToLegalize;
6997 Observer.changingInstr(MI);
6998 moreElementsVectorSrc(MI, MoreTy, 1);
6999 Observer.changedInstr(MI);
7000 return Legalized;
7001 case TargetOpcode::G_INSERT:
7002 case TargetOpcode::G_INSERT_VECTOR_ELT:
7003 case TargetOpcode::G_FREEZE:
7004 case TargetOpcode::G_FNEG:
7005 case TargetOpcode::G_FABS:
7006 case TargetOpcode::G_FSQRT:
7007 case TargetOpcode::G_FCEIL:
7008 case TargetOpcode::G_FFLOOR:
7009 case TargetOpcode::G_FNEARBYINT:
7010 case TargetOpcode::G_FRINT:
7011 case TargetOpcode::G_INTRINSIC_ROUND:
7012 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
7013 case TargetOpcode::G_INTRINSIC_TRUNC:
7014 case TargetOpcode::G_BITREVERSE:
7015 case TargetOpcode::G_BSWAP:
7016 case TargetOpcode::G_FCANONICALIZE:
7017 case TargetOpcode::G_SEXT_INREG:
7018 case TargetOpcode::G_ABS:
7019 case TargetOpcode::G_CTLZ:
7020 case TargetOpcode::G_CTPOP:
7021 if (TypeIdx != 0)
7022 return UnableToLegalize;
7023 Observer.changingInstr(MI);
7024 moreElementsVectorSrc(MI, MoreTy, 1);
7025 moreElementsVectorDst(MI, MoreTy, 0);
7026 Observer.changedInstr(MI);
7027 return Legalized;
7028 case TargetOpcode::G_SELECT: {
7029 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
7030 if (TypeIdx == 1) {
7031 if (!CondTy.isScalar() ||
7032 DstTy.getElementCount() != MoreTy.getElementCount())
7033 return UnableToLegalize;
7034
7035 // This is turning a scalar select of vectors into a vector
7036 // select. Broadcast the select condition.
7037 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
7038 Observer.changingInstr(MI);
7039 MI.getOperand(1).setReg(ShufSplat.getReg(0));
7040 Observer.changedInstr(MI);
7041 return Legalized;
7042 }
7043
7044 if (CondTy.isVector())
7045 return UnableToLegalize;
7046
7047 Observer.changingInstr(MI);
7048 moreElementsVectorSrc(MI, MoreTy, 2);
7049 moreElementsVectorSrc(MI, MoreTy, 3);
7050 moreElementsVectorDst(MI, MoreTy, 0);
7051 Observer.changedInstr(MI);
7052 return Legalized;
7053 }
7054 case TargetOpcode::G_UNMERGE_VALUES:
7055 return UnableToLegalize;
7056 case TargetOpcode::G_PHI:
7057 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
7058 case TargetOpcode::G_SHUFFLE_VECTOR:
7059 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
7060 case TargetOpcode::G_BUILD_VECTOR: {
7062 for (auto Op : MI.uses()) {
7063 Elts.push_back(Op.getReg());
7064 }
7065
7066 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
7067 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
7068 }
7069
7070 MIRBuilder.buildDeleteTrailingVectorElements(
7071 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
7072 MI.eraseFromParent();
7073 return Legalized;
7074 }
7075 case TargetOpcode::G_SEXT:
7076 case TargetOpcode::G_ZEXT:
7077 case TargetOpcode::G_ANYEXT:
7078 case TargetOpcode::G_TRUNC:
7079 case TargetOpcode::G_FPTRUNC:
7080 case TargetOpcode::G_FPEXT:
7081 case TargetOpcode::G_FPTOSI:
7082 case TargetOpcode::G_FPTOUI:
7083 case TargetOpcode::G_FPTOSI_SAT:
7084 case TargetOpcode::G_FPTOUI_SAT:
7085 case TargetOpcode::G_SITOFP:
7086 case TargetOpcode::G_UITOFP:
7087 case TargetOpcode::G_TRUNC_SSAT_S:
7088 case TargetOpcode::G_TRUNC_SSAT_U:
7089 case TargetOpcode::G_TRUNC_USAT_U: {
7090 Observer.changingInstr(MI);
7091 LLT SrcExtTy;
7092 LLT DstExtTy;
7093 if (TypeIdx == 0) {
7094 DstExtTy = MoreTy;
7095 SrcExtTy = MoreTy.changeElementType(
7096 MRI.getType(MI.getOperand(1).getReg()).getElementType());
7097 } else {
7098 DstExtTy = MoreTy.changeElementType(
7099 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7100 SrcExtTy = MoreTy;
7101 }
7102 moreElementsVectorSrc(MI, SrcExtTy, 1);
7103 moreElementsVectorDst(MI, DstExtTy, 0);
7104 Observer.changedInstr(MI);
7105 return Legalized;
7106 }
7107 case TargetOpcode::G_ICMP:
7108 case TargetOpcode::G_FCMP: {
7109 if (TypeIdx != 1)
7110 return UnableToLegalize;
7111
7112 Observer.changingInstr(MI);
7113 moreElementsVectorSrc(MI, MoreTy, 2);
7114 moreElementsVectorSrc(MI, MoreTy, 3);
7115 LLT CondTy = MoreTy.changeVectorElementType(
7116 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7117 moreElementsVectorDst(MI, CondTy, 0);
7118 Observer.changedInstr(MI);
7119 return Legalized;
7120 }
7121 case TargetOpcode::G_BITCAST: {
7122 if (TypeIdx != 0)
7123 return UnableToLegalize;
7124
7125 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7126 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7127
7128 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7129 if (coefficient % DstTy.getNumElements() != 0)
7130 return UnableToLegalize;
7131
7132 coefficient = coefficient / DstTy.getNumElements();
7133
7134 LLT NewTy = SrcTy.changeElementCount(
7135 ElementCount::get(coefficient, MoreTy.isScalable()));
7136 Observer.changingInstr(MI);
7137 moreElementsVectorSrc(MI, NewTy, 1);
7138 moreElementsVectorDst(MI, MoreTy, 0);
7139 Observer.changedInstr(MI);
7140 return Legalized;
7141 }
7142 case TargetOpcode::G_VECREDUCE_FADD:
7143 case TargetOpcode::G_VECREDUCE_FMUL:
7144 case TargetOpcode::G_VECREDUCE_ADD:
7145 case TargetOpcode::G_VECREDUCE_MUL:
7146 case TargetOpcode::G_VECREDUCE_AND:
7147 case TargetOpcode::G_VECREDUCE_OR:
7148 case TargetOpcode::G_VECREDUCE_XOR:
7149 case TargetOpcode::G_VECREDUCE_SMAX:
7150 case TargetOpcode::G_VECREDUCE_SMIN:
7151 case TargetOpcode::G_VECREDUCE_UMAX:
7152 case TargetOpcode::G_VECREDUCE_UMIN: {
7153 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7154 MachineOperand &MO = MI.getOperand(1);
7155 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7156 auto NeutralElement = getNeutralElementForVecReduce(
7157 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7158
7159 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7160 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7161 i != e; i++) {
7162 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7163 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7164 NeutralElement, Idx);
7165 }
7166
7167 Observer.changingInstr(MI);
7168 MO.setReg(NewVec.getReg(0));
7169 Observer.changedInstr(MI);
7170 return Legalized;
7171 }
7172
7173 default:
7174 return UnableToLegalize;
7175 }
7176}
7177
7180 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7181 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7182 unsigned MaskNumElts = Mask.size();
7183 unsigned SrcNumElts = SrcTy.getNumElements();
7184 LLT DestEltTy = DstTy.getElementType();
7185
7186 if (MaskNumElts == SrcNumElts)
7187 return Legalized;
7188
7189 if (MaskNumElts < SrcNumElts) {
7190 // Extend mask to match new destination vector size with
7191 // undef values.
7192 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7193 llvm::copy(Mask, NewMask.begin());
7194
7195 moreElementsVectorDst(MI, SrcTy, 0);
7196 MIRBuilder.setInstrAndDebugLoc(MI);
7197 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7198 MI.getOperand(1).getReg(),
7199 MI.getOperand(2).getReg(), NewMask);
7200 MI.eraseFromParent();
7201
7202 return Legalized;
7203 }
7204
7205 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7206 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7207 LLT PaddedTy =
7208 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7209
7210 // Create new source vectors by concatenating the initial
7211 // source vectors with undefined vectors of the same size.
7212 auto Undef = MIRBuilder.buildUndef(SrcTy);
7213 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7214 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7215 MOps1[0] = MI.getOperand(1).getReg();
7216 MOps2[0] = MI.getOperand(2).getReg();
7217
7218 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7219 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7220
7221 // Readjust mask for new input vector length.
7222 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7223 for (unsigned I = 0; I != MaskNumElts; ++I) {
7224 int Idx = Mask[I];
7225 if (Idx >= static_cast<int>(SrcNumElts))
7226 Idx += PaddedMaskNumElts - SrcNumElts;
7227 MappedOps[I] = Idx;
7228 }
7229
7230 // If we got more elements than required, extract subvector.
7231 if (MaskNumElts != PaddedMaskNumElts) {
7232 auto Shuffle =
7233 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7234
7235 SmallVector<Register, 16> Elts(MaskNumElts);
7236 for (unsigned I = 0; I < MaskNumElts; ++I) {
7237 Elts[I] =
7238 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7239 .getReg(0);
7240 }
7241 MIRBuilder.buildBuildVector(DstReg, Elts);
7242 } else {
7243 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7244 }
7245
7246 MI.eraseFromParent();
7248}
7249
7252 unsigned int TypeIdx, LLT MoreTy) {
7253 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7254 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7255 unsigned NumElts = DstTy.getNumElements();
7256 unsigned WidenNumElts = MoreTy.getNumElements();
7257
7258 if (DstTy.isVector() && Src1Ty.isVector() &&
7259 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7261 }
7262
7263 if (TypeIdx != 0)
7264 return UnableToLegalize;
7265
7266 // Expect a canonicalized shuffle.
7267 if (DstTy != Src1Ty || DstTy != Src2Ty)
7268 return UnableToLegalize;
7269
7270 moreElementsVectorSrc(MI, MoreTy, 1);
7271 moreElementsVectorSrc(MI, MoreTy, 2);
7272
7273 // Adjust mask based on new input vector length.
7274 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7275 for (unsigned I = 0; I != NumElts; ++I) {
7276 int Idx = Mask[I];
7277 if (Idx < static_cast<int>(NumElts))
7278 NewMask[I] = Idx;
7279 else
7280 NewMask[I] = Idx - NumElts + WidenNumElts;
7281 }
7282 moreElementsVectorDst(MI, MoreTy, 0);
7283 MIRBuilder.setInstrAndDebugLoc(MI);
7284 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7285 MI.getOperand(1).getReg(),
7286 MI.getOperand(2).getReg(), NewMask);
7287 MI.eraseFromParent();
7288 return Legalized;
7289}
7290
7291void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7292 ArrayRef<Register> Src1Regs,
7293 ArrayRef<Register> Src2Regs,
7294 LLT NarrowTy) {
7296 unsigned SrcParts = Src1Regs.size();
7297 unsigned DstParts = DstRegs.size();
7298
7299 unsigned DstIdx = 0; // Low bits of the result.
7300 Register FactorSum =
7301 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7302 DstRegs[DstIdx] = FactorSum;
7303
7304 Register CarrySumPrevDstIdx;
7306
7307 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7308 // Collect high parts of muls from previous DstIdx.
7309 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7310 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7311 MachineInstrBuilder Umulh =
7312 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7313 Factors.push_back(Umulh.getReg(0));
7314 }
7315 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7316 // the low Src1 part, so multiply-add selectors can use it as the first
7317 // accumulated cross product.
7318 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7319 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7320 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7321 unsigned i = RevI - 1;
7323 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7324 Factors.push_back(Mul.getReg(0));
7325 }
7326 // Add CarrySum from additions calculated for previous DstIdx.
7327 if (DstIdx != 1) {
7328 Factors.push_back(CarrySumPrevDstIdx);
7329 }
7330
7331 Register CarrySum;
7332 // Add all factors and accumulate all carries into CarrySum.
7333 if (DstIdx != DstParts - 1) {
7334 MachineInstrBuilder Uaddo =
7335 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7336 FactorSum = Uaddo.getReg(0);
7337 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7338 for (unsigned i = 2; i < Factors.size(); ++i) {
7339 MachineInstrBuilder Uaddo =
7340 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7341 FactorSum = Uaddo.getReg(0);
7342 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7343 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7344 }
7345 } else {
7346 // Since value for the next index is not calculated, neither is CarrySum.
7347 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7348 for (unsigned i = 2; i < Factors.size(); ++i)
7349 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7350 }
7351
7352 CarrySumPrevDstIdx = CarrySum;
7353 DstRegs[DstIdx] = FactorSum;
7354 Factors.clear();
7355 }
7356}
7357
7360 LLT NarrowTy) {
7361 if (TypeIdx != 0)
7362 return UnableToLegalize;
7363
7364 Register DstReg = MI.getOperand(0).getReg();
7365 LLT DstType = MRI.getType(DstReg);
7366 // FIXME: add support for vector types
7367 if (DstType.isVector())
7368 return UnableToLegalize;
7369
7370 unsigned Opcode = MI.getOpcode();
7371 unsigned OpO, OpE, OpF;
7372 switch (Opcode) {
7373 case TargetOpcode::G_SADDO:
7374 case TargetOpcode::G_SADDE:
7375 case TargetOpcode::G_UADDO:
7376 case TargetOpcode::G_UADDE:
7377 case TargetOpcode::G_ADD:
7378 OpO = TargetOpcode::G_UADDO;
7379 OpE = TargetOpcode::G_UADDE;
7380 OpF = TargetOpcode::G_UADDE;
7381 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7382 OpF = TargetOpcode::G_SADDE;
7383 break;
7384 case TargetOpcode::G_SSUBO:
7385 case TargetOpcode::G_SSUBE:
7386 case TargetOpcode::G_USUBO:
7387 case TargetOpcode::G_USUBE:
7388 case TargetOpcode::G_SUB:
7389 OpO = TargetOpcode::G_USUBO;
7390 OpE = TargetOpcode::G_USUBE;
7391 OpF = TargetOpcode::G_USUBE;
7392 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7393 OpF = TargetOpcode::G_SSUBE;
7394 break;
7395 default:
7396 llvm_unreachable("Unexpected add/sub opcode!");
7397 }
7398
7399 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7400 unsigned NumDefs = MI.getNumExplicitDefs();
7401 Register Src1 = MI.getOperand(NumDefs).getReg();
7402 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7403 Register CarryDst, CarryIn;
7404 if (NumDefs == 2)
7405 CarryDst = MI.getOperand(1).getReg();
7406 if (MI.getNumOperands() == NumDefs + 3)
7407 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7408
7409 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7410 LLT LeftoverTy, DummyTy;
7411 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7412 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7413 MIRBuilder, MRI);
7414 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7415 MRI);
7416
7417 int NarrowParts = Src1Regs.size();
7418 Src1Regs.append(Src1Left);
7419 Src2Regs.append(Src2Left);
7420 DstRegs.reserve(Src1Regs.size());
7421
7422 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7423 Register DstReg =
7424 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7425 Register CarryOut;
7426 // Forward the final carry-out to the destination register
7427 if (i == e - 1 && CarryDst)
7428 CarryOut = CarryDst;
7429 else
7430 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7431
7432 if (!CarryIn) {
7433 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7434 {Src1Regs[i], Src2Regs[i]});
7435 } else if (i == e - 1) {
7436 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7437 {Src1Regs[i], Src2Regs[i], CarryIn});
7438 } else {
7439 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7440 {Src1Regs[i], Src2Regs[i], CarryIn});
7441 }
7442
7443 DstRegs.push_back(DstReg);
7444 CarryIn = CarryOut;
7445 }
7446 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7447 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7448 ArrayRef(DstRegs).drop_front(NarrowParts));
7449
7450 MI.eraseFromParent();
7451 return Legalized;
7452}
7453
7456 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7457
7458 LLT Ty = MRI.getType(DstReg);
7459 if (Ty.isVector())
7460 return UnableToLegalize;
7461
7462 unsigned Size = Ty.getSizeInBits();
7463 unsigned NarrowSize = NarrowTy.getSizeInBits();
7464 if (Size % NarrowSize != 0)
7465 return UnableToLegalize;
7466
7467 unsigned NumParts = Size / NarrowSize;
7468 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
7469 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7470
7471 SmallVector<Register, 2> Src1Parts, Src2Parts;
7472 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7473 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7474 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7475 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7476
7477 // Take only high half of registers if this is high mul.
7478 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7479 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7480 MI.eraseFromParent();
7481 return Legalized;
7482}
7483
7486 LLT NarrowTy) {
7487 if (TypeIdx != 0)
7488 return UnableToLegalize;
7489
7490 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7491
7492 Register Src = MI.getOperand(1).getReg();
7493 LLT SrcTy = MRI.getType(Src);
7494
7495 // If all finite floats fit into the narrowed integer type, we can just swap
7496 // out the result type. This is practically only useful for conversions from
7497 // half to at least 16-bits, so just handle the one case.
7498 if (SrcTy.getScalarType() != LLT::scalar(16) ||
7499 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7500 return UnableToLegalize;
7501
7502 Observer.changingInstr(MI);
7503 narrowScalarDst(MI, NarrowTy, 0,
7504 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7505 Observer.changedInstr(MI);
7506 return Legalized;
7507}
7508
7511 LLT NarrowTy) {
7512 if (TypeIdx != 1)
7513 return UnableToLegalize;
7514
7515 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7516
7517 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7518 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7519 // NarrowSize.
7520 if (SizeOp1 % NarrowSize != 0)
7521 return UnableToLegalize;
7522 int NumParts = SizeOp1 / NarrowSize;
7523
7524 SmallVector<Register, 2> SrcRegs, DstRegs;
7525 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7526 MIRBuilder, MRI);
7527
7528 Register OpReg = MI.getOperand(0).getReg();
7529 uint64_t OpStart = MI.getOperand(2).getImm();
7530 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7531 for (int i = 0; i < NumParts; ++i) {
7532 unsigned SrcStart = i * NarrowSize;
7533
7534 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7535 // No part of the extract uses this subregister, ignore it.
7536 continue;
7537 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7538 // The entire subregister is extracted, forward the value.
7539 DstRegs.push_back(SrcRegs[i]);
7540 continue;
7541 }
7542
7543 // OpSegStart is where this destination segment would start in OpReg if it
7544 // extended infinitely in both directions.
7545 int64_t ExtractOffset;
7546 uint64_t SegSize;
7547 if (OpStart < SrcStart) {
7548 ExtractOffset = 0;
7549 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7550 } else {
7551 ExtractOffset = OpStart - SrcStart;
7552 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7553 }
7554
7555 Register SegReg = SrcRegs[i];
7556 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7557 // A genuine extract is needed.
7558 SegReg = MRI.createGenericVirtualRegister(LLT::integer(SegSize));
7559 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7560 }
7561
7562 DstRegs.push_back(SegReg);
7563 }
7564
7565 Register DstReg = MI.getOperand(0).getReg();
7566 if (MRI.getType(DstReg).isVector())
7567 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7568 else if (DstRegs.size() > 1)
7569 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7570 else
7571 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7572 MI.eraseFromParent();
7573 return Legalized;
7574}
7575
7578 LLT NarrowTy) {
7579 // FIXME: Don't know how to handle secondary types yet.
7580 if (TypeIdx != 0)
7581 return UnableToLegalize;
7582
7583 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7584 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7585 LLT LeftoverTy;
7586 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7587 LeftoverRegs, MIRBuilder, MRI);
7588
7589 SrcRegs.append(LeftoverRegs);
7590
7591 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7592 Register OpReg = MI.getOperand(2).getReg();
7593 uint64_t OpStart = MI.getOperand(3).getImm();
7594 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7595 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7596 unsigned DstStart = I * NarrowSize;
7597
7598 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7599 // The entire subregister is defined by this insert, forward the new
7600 // value.
7601 DstRegs.push_back(OpReg);
7602 continue;
7603 }
7604
7605 Register SrcReg = SrcRegs[I];
7606 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7607 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7608 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7609 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7610 }
7611
7612 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7613 // No part of the insert affects this subregister, forward the original.
7614 DstRegs.push_back(SrcReg);
7615 continue;
7616 }
7617
7618 // OpSegStart is where this destination segment would start in OpReg if it
7619 // extended infinitely in both directions.
7620 int64_t ExtractOffset, InsertOffset;
7621 uint64_t SegSize;
7622 if (OpStart < DstStart) {
7623 InsertOffset = 0;
7624 ExtractOffset = DstStart - OpStart;
7625 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7626 } else {
7627 InsertOffset = OpStart - DstStart;
7628 ExtractOffset = 0;
7629 SegSize =
7630 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
7631 }
7632
7633 Register SegReg = OpReg;
7634 if (ExtractOffset != 0 || SegSize != OpSize) {
7635 // A genuine extract is needed.
7636 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7637 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7638 }
7639
7640 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7641 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7642 DstRegs.push_back(DstReg);
7643 }
7644
7645 uint64_t WideSize = DstRegs.size() * NarrowSize;
7646 Register DstReg = MI.getOperand(0).getReg();
7647 if (WideSize > RegTy.getSizeInBits()) {
7648 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7649 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7650 MIRBuilder.buildTrunc(DstReg, MergeReg);
7651 } else
7652 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7653
7654 MI.eraseFromParent();
7655 return Legalized;
7656}
7657
7660 LLT NarrowTy) {
7661 Register DstReg = MI.getOperand(0).getReg();
7662 LLT DstTy = MRI.getType(DstReg);
7663
7664 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7665
7666 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7667 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7668 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7669 LLT LeftoverTy;
7670 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7671 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7672 return UnableToLegalize;
7673
7674 LLT Unused;
7675 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7676 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7677 llvm_unreachable("inconsistent extractParts result");
7678
7679 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7680 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7681 {Src0Regs[I], Src1Regs[I]});
7682 DstRegs.push_back(Inst.getReg(0));
7683 }
7684
7685 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7686 auto Inst = MIRBuilder.buildInstr(
7687 MI.getOpcode(),
7688 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7689 DstLeftoverRegs.push_back(Inst.getReg(0));
7690 }
7691
7692 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7693 LeftoverTy, DstLeftoverRegs);
7694
7695 MI.eraseFromParent();
7696 return Legalized;
7697}
7698
7701 LLT NarrowTy) {
7702 if (TypeIdx != 0)
7703 return UnableToLegalize;
7704
7705 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7706
7707 LLT DstTy = MRI.getType(DstReg);
7708 if (DstTy.isVector())
7709 return UnableToLegalize;
7710
7712 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7713 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7714 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7715
7716 MI.eraseFromParent();
7717 return Legalized;
7718}
7719
7722 LLT NarrowTy) {
7723 if (TypeIdx != 0)
7724 return UnableToLegalize;
7725
7726 Register CondReg = MI.getOperand(1).getReg();
7727 LLT CondTy = MRI.getType(CondReg);
7728 if (CondTy.isVector()) // TODO: Handle vselect
7729 return UnableToLegalize;
7730
7731 Register DstReg = MI.getOperand(0).getReg();
7732 LLT DstTy = MRI.getType(DstReg);
7733
7734 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7735 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7736 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7737 LLT LeftoverTy;
7738 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7739 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7740 return UnableToLegalize;
7741
7742 LLT Unused;
7743 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7744 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7745 llvm_unreachable("inconsistent extractParts result");
7746
7747 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7748 auto Select = MIRBuilder.buildSelect(NarrowTy,
7749 CondReg, Src1Regs[I], Src2Regs[I]);
7750 DstRegs.push_back(Select.getReg(0));
7751 }
7752
7753 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7754 auto Select = MIRBuilder.buildSelect(
7755 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7756 DstLeftoverRegs.push_back(Select.getReg(0));
7757 }
7758
7759 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7760 LeftoverTy, DstLeftoverRegs);
7761
7762 MI.eraseFromParent();
7763 return Legalized;
7764}
7765
7768 LLT NarrowTy) {
7769 if (TypeIdx != 1)
7770 return UnableToLegalize;
7771
7772 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7773 unsigned NarrowSize = NarrowTy.getSizeInBits();
7774
7775 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7776 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7777
7779 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7780 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7781 auto C_0 = B.buildConstant(NarrowTy, 0);
7782 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7783 UnmergeSrc.getReg(1), C_0);
7784 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7785 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7786 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7787 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7788 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7789 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7790
7791 MI.eraseFromParent();
7792 return Legalized;
7793 }
7794
7795 return UnableToLegalize;
7796}
7797
7800 LLT NarrowTy) {
7801 if (TypeIdx != 1)
7802 return UnableToLegalize;
7803
7804 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7805 unsigned NarrowSize = NarrowTy.getSizeInBits();
7806
7807 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7808 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7809
7811 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7812 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7813 auto C_0 = B.buildConstant(NarrowTy, 0);
7814 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7815 UnmergeSrc.getReg(0), C_0);
7816 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7817 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7818 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7819 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7820 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7821 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7822
7823 MI.eraseFromParent();
7824 return Legalized;
7825 }
7826
7827 return UnableToLegalize;
7828}
7829
7832 LLT NarrowTy) {
7833 if (TypeIdx != 1)
7834 return UnableToLegalize;
7835
7836 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7837 unsigned NarrowSize = NarrowTy.getSizeInBits();
7838
7839 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7840 return UnableToLegalize;
7841
7843
7844 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7845 Register Lo = UnmergeSrc.getReg(0);
7846 Register Hi = UnmergeSrc.getReg(1);
7847
7848 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7849 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7850
7851 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7852
7853 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7854 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7855 // Otherwise the leading zeros represent additional sign bits of the original
7856 // value.
7857 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7858 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7859
7860 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7861 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7862 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7863
7864 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7865
7866 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7867
7868 MI.eraseFromParent();
7869 return Legalized;
7870}
7871
7874 LLT NarrowTy) {
7875 if (TypeIdx != 1)
7876 return UnableToLegalize;
7877
7878 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7879 unsigned NarrowSize = NarrowTy.getSizeInBits();
7880
7881 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7882 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
7883
7884 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
7885 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
7886 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
7887
7888 MI.eraseFromParent();
7889 return Legalized;
7890 }
7891
7892 return UnableToLegalize;
7893}
7894
7897 LLT NarrowTy) {
7898 if (TypeIdx != 1)
7899 return UnableToLegalize;
7900
7902 Register ExpReg = MI.getOperand(2).getReg();
7903 LLT ExpTy = MRI.getType(ExpReg);
7904
7905 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
7906
7907 // Clamp the exponent to the range of the target type.
7908 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
7909 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
7910 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
7911 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
7912
7913 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
7914 Observer.changingInstr(MI);
7915 MI.getOperand(2).setReg(Trunc.getReg(0));
7916 Observer.changedInstr(MI);
7917 return Legalized;
7918}
7919
7922 unsigned Opc = MI.getOpcode();
7923 const auto &TII = MIRBuilder.getTII();
7924 auto isSupported = [this](const LegalityQuery &Q) {
7925 auto QAction = LI.getAction(Q).Action;
7926 return QAction == Legal || QAction == Libcall || QAction == Custom;
7927 };
7928 switch (Opc) {
7929 default:
7930 return UnableToLegalize;
7931 case TargetOpcode::G_CTLZ_ZERO_POISON: {
7932 // This trivially expands to CTLZ.
7933 Observer.changingInstr(MI);
7934 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
7935 Observer.changedInstr(MI);
7936 return Legalized;
7937 }
7938 case TargetOpcode::G_CTLZ: {
7939 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7940 unsigned Len = SrcTy.getScalarSizeInBits();
7941
7942 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
7943 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
7944 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
7945 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
7946 auto ICmp = MIRBuilder.buildICmp(
7947 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
7948 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7949 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
7950 MI.eraseFromParent();
7951 return Legalized;
7952 }
7953 // for now, we do this:
7954 // NewLen = NextPowerOf2(Len);
7955 // x = x | (x >> 1);
7956 // x = x | (x >> 2);
7957 // ...
7958 // x = x | (x >>16);
7959 // x = x | (x >>32); // for 64-bit input
7960 // Upto NewLen/2
7961 // return Len - popcount(x);
7962 //
7963 // Ref: "Hacker's Delight" by Henry Warren
7964 Register Op = SrcReg;
7965 unsigned NewLen = PowerOf2Ceil(Len);
7966 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
7967 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
7968 auto MIBOp = MIRBuilder.buildOr(
7969 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
7970 Op = MIBOp.getReg(0);
7971 }
7972 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
7973 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
7974 MIBPop);
7975 MI.eraseFromParent();
7976 return Legalized;
7977 }
7978 case TargetOpcode::G_CTTZ_ZERO_POISON: {
7979 // This trivially expands to CTTZ.
7980 Observer.changingInstr(MI);
7981 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
7982 Observer.changedInstr(MI);
7983 return Legalized;
7984 }
7985 case TargetOpcode::G_CTTZ: {
7986 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7987
7988 unsigned Len = SrcTy.getScalarSizeInBits();
7989 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
7990 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
7991 // zero.
7992 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
7993 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
7994 auto ICmp = MIRBuilder.buildICmp(
7995 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
7996 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7997 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
7998 MI.eraseFromParent();
7999 return Legalized;
8000 }
8001 // for now, we use: { return popcount(~x & (x - 1)); }
8002 // unless the target has ctlz but not ctpop, in which case we use:
8003 // { return 32 - nlz(~x & (x-1)); }
8004 // Ref: "Hacker's Delight" by Henry Warren
8005 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
8006 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
8007 auto MIBTmp = MIRBuilder.buildAnd(
8008 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
8009 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
8010 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
8011 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
8012 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
8013 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
8014 MI.eraseFromParent();
8015 return Legalized;
8016 }
8017 Observer.changingInstr(MI);
8018 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
8019 MI.getOperand(1).setReg(MIBTmp.getReg(0));
8020 Observer.changedInstr(MI);
8021 return Legalized;
8022 }
8023 case TargetOpcode::G_CTPOP: {
8024 Register SrcReg = MI.getOperand(1).getReg();
8025 LLT Ty = MRI.getType(SrcReg);
8026 unsigned Size = Ty.getScalarSizeInBits();
8028
8029 // Bail out on irregular type lengths.
8030 if (Size > 128 || Size % 8 != 0)
8031 return UnableToLegalize;
8032
8033 // Count set bits in blocks of 2 bits. Default approach would be
8034 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
8035 // We use following formula instead:
8036 // B2Count = val - { (val >> 1) & 0x55555555 }
8037 // since it gives same result in blocks of 2 with one instruction less.
8038 auto C_1 = B.buildConstant(Ty, 1);
8039 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
8040 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
8041 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
8042 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
8043 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
8044
8045 // In order to get count in blocks of 4 add values from adjacent block of 2.
8046 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
8047 auto C_2 = B.buildConstant(Ty, 2);
8048 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
8049 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
8050 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
8051 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
8052 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
8053 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
8054
8055 // For count in blocks of 8 bits we don't have to mask high 4 bits before
8056 // addition since count value sits in range {0,...,8} and 4 bits are enough
8057 // to hold such binary values. After addition high 4 bits still hold count
8058 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
8059 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
8060 auto C_4 = B.buildConstant(Ty, 4);
8061 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
8062 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
8063 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
8064 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
8065 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
8066
8067 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
8068
8069 // Avoid the multiply when shift-add is cheaper.
8070 if (Size == 16 && !Ty.isVector()) {
8071 // v = (v + (v >> 8)) & 0xFF;
8072 auto C_8 = B.buildConstant(Ty, 8);
8073 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
8074 auto Res = B.buildAdd(Ty, B8Count, HighSum);
8075 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
8076 MI.eraseFromParent();
8077 return Legalized;
8078 }
8079
8080 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
8081 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
8082 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
8083
8084 // Shift count result from 8 high bits to low bits.
8085 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
8086
8087 auto IsMulSupported = [this](const LLT Ty) {
8088 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
8089 return Action == Legal || Action == WidenScalar || Action == Custom;
8090 };
8091 if (IsMulSupported(Ty)) {
8092 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
8093 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8094 } else {
8095 auto ResTmp = B8Count;
8096 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
8097 auto ShiftC = B.buildConstant(Ty, Shift);
8098 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
8099 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
8100 }
8101 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8102 }
8103 MI.eraseFromParent();
8104 return Legalized;
8105 }
8106 case TargetOpcode::G_CTLS: {
8107 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8108
8109 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
8110 auto SignIdxC =
8111 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
8112 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
8113
8114 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
8115
8116 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
8117 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
8118
8119 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8120 MI.eraseFromParent();
8121 return Legalized;
8122 }
8123 }
8124}
8125
8126// Check that (every element of) Reg is undef or not an exact multiple of BW.
8128 Register Reg, unsigned BW) {
8129 return matchUnaryPredicate(
8130 MRI, Reg,
8131 [=](const Constant *C) {
8132 // Null constant here means an undef.
8134 return !CI || CI->getValue().urem(BW) != 0;
8135 },
8136 /*AllowUndefs*/ true);
8137}
8138
8141 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8142 LLT Ty = MRI.getType(Dst);
8143 LLT ShTy = MRI.getType(Z);
8144
8145 unsigned BW = Ty.getScalarSizeInBits();
8146
8147 if (!isPowerOf2_32(BW))
8148 return UnableToLegalize;
8149
8150 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8151 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8152
8153 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8154 // fshl X, Y, Z -> fshr X, Y, -Z
8155 // fshr X, Y, Z -> fshl X, Y, -Z
8156 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8157 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8158 } else {
8159 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8160 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8161 auto One = MIRBuilder.buildConstant(ShTy, 1);
8162 if (IsFSHL) {
8163 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8164 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8165 } else {
8166 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8167 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8168 }
8169
8170 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8171 }
8172
8173 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8174 MI.eraseFromParent();
8175 return Legalized;
8176}
8177
8180 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8181 LLT Ty = MRI.getType(Dst);
8182 LLT ShTy = MRI.getType(Z);
8183
8184 const unsigned BW = Ty.getScalarSizeInBits();
8185 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8186
8187 Register ShX, ShY;
8188 Register ShAmt, InvShAmt;
8189
8190 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8191 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8192 // fshl: X << C | Y >> (BW - C)
8193 // fshr: X << (BW - C) | Y >> C
8194 // where C = Z % BW is not zero
8195 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8196 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8197 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8198 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8199 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8200 } else {
8201 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8202 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8203 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8204 if (isPowerOf2_32(BW)) {
8205 // Z % BW -> Z & (BW - 1)
8206 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8207 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8208 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8209 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8210 } else {
8211 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8212 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8213 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8214 }
8215
8216 auto One = MIRBuilder.buildConstant(ShTy, 1);
8217 if (IsFSHL) {
8218 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8219 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8220 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8221 } else {
8222 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8223 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8224 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8225 }
8226 }
8227
8228 MIRBuilder.buildOr(Dst, ShX, ShY, MachineInstr::Disjoint);
8229 MI.eraseFromParent();
8230 return Legalized;
8231}
8232
8235 // These operations approximately do the following (while avoiding undefined
8236 // shifts by BW):
8237 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8238 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8239 Register Dst = MI.getOperand(0).getReg();
8240 LLT Ty = MRI.getType(Dst);
8241 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8242
8243 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8244 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8245
8246 // TODO: Use smarter heuristic that accounts for vector legalization.
8247 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8248 return lowerFunnelShiftAsShifts(MI);
8249
8250 // This only works for powers of 2, fallback to shifts if it fails.
8251 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8252 if (Result == UnableToLegalize)
8253 return lowerFunnelShiftAsShifts(MI);
8254 return Result;
8255}
8256
8258 auto [Dst, Src] = MI.getFirst2Regs();
8259 LLT DstTy = MRI.getType(Dst);
8260 LLT SrcTy = MRI.getType(Src);
8261
8262 uint32_t DstTySize = DstTy.getSizeInBits();
8263 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8264 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8265
8266 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8267 !isPowerOf2_32(SrcTyScalarSize))
8268 return UnableToLegalize;
8269
8270 // The step between extend is too large, split it by creating an intermediate
8271 // extend instruction
8272 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8273 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8274 // If the destination type is illegal, split it into multiple statements
8275 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8276 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8277 // Unmerge the vector
8278 LLT EltTy = MidTy.changeElementCount(
8280 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8281
8282 // ZExt the vectors
8283 LLT ZExtResTy = DstTy.changeElementCount(
8285 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8286 {UnmergeSrc.getReg(0)});
8287 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8288 {UnmergeSrc.getReg(1)});
8289
8290 // Merge the ending vectors
8291 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8292
8293 MI.eraseFromParent();
8294 return Legalized;
8295 }
8296 return UnableToLegalize;
8297}
8298
8300 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8301 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8302 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8303 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8304 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8305 // %lo16(<4 x s16>) = G_TRUNC %inlo
8306 // %hi16(<4 x s16>) = G_TRUNC %inhi
8307 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8308 // %res(<8 x s8>) = G_TRUNC %in16
8309
8310 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8311
8312 Register DstReg = MI.getOperand(0).getReg();
8313 Register SrcReg = MI.getOperand(1).getReg();
8314 LLT DstTy = MRI.getType(DstReg);
8315 LLT SrcTy = MRI.getType(SrcReg);
8316
8317 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8319 isPowerOf2_32(SrcTy.getNumElements()) &&
8320 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8321 // Split input type.
8322 LLT SplitSrcTy = SrcTy.changeElementCount(
8323 SrcTy.getElementCount().divideCoefficientBy(2));
8324
8325 // First, split the source into two smaller vectors.
8326 SmallVector<Register, 2> SplitSrcs;
8327 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8328
8329 // Truncate the splits into intermediate narrower elements.
8330 LLT InterTy;
8331 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8332 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8333 else
8334 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8335 for (Register &Src : SplitSrcs)
8336 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8337
8338 // Combine the new truncates into one vector
8339 auto Merge = MIRBuilder.buildMergeLikeInstr(
8340 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8341
8342 // Truncate the new vector to the final result type
8343 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8344 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8345 else
8346 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8347
8348 MI.eraseFromParent();
8349
8350 return Legalized;
8351 }
8352 return UnableToLegalize;
8353}
8354
8357 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8358 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8359 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8360 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8361 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8362 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8363 MI.eraseFromParent();
8364 return Legalized;
8365}
8366
8368 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8369
8370 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8371 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8372
8373 MIRBuilder.setInstrAndDebugLoc(MI);
8374
8375 // If a rotate in the other direction is supported, use it.
8376 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8377 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8378 isPowerOf2_32(EltSizeInBits))
8379 return lowerRotateWithReverseRotate(MI);
8380
8381 // If a funnel shift is supported, use it.
8382 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8383 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8384 bool IsFShLegal = false;
8385 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8386 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8387 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8388 Register R3) {
8389 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8390 MI.eraseFromParent();
8391 return Legalized;
8392 };
8393 // If a funnel shift in the other direction is supported, use it.
8394 if (IsFShLegal) {
8395 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8396 } else if (isPowerOf2_32(EltSizeInBits)) {
8397 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8398 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8399 }
8400 }
8401
8402 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8403 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8404 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8405 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8406 Register ShVal;
8407 Register RevShiftVal;
8408 if (isPowerOf2_32(EltSizeInBits)) {
8409 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8410 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8411 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8412 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8413 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8414 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8415 RevShiftVal =
8416 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8417 } else {
8418 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8419 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8420 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8421 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8422 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8423 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8424 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8425 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8426 RevShiftVal =
8427 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8428 }
8429 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, MachineInstr::Disjoint);
8430 MI.eraseFromParent();
8431 return Legalized;
8432}
8433
8434// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8435// operations and G_SITOFP
8438 auto [Dst, Src] = MI.getFirst2Regs();
8439 const LLT S64 = LLT::scalar(64);
8440 const LLT S32 = LLT::scalar(32);
8441 const LLT S1 = LLT::scalar(1);
8442
8443 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8444
8445 // For i64 < INT_MAX we simply reuse SITOFP.
8446 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8447 // saved before division, convert to float by SITOFP, multiply the result
8448 // by 2.
8449 auto One = MIRBuilder.buildConstant(S64, 1);
8450 auto Zero = MIRBuilder.buildConstant(S64, 0);
8451 // Result if Src < INT_MAX
8452 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8453 // Result if Src >= INT_MAX
8454 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8455 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8456 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8457 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8458 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8459 // Check if the original value is larger than INT_MAX by comparing with
8460 // zero to pick one of the two conversions.
8461 auto IsLarge =
8462 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
8463 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8464
8465 MI.eraseFromParent();
8466 return Legalized;
8467}
8468
8469// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8470// IEEE double representation.
8473 auto [Dst, Src] = MI.getFirst2Regs();
8474 const LLT S64 = LLT::scalar(64);
8475 const LLT S32 = LLT::scalar(32);
8476
8477 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8478
8479 // We create double value from 32 bit parts with 32 exponent difference.
8480 // Note that + and - are float operations that adjust the implicit leading
8481 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8482 //
8483 // X = 2^52 * 1.0...LowBits
8484 // Y = 2^84 * 1.0...HighBits
8485 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8486 // = - 2^52 * 1.0...HighBits
8487 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8488 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8489 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8490 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8491 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8492 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8493
8494 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8495 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8496 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8497 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8498 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8499 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8500 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8501
8502 MI.eraseFromParent();
8503 return Legalized;
8504}
8505
8506/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8507/// convert fpround f64->f16 without double-rounding, so we manually perform the
8508/// lowering here where we know it is valid.
8511 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8512 auto DstFpTy =
8513 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8514 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8515 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8516 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8517 LLT F32Ty = DstFpTy.changeElementSize(32);
8518 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8519 MIRBuilder.buildFPTrunc(Dst, M2);
8520 MI.eraseFromParent();
8522}
8523
8525 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8526
8527 if (SrcTy == LLT::scalar(1)) {
8528 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8529 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8530 MIRBuilder.buildSelect(Dst, Src, True, False);
8531 MI.eraseFromParent();
8532 return Legalized;
8533 }
8534
8535 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8536 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8537
8538 if (SrcTy != LLT::scalar(64))
8539 return UnableToLegalize;
8540
8541 if (DstTy == LLT::scalar(32))
8542 // TODO: SelectionDAG has several alternative expansions to port which may
8543 // be more reasonable depending on the available instructions. We also need
8544 // a more advanced mechanism to choose an optimal version depending on
8545 // target features such as sitofp or CTLZ availability.
8547
8548 if (DstTy == LLT::scalar(64))
8550
8551 return UnableToLegalize;
8552}
8553
8555 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8556
8557 const LLT I64 = LLT::integer(64);
8558 const LLT I32 = LLT::integer(32);
8559 const LLT I1 = LLT::integer(1);
8560
8561 if (SrcTy == I1) {
8562 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8563 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8564 MIRBuilder.buildSelect(Dst, Src, True, False);
8565 MI.eraseFromParent();
8566 return Legalized;
8567 }
8568
8569 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8570 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8571
8572 if (SrcTy != I64)
8573 return UnableToLegalize;
8574
8575 if (DstTy.getScalarSizeInBits() == 32) {
8576 // signed cl2f(long l) {
8577 // long s = l >> 63;
8578 // float r = cul2f((l + s) ^ s);
8579 // return s ? -r : r;
8580 // }
8581 Register L = Src;
8582 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8583 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8584
8585 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8586 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8587 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8588
8589 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8590 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8591 MIRBuilder.buildConstant(I64, 0));
8592 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8593 MI.eraseFromParent();
8594 return Legalized;
8595 }
8596
8597 return UnableToLegalize;
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 if (SrcTy != S64 && SrcTy != S32)
8606 return UnableToLegalize;
8607 if (DstTy != S32 && DstTy != S64)
8608 return UnableToLegalize;
8609
8610 // FPTOSI gives same result as FPTOUI for positive signed integers.
8611 // FPTOUI needs to deal with fp values that convert to unsigned integers
8612 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8613
8614 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8615 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8617 APInt::getZero(SrcTy.getSizeInBits()));
8618 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8619
8620 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8621
8622 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8623 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8624 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8625 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8626 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8627 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8628 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8629
8630 const LLT S1 = LLT::scalar(1);
8631
8632 MachineInstrBuilder FCMP =
8633 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8634 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8635
8636 MI.eraseFromParent();
8637 return Legalized;
8638}
8639
8641 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8642 const LLT S64 = LLT::scalar(64);
8643 const LLT S32 = LLT::scalar(32);
8644
8645 // FIXME: Only f32 to i64 conversions are supported.
8646 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8647 return UnableToLegalize;
8648
8649 // Expand f32 -> i64 conversion
8650 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8651 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8652
8653 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8654
8655 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8656 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8657
8658 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8659 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8660
8661 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8662 APInt::getSignMask(SrcEltBits));
8663 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8664 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8665 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8666 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8667
8668 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8669 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8670 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8671
8672 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8673 R = MIRBuilder.buildZExt(DstTy, R);
8674
8675 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8676 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8677 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8678 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8679
8680 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8681 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8682
8683 const LLT S1 = LLT::scalar(1);
8684 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8685 S1, Exponent, ExponentLoBit);
8686
8687 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8688
8689 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8690 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8691
8692 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8693
8694 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8695 S1, Exponent, ZeroSrcTy);
8696
8697 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8698 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8699
8700 MI.eraseFromParent();
8701 return Legalized;
8702}
8703
8706 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8707
8708 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8709 unsigned SatWidth = DstTy.getScalarSizeInBits();
8710
8711 // Determine minimum and maximum integer values and their corresponding
8712 // floating-point values.
8713 APInt MinInt, MaxInt;
8714 if (IsSigned) {
8715 MinInt = APInt::getSignedMinValue(SatWidth);
8716 MaxInt = APInt::getSignedMaxValue(SatWidth);
8717 } else {
8718 MinInt = APInt::getMinValue(SatWidth);
8719 MaxInt = APInt::getMaxValue(SatWidth);
8720 }
8721
8722 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8723 APFloat MinFloat(Semantics);
8724 APFloat MaxFloat(Semantics);
8725
8726 APFloat::opStatus MinStatus =
8727 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8728 APFloat::opStatus MaxStatus =
8729 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8730 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8731 !(MaxStatus & APFloat::opStatus::opInexact);
8732
8733 // If the integer bounds are exactly representable as floats, emit a
8734 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8735 // and selects.
8736 if (AreExactFloatBounds) {
8737 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8738 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8739 auto MaxP =
8740 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8741 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8742 // Clamp by MaxFloat from above. NaN cannot occur.
8743 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8744 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8746 auto Min =
8747 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8748 // Convert clamped value to integer. In the unsigned case we're done,
8749 // because we mapped NaN to MinFloat, which will cast to zero.
8750 if (!IsSigned) {
8751 MIRBuilder.buildFPTOUI(Dst, Min);
8752 MI.eraseFromParent();
8753 return Legalized;
8754 }
8755
8756 // Otherwise, select 0 if Src is NaN.
8757 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8758 auto IsZero =
8759 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8760 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8761 FpToInt);
8762 MI.eraseFromParent();
8763 return Legalized;
8764 }
8765
8766 // Result of direct conversion. The assumption here is that the operation is
8767 // non-trapping and it's fine to apply it to an out-of-range value if we
8768 // select it away later.
8769 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8770 : MIRBuilder.buildFPTOUI(DstTy, Src);
8771
8772 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8773 // MinInt if Src is NaN.
8774 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8775 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8776 auto Max = MIRBuilder.buildSelect(
8777 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8778 // If Src OGT MaxFloat, select MaxInt.
8779 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8780 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8781
8782 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8783 // is already zero.
8784 if (!IsSigned) {
8785 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8786 Max);
8787 MI.eraseFromParent();
8788 return Legalized;
8789 }
8790
8791 // Otherwise, select 0 if Src is NaN.
8792 auto Min = MIRBuilder.buildSelect(
8793 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8794 auto IsZero =
8795 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8796 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8797 MI.eraseFromParent();
8798 return Legalized;
8799}
8800
8801// Floating-point conversions using truncating and extending loads and stores.
8804 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8805 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8806 "Only G_FPEXT and G_FPTRUNC are expected");
8807
8808 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8809 MachinePointerInfo PtrInfo;
8810 unsigned StoreOpc;
8811 unsigned LoadOpc;
8812 LLT StackTy;
8813 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8814 StackTy = SrcTy;
8815 StoreOpc = TargetOpcode::G_STORE;
8816 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8817 } else {
8818 StackTy = DstTy;
8819 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8820 LoadOpc = TargetOpcode::G_LOAD;
8821 }
8822
8823 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8824 auto StackTemp =
8825 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8826
8827 MachineFunction &MF = MIRBuilder.getMF();
8828 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8829 StackTy, StackTyAlign);
8830 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8831
8832 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8833 StackTy, StackTyAlign);
8834 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8835
8836 MI.eraseFromParent();
8837 return Legalized;
8838}
8839
8840// Expand a bf16 -> f32/f64 fpext with a shift and bitcast. This is based on the
8841// SDAG ISD::BF16_TO_FP lowering.
8844 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8845 assert(SrcTy.getScalarType().isBFloat16() &&
8846 "expected a bf16 source for bf16 fpext lowering");
8847
8848 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8849 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8850 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
8851
8852 auto SrcI =
8853 MIRBuilder.buildAnyExt(I32Ty, MIRBuilder.buildBitcast(I16Ty, SrcReg));
8854 auto Shl =
8855 MIRBuilder.buildShl(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8856
8857 if (DstTy.getScalarType().isFloat32())
8858 MIRBuilder.buildBitcast(DstReg, Shl);
8859 else
8860 MIRBuilder.buildFPExt(DstReg, MIRBuilder.buildBitcast(F32Ty, Shl));
8861
8862 MI.eraseFromParent();
8863 return Legalized;
8864}
8865
8867 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
8868 if (SrcTy.getScalarType().isBFloat16() &&
8869 (DstTy.getScalarType().isFloat32() || DstTy.getScalarType().isFloat64()))
8870 return lowerFPEXT_BF16(MI);
8871
8872 return lowerFPExtAndTruncMem(MI);
8873}
8874
8875// f64 -> f16 conversion using round-to-nearest-even rounding mode.
8878 const LLT S1 = LLT::scalar(1);
8879 const LLT I32 = LLT::integer(32);
8880
8881 auto [Dst, Src] = MI.getFirst2Regs();
8882 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
8883 MRI.getType(Src).getScalarType() == LLT::float64());
8884
8885 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
8886 return UnableToLegalize;
8887
8888 if (MI.getFlag(MachineInstr::FmAfn)) {
8889 unsigned Flags = MI.getFlags();
8890 auto Src32 = MIRBuilder.buildFPTrunc(LLT::float32(), Src, Flags);
8891 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
8892 MI.eraseFromParent();
8893 return Legalized;
8894 }
8895
8896 const unsigned ExpMask = 0x7ff;
8897 const unsigned ExpBiasf64 = 1023;
8898 const unsigned ExpBiasf16 = 15;
8899
8900 auto Unmerge = MIRBuilder.buildUnmerge(I32, Src);
8901 Register U = Unmerge.getReg(0);
8902 Register UH = Unmerge.getReg(1);
8903
8904 auto E = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 20));
8905 E = MIRBuilder.buildAnd(I32, E, MIRBuilder.buildConstant(I32, ExpMask));
8906
8907 // Subtract the fp64 exponent bias (1023) to get the real exponent and
8908 // add the f16 bias (15) to get the biased exponent for the f16 format.
8909 E = MIRBuilder.buildAdd(
8910 I32, E, MIRBuilder.buildConstant(I32, -ExpBiasf64 + ExpBiasf16));
8911
8912 auto M = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 8));
8913 M = MIRBuilder.buildAnd(I32, M, MIRBuilder.buildConstant(I32, 0xffe));
8914
8915 auto MaskedSig =
8916 MIRBuilder.buildAnd(I32, UH, MIRBuilder.buildConstant(I32, 0x1ff));
8917 MaskedSig = MIRBuilder.buildOr(I32, MaskedSig, U);
8918
8919 auto Zero = MIRBuilder.buildConstant(I32, 0);
8920 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
8921 auto Lo40Set = MIRBuilder.buildZExt(I32, SigCmpNE0);
8922 M = MIRBuilder.buildOr(I32, M, Lo40Set);
8923
8924 // (M != 0 ? 0x0200 : 0) | 0x7c00;
8925 auto Bits0x200 = MIRBuilder.buildConstant(I32, 0x0200);
8926 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
8927 auto SelectCC = MIRBuilder.buildSelect(I32, CmpM_NE0, Bits0x200, Zero);
8928
8929 auto Bits0x7c00 = MIRBuilder.buildConstant(I32, 0x7c00);
8930 auto I = MIRBuilder.buildOr(I32, SelectCC, Bits0x7c00);
8931
8932 // N = M | (E << 12);
8933 auto EShl12 = MIRBuilder.buildShl(I32, E, MIRBuilder.buildConstant(I32, 12));
8934 auto N = MIRBuilder.buildOr(I32, M, EShl12);
8935
8936 // B = clamp(1-E, 0, 13);
8937 auto One = MIRBuilder.buildConstant(I32, 1);
8938 auto OneSubExp = MIRBuilder.buildSub(I32, One, E);
8939 auto B = MIRBuilder.buildSMax(I32, OneSubExp, Zero);
8940 B = MIRBuilder.buildSMin(I32, B, MIRBuilder.buildConstant(I32, 13));
8941
8942 auto SigSetHigh =
8943 MIRBuilder.buildOr(I32, M, MIRBuilder.buildConstant(I32, 0x1000));
8944
8945 auto D = MIRBuilder.buildLShr(I32, SigSetHigh, B);
8946 auto D0 = MIRBuilder.buildShl(I32, D, B);
8947
8948 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
8949 D0, SigSetHigh);
8950 auto D1 = MIRBuilder.buildZExt(I32, D0_NE_SigSetHigh);
8951 D = MIRBuilder.buildOr(I32, D, D1);
8952
8953 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
8954 auto V = MIRBuilder.buildSelect(I32, CmpELtOne, D, N);
8955
8956 auto VLow3 = MIRBuilder.buildAnd(I32, V, MIRBuilder.buildConstant(I32, 7));
8957 V = MIRBuilder.buildLShr(I32, V, MIRBuilder.buildConstant(I32, 2));
8958
8959 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
8960 MIRBuilder.buildConstant(I32, 3));
8961 auto V0 = MIRBuilder.buildZExt(I32, VLow3Eq3);
8962
8963 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
8964 MIRBuilder.buildConstant(I32, 5));
8965 auto V1 = MIRBuilder.buildZExt(I32, VLow3Gt5);
8966
8967 V1 = MIRBuilder.buildOr(I32, V0, V1);
8968 V = MIRBuilder.buildAdd(I32, V, V1);
8969
8970 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, E,
8971 MIRBuilder.buildConstant(I32, 30));
8972 V = MIRBuilder.buildSelect(I32, CmpEGt30,
8973 MIRBuilder.buildConstant(I32, 0x7c00), V);
8974
8975 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, E,
8976 MIRBuilder.buildConstant(I32, 1039));
8977 V = MIRBuilder.buildSelect(I32, CmpEGt1039, I, V);
8978
8979 // Extract the sign bit.
8980 auto Sign = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 16));
8981 Sign = MIRBuilder.buildAnd(I32, Sign, MIRBuilder.buildConstant(I32, 0x8000));
8982
8983 // Insert the sign bit
8984 V = MIRBuilder.buildOr(I32, Sign, V);
8985
8986 MIRBuilder.buildTrunc(Dst, V);
8987 MI.eraseFromParent();
8988 return Legalized;
8989}
8990
8991// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
8994 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8995 assert(DstTy.getScalarType() == LLT::bfloat16() &&
8996 SrcTy.getScalarType() == LLT::float32());
8997
8998 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
8999 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
9000 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
9001
9002 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
9003
9004 // Conversions should set NaN's quiet bit. This also prevents NaNs from
9005 // turning into infinities.
9006 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
9007 MIRBuilder.buildConstant(I32Ty, 0x400000));
9008
9009 // Factor in the contribution of the low 16 bits.
9010 auto Lsb =
9011 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
9012 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
9013 auto RoundingBias =
9014 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
9015 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
9016
9017 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
9018 // 0x80000000.
9019 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9020 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
9021 MIRBuilder.buildFConstant(SrcTy, 0));
9022 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
9023 }
9024
9025 // Now that we have rounded, shift the bits into position.
9026 auto Srl =
9027 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
9028 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
9029 MIRBuilder.buildBitcast(DstReg, Trunc);
9030 MI.eraseFromParent();
9031 return Legalized;
9032}
9033
9034// Round a wide fp value to ResultTy's element size, forcing inexact
9035// results to the odd value so a subsequent narrowing round is correct. This
9036// avoids double-rounding when narrowing e.g. f64 -> f32 -> bf16. See Boldo &
9037// Melquiond, "When double rounding is odd" (2005).
9039 LLT OperandTy = MRI.getType(Op);
9040 if (OperandTy.getScalarType() == ResultTy.getScalarType())
9041 return Op;
9042
9043 LLT ResultIntTy =
9045 LLT ResultCCTy = ResultTy.changeElementType(LLT::integer(1));
9046 LLT OperandCCTy = OperandTy.changeElementType(LLT::integer(1));
9047
9048 auto Narrow = MIRBuilder.buildFPTrunc(ResultTy, Op);
9049 auto NarrowAsWide = MIRBuilder.buildFPExt(OperandTy, Narrow);
9050
9051 auto NarrowBits = MIRBuilder.buildBitcast(ResultIntTy, Narrow);
9052 auto One = MIRBuilder.buildConstant(ResultIntTy, 1);
9053 auto NegativeOne = MIRBuilder.buildConstant(ResultIntTy, -1);
9054 auto Zero = MIRBuilder.buildConstant(ResultIntTy, 0);
9055 auto And = MIRBuilder.buildAnd(ResultIntTy, NarrowBits, One);
9056 // The result is already odd so we don't need to do anything.
9057 auto AlreadyOdd =
9058 MIRBuilder.buildICmp(CmpInst::ICMP_NE, ResultCCTy, And, Zero);
9059
9060 // We keep results which are exact, odd or NaN.
9061 auto KeepNarrow =
9062 MIRBuilder.buildFCmp(CmpInst::FCMP_UEQ, OperandCCTy, Op, NarrowAsWide);
9063 KeepNarrow = MIRBuilder.buildOr(OperandCCTy, KeepNarrow, AlreadyOdd);
9064 // We morally performed a round-down if AbsNarrow is smaller than AbsWide.
9065 auto AbsWide = MIRBuilder.buildFAbs(OperandTy, Op);
9066 auto AbsNarrowAsWide = MIRBuilder.buildFAbs(OperandTy, NarrowAsWide);
9067 auto NarrowIsRd = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, OperandCCTy,
9068 AbsWide, AbsNarrowAsWide);
9069 // If narrow is the rounded-down value, pick the rounded-up value as it will
9070 // be odd; otherwise adjust down.
9071 auto Adjust =
9072 MIRBuilder.buildSelect(ResultIntTy, NarrowIsRd, One, NegativeOne);
9073 auto Adjusted = MIRBuilder.buildAdd(ResultIntTy, NarrowBits, Adjust);
9074 auto Res =
9075 MIRBuilder.buildSelect(ResultIntTy, KeepNarrow, NarrowBits, Adjusted);
9076 return MIRBuilder.buildBitcast(ResultTy, Res).getReg(0);
9077}
9078
9079// f64 -> bf16 conversion, correcting for double rounding.
9082 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9083 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9084 SrcTy.getScalarType() == LLT::float64());
9085
9086 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
9087 Register OddF32 = lowerRoundInexactToOdd(F32Ty, SrcReg);
9088 MIRBuilder.buildFPTrunc(DstReg, OddF32, MI.getFlags());
9089 MI.eraseFromParent();
9090 return Legalized;
9091}
9092
9095 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9096 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
9098
9099 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
9101
9102 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat64())
9104
9105 return lowerFPExtAndTruncMem(MI);
9106}
9107
9109 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9110 LLT Ty = MRI.getType(Dst);
9111
9112 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
9113 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
9114 MI.eraseFromParent();
9115 return Legalized;
9116}
9117
9119 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
9120 LLT Ty = MRI.getType(Src);
9121 auto Flags = MI.getFlags();
9122 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9123
9124 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
9125 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
9126
9127 Register FracToUse;
9128 if (MI.getFlag(MachineInstr::FmNoInfs)) {
9129 FracToUse = FracPart.getReg(0);
9130 } else {
9131 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
9132 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
9133 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
9134 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
9135 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9136 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
9137 FracToUse = Select.getReg(0);
9138 }
9139
9140 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
9141 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
9142
9143 MI.eraseFromParent();
9144 return Legalized;
9145}
9146
9148 switch (Opc) {
9149 case TargetOpcode::G_SMIN:
9150 return CmpInst::ICMP_SLT;
9151 case TargetOpcode::G_SMAX:
9152 return CmpInst::ICMP_SGT;
9153 case TargetOpcode::G_UMIN:
9154 return CmpInst::ICMP_ULT;
9155 case TargetOpcode::G_UMAX:
9156 return CmpInst::ICMP_UGT;
9157 default:
9158 llvm_unreachable("not in integer min/max");
9159 }
9160}
9161
9163 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9164
9165 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9166 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9167
9168 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9169 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9170
9171 MI.eraseFromParent();
9172 return Legalized;
9173}
9174
9177 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9178
9179 Register Dst = Cmp->getReg(0);
9180 LLT DstTy = MRI.getType(Dst);
9181 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9182 LLT CmpTy = DstTy.changeElementSize(1);
9183
9184 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9187 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9190
9191 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9192 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9193 Cmp->getRHSReg());
9194 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9195 Cmp->getRHSReg());
9196
9197 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9198 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9199 if (TLI.preferSelectsOverBooleanArithmetic(
9200 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9202 auto One = MIRBuilder.buildConstant(DstTy, 1);
9203 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9204
9205 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9206 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9207 } else {
9209 std::swap(IsGT, IsLT);
9210 // Extend boolean results to DstTy, which is at least i2, before subtracting
9211 // them.
9212 unsigned BoolExtOp =
9213 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9214 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9215 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9216 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9217 }
9218
9219 MI.eraseFromParent();
9220 return Legalized;
9221}
9222
9225 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9226 const int Src0Size = Src0Ty.getScalarSizeInBits();
9227 const int Src1Size = Src1Ty.getScalarSizeInBits();
9228
9229 LLT DstIntTy =
9230 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9231 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9232 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9233
9234 Register Src0Int = Src0;
9235 Register Src1Int = Src1;
9236
9237 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9238 Src0Ty.getScalarType().isInteger()))
9239 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9240
9241 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9242 Src1Ty.getScalarType().isInteger()))
9243 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9244
9245 auto SignBitMask =
9246 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9247
9248 auto NotSignBitMask = MIRBuilder.buildConstant(
9249 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9250
9251 Register And0 =
9252 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9253 Register And1;
9254 if (Src0Ty == Src1Ty) {
9255 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9256 } else if (Src0Size > Src1Size) {
9257 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9258 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9259 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9260 And1 = MIRBuilder.buildAnd(Src0IntTy, Shift, SignBitMask).getReg(0);
9261 } else {
9262 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9263 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9264 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9265 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9266 }
9267
9268 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9269 // constants are a nan and -0.0, but the final result should preserve
9270 // everything.
9271 unsigned Flags = MI.getFlags();
9272
9273 // We masked the sign bit and the not-sign bit, so these are disjoint.
9274 Flags |= MachineInstr::Disjoint;
9275
9276 if (DstTy == DstIntTy)
9277 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9278 else {
9279 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9280 MIRBuilder.buildBitcast(Dst, NewDst);
9281 }
9282
9283 MI.eraseFromParent();
9284 return Legalized;
9285}
9286
9289 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9290 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9291 // depend on fminnum/fmaxnum.
9292
9293 unsigned NewOp;
9294 switch (MI.getOpcode()) {
9295 case TargetOpcode::G_FMINNUM:
9296 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9297 break;
9298 case TargetOpcode::G_FMINIMUMNUM:
9299 NewOp = TargetOpcode::G_FMINNUM;
9300 break;
9301 case TargetOpcode::G_FMAXNUM:
9302 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9303 break;
9304 case TargetOpcode::G_FMAXIMUMNUM:
9305 NewOp = TargetOpcode::G_FMAXNUM;
9306 break;
9307 default:
9308 llvm_unreachable("unexpected min/max opcode");
9309 }
9310
9311 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9312 LLT Ty = MRI.getType(Dst);
9313
9314 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9315 // Insert canonicalizes if it's possible we need to quiet to get correct
9316 // sNaN behavior.
9317
9318 // Note this must be done here, and not as an optimization combine in the
9319 // absence of a dedicate quiet-snan instruction as we're using an
9320 // omni-purpose G_FCANONICALIZE.
9321 if (!VT->isKnownNeverSNaN(Src0))
9322 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9323
9324 if (!VT->isKnownNeverSNaN(Src1))
9325 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9326 }
9327
9328 // If there are no nans, it's safe to simply replace this with the non-IEEE
9329 // version.
9330 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9331 MI.eraseFromParent();
9332 return Legalized;
9333}
9334
9337 unsigned Opc = MI.getOpcode();
9338 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9339 LLT Ty = MRI.getType(Dst);
9340 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9341
9342 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9343 unsigned OpcIeee =
9344 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9345 unsigned OpcNonIeee =
9346 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9347 bool MinMaxMustRespectOrderedZero = false;
9348 Register Res;
9349
9350 // IEEE variants don't need canonicalization
9351 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9352 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9353 MinMaxMustRespectOrderedZero = true;
9354 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9355 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9356 } else {
9357 auto Compare = MIRBuilder.buildFCmp(
9358 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9359 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9360 }
9361
9362 // Propagate any NaN of both operands
9363 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9364 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9365 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9366
9367 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9368 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9369 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9370 if (Ty.isVector())
9371 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9372
9373 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9374 }
9375
9376 // fminimum/fmaximum requires -0.0 less than +0.0
9377 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9378 GISelValueTracking VT(MIRBuilder.getMF());
9379 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9380 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9381
9382 if (!Src0Info.isKnownNeverZero() && !Src1Info.isKnownNeverZero()) {
9383 const unsigned Flags = MI.getFlags();
9384 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9385 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9386
9387 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9388
9389 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9390 auto LHSSelect =
9391 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9392
9393 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9394 auto RHSSelect =
9395 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9396
9397 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9398 }
9399 }
9400
9401 MIRBuilder.buildCopy(Dst, Res);
9402 MI.eraseFromParent();
9403 return Legalized;
9404}
9405
9407 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9408 Register DstReg = MI.getOperand(0).getReg();
9409 LLT Ty = MRI.getType(DstReg);
9410 unsigned Flags = MI.getFlags();
9411
9412 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9413 Flags);
9414 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9415 MI.eraseFromParent();
9416 return Legalized;
9417}
9418
9421 auto [DstReg, X] = MI.getFirst2Regs();
9422 const unsigned Flags = MI.getFlags();
9423 const LLT Ty = MRI.getType(DstReg);
9424 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9425
9426 // round(x) =>
9427 // t = trunc(x);
9428 // d = fabs(x - t);
9429 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9430 // return t + o;
9431
9432 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9433
9434 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9435 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9436
9437 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9438 auto Cmp =
9439 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9440
9441 // Could emit G_UITOFP instead
9442 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9443 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9444 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9445 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9446
9447 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9448
9449 MI.eraseFromParent();
9450 return Legalized;
9451}
9452
9454 auto [DstReg, SrcReg] = MI.getFirst2Regs();
9455 unsigned Flags = MI.getFlags();
9456 LLT Ty = MRI.getType(DstReg);
9457 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9458
9459 // result = trunc(src);
9460 // if (src < 0.0 && src != result)
9461 // result += -1.0.
9462
9463 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
9464 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9465
9466 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
9467 SrcReg, Zero, Flags);
9468 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
9469 SrcReg, Trunc, Flags);
9470 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
9471 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
9472
9473 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
9474 MI.eraseFromParent();
9475 return Legalized;
9476}
9477
9480 const unsigned NumOps = MI.getNumOperands();
9481 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
9482 unsigned PartSize = Src0Ty.getSizeInBits();
9483
9484 LLT WideTy = LLT::integer(DstTy.getSizeInBits());
9485 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
9486
9487 for (unsigned I = 2; I != NumOps; ++I) {
9488 const unsigned Offset = (I - 1) * PartSize;
9489
9490 Register SrcReg = MI.getOperand(I).getReg();
9491 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
9492
9493 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
9494 MRI.createGenericVirtualRegister(WideTy);
9495
9496 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
9497 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
9498 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
9499 ResultReg = NextResult;
9500 }
9501
9502 if (DstTy.isPointer()) {
9503 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
9504 DstTy.getAddressSpace())) {
9505 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
9506 return UnableToLegalize;
9507 }
9508
9509 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9510 } else if (WideTy != DstTy) {
9511 MIRBuilder.buildBitcast(DstReg, ResultReg);
9512 }
9513
9514 MI.eraseFromParent();
9515 return Legalized;
9516}
9517
9520 const unsigned NumDst = MI.getNumOperands() - 1;
9521 Register SrcReg = MI.getOperand(NumDst).getReg();
9522 Register Dst0Reg = MI.getOperand(0).getReg();
9523 LLT DstTy = MRI.getType(Dst0Reg);
9524 if (DstTy.isPointer())
9525 return UnableToLegalize; // TODO
9526
9527 SrcReg = coerceToInteger(SrcReg);
9528 if (!SrcReg)
9529 return UnableToLegalize;
9530
9531 // Expand scalarizing unmerge as bitcast to integer and shift.
9532 LLT IntTy = MRI.getType(SrcReg);
9533
9534 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
9535
9536 const unsigned DstSize = DstTy.getSizeInBits();
9537 unsigned Offset = DstSize;
9538 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
9539 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
9540 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
9541 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
9542 }
9543
9544 MI.eraseFromParent();
9545 return Legalized;
9546}
9547
9548/// Lower a vector extract or insert by writing the vector to a stack temporary
9549/// and reloading the element or vector.
9550///
9551/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
9552/// =>
9553/// %stack_temp = G_FRAME_INDEX
9554/// G_STORE %vec, %stack_temp
9555/// %idx = clamp(%idx, %vec.getNumElements())
9556/// %element_ptr = G_PTR_ADD %stack_temp, %idx
9557/// %dst = G_LOAD %element_ptr
9560 Register DstReg = MI.getOperand(0).getReg();
9561 Register SrcVec = MI.getOperand(1).getReg();
9562 Register InsertVal;
9563 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
9564 InsertVal = MI.getOperand(2).getReg();
9565
9566 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
9567
9568 LLT VecTy = MRI.getType(SrcVec);
9569 LLT EltTy = VecTy.getElementType();
9570 unsigned NumElts = VecTy.getNumElements();
9571
9572 int64_t IdxVal;
9573 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
9575 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
9576
9577 if (InsertVal) {
9578 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
9579 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
9580 } else {
9581 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
9582 }
9583
9584 MI.eraseFromParent();
9585 return Legalized;
9586 }
9587
9588 if (!EltTy.isByteSized()) { // Not implemented.
9589 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
9590 return UnableToLegalize;
9591 }
9592
9593 unsigned EltBytes = EltTy.getSizeInBytes();
9594 Align VecAlign = getStackTemporaryAlignment(VecTy);
9595 Align EltAlign;
9596
9597 MachinePointerInfo PtrInfo;
9598 auto StackTemp = createStackTemporary(
9599 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
9600 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
9601
9602 // Get the pointer to the element, and be sure not to hit undefined behavior
9603 // if the index is out of bounds.
9604 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
9605
9606 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
9607 int64_t Offset = IdxVal * EltBytes;
9608 PtrInfo = PtrInfo.getWithOffset(Offset);
9609 EltAlign = commonAlignment(VecAlign, Offset);
9610 } else {
9611 // We lose information with a variable offset.
9612 EltAlign = getStackTemporaryAlignment(EltTy);
9613 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
9614 }
9615
9616 if (InsertVal) {
9617 // Write the inserted element
9618 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
9619
9620 // Reload the whole vector.
9621 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
9622 } else {
9623 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
9624 }
9625
9626 MI.eraseFromParent();
9627 return Legalized;
9628}
9629
9632 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
9633 MI.getFirst3RegLLTs();
9634 LLT IdxTy = LLT::scalar(32);
9635
9636 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
9639 LLT EltTy = DstTy.getScalarType();
9640
9641 DenseMap<unsigned, Register> CachedExtract;
9642
9643 for (int Idx : Mask) {
9644 if (Idx < 0) {
9645 if (!Undef.isValid())
9646 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
9647 BuildVec.push_back(Undef);
9648 continue;
9649 }
9650
9651 assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");
9652
9653 int NumElts = Src0Ty.getNumElements();
9654 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
9655 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
9656 auto [It, Inserted] = CachedExtract.try_emplace(Idx);
9657 if (Inserted) {
9658 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
9659 It->second =
9660 MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);
9661 }
9662 BuildVec.push_back(It->second);
9663 }
9664
9665 assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");
9666 MIRBuilder.buildBuildVector(DstReg, BuildVec);
9667 MI.eraseFromParent();
9668 return Legalized;
9669}
9670
9673 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
9674 MI.getFirst4RegLLTs();
9675
9676 if (VecTy.isScalableVector())
9677 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
9678
9679 Align VecAlign = getStackTemporaryAlignment(VecTy);
9680 MachinePointerInfo PtrInfo;
9681 Register StackPtr =
9682 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
9683 PtrInfo)
9684 .getReg(0);
9685 MachinePointerInfo ValPtrInfo =
9687
9688 LLT IdxTy = LLT::integer(32);
9689 LLT ValTy = VecTy.getElementType();
9690 Align ValAlign = getStackTemporaryAlignment(ValTy);
9691
9692 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
9693
9694 bool HasPassthru = !mi_match(Passthru, MRI, m_GImplicitDef());
9695
9696 if (HasPassthru)
9697 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
9698
9699 Register LastWriteVal;
9700 std::optional<APInt> PassthruSplatVal =
9701 isConstantOrConstantSplatVector(Passthru, MRI);
9702
9703 if (PassthruSplatVal.has_value()) {
9704 LastWriteVal =
9705 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
9706 } else if (HasPassthru) {
9707 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
9708 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
9709 {LLT::integer(32)}, {Popcount});
9710
9711 Register LastElmtPtr =
9712 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
9713 LastWriteVal =
9714 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
9715 .getReg(0);
9716 }
9717
9718 unsigned NumElmts = VecTy.getNumElements();
9719 for (unsigned I = 0; I < NumElmts; ++I) {
9720 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
9721 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
9722 Register ElmtPtr =
9723 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9724 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
9725
9726 LLT MaskITy = MaskTy.getElementType();
9727 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
9728 if (MaskITy.getSizeInBits() > 1)
9729 MaskI = MIRBuilder.buildTrunc(LLT::integer(1), MaskI);
9730
9731 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
9732 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
9733
9734 if (HasPassthru && I == NumElmts - 1) {
9735 auto EndOfVector =
9736 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
9737 auto AllLanesSelected = MIRBuilder.buildICmp(
9738 CmpInst::ICMP_UGT, LLT::integer(1), OutPos, EndOfVector);
9739 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
9740 {OutPos, EndOfVector});
9741 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9742
9743 LastWriteVal =
9744 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
9745 .getReg(0);
9746 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
9747 }
9748 }
9749
9750 // TODO: Use StackPtr's FrameIndex alignment.
9751 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
9752
9753 MI.eraseFromParent();
9754 return Legalized;
9755}
9756
9758 Register AllocSize,
9759 Align Alignment,
9760 LLT PtrTy) {
9762
9763 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
9764 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
9765
9766 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
9767 // have to generate an extra instruction to negate the alloc and then use
9768 // G_PTR_ADD to add the negative offset.
9769 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
9770 if (Alignment > Align(1)) {
9771 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
9772 AlignMask.negate();
9773 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
9774 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
9775 }
9776
9777 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
9778}
9779
9782 const auto &MF = *MI.getMF();
9783 const auto &TFI = *MF.getSubtarget().getFrameLowering();
9784 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
9785 return UnableToLegalize;
9786
9787 Register Dst = MI.getOperand(0).getReg();
9788 Register AllocSize = MI.getOperand(1).getReg();
9789 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
9790
9791 LLT PtrTy = MRI.getType(Dst);
9792 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
9793 Register SPTmp =
9794 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
9795
9796 MIRBuilder.buildCopy(SPReg, SPTmp);
9797 MIRBuilder.buildCopy(Dst, SPTmp);
9798
9799 MI.eraseFromParent();
9800 return Legalized;
9801}
9802
9805 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9806 if (!StackPtr)
9807 return UnableToLegalize;
9808
9809 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
9810 MI.eraseFromParent();
9811 return Legalized;
9812}
9813
9816 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9817 if (!StackPtr)
9818 return UnableToLegalize;
9819
9820 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
9821 MI.eraseFromParent();
9822 return Legalized;
9823}
9824
9827 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9828 unsigned Offset = MI.getOperand(2).getImm();
9829
9830 // Extract sub-vector or one element
9831 if (SrcTy.isVector()) {
9832 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
9833 unsigned DstSize = DstTy.getSizeInBits();
9834
9835 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
9836 (Offset + DstSize <= SrcTy.getSizeInBits())) {
9837 // Unmerge and allow access to each Src element for the artifact combiner.
9838 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
9839
9840 // Take element(s) we need to extract and copy it (merge them).
9841 SmallVector<Register, 8> SubVectorElts;
9842 for (unsigned Idx = Offset / SrcEltSize;
9843 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
9844 SubVectorElts.push_back(Unmerge.getReg(Idx));
9845 }
9846 if (SubVectorElts.size() == 1)
9847 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
9848 else
9849 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
9850
9851 MI.eraseFromParent();
9852 return Legalized;
9853 }
9854 }
9855
9856 const DataLayout &DL = MIRBuilder.getDataLayout();
9857 if ((SrcTy.isPointer() &&
9858 DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) ||
9859 (DstTy.isPointer() &&
9860 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace()))) {
9861 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9862 return UnableToLegalize;
9863 }
9864
9865 if ((DstTy.isScalar() || DstTy.isPointer()) &&
9866 (SrcTy.isScalar() || SrcTy.isPointer() ||
9867 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
9868 LLT SrcIntTy = SrcTy;
9869 if (!SrcTy.isScalar()) {
9870 SrcIntTy = LLT::integer(SrcTy.getSizeInBits());
9871 SrcReg = MIRBuilder.buildCast(SrcIntTy, SrcReg).getReg(0);
9872 }
9873
9874 Register ResultReg = DstReg;
9875 if (DstTy.isPointer())
9876 ResultReg =
9877 MRI.createGenericVirtualRegister(LLT::integer(DstTy.getSizeInBits()));
9878
9879 if (Offset == 0)
9880 MIRBuilder.buildTrunc(ResultReg, SrcReg);
9881 else {
9882 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
9883 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
9884 MIRBuilder.buildTrunc(ResultReg, Shr);
9885 }
9886
9887 if (DstTy.isPointer())
9888 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9889
9890 MI.eraseFromParent();
9891 return Legalized;
9892 }
9893
9894 return UnableToLegalize;
9895}
9896
9898 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
9899 uint64_t Offset = MI.getOperand(3).getImm();
9900
9901 LLT DstTy = MRI.getType(Src);
9902 LLT InsertTy = MRI.getType(InsertSrc);
9903
9904 const DataLayout &DL = MIRBuilder.getDataLayout();
9905 bool IsNonIntegralInsert =
9906 InsertTy.isPointerOrPointerVector() &&
9907 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace());
9908 bool IsNonIntegralDst = DstTy.isPointerOrPointerVector() &&
9909 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace());
9910
9911 // Insert sub-vector or one element
9912 if (DstTy.isVector()) {
9913 LLT EltTy = DstTy.getElementType();
9914
9915 if ((IsNonIntegralInsert || IsNonIntegralDst) && InsertTy != EltTy) {
9916 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9917 return UnableToLegalize;
9918 }
9919
9920 unsigned EltSize = EltTy.getSizeInBits();
9921 unsigned InsertSize = InsertTy.getSizeInBits();
9922
9923 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
9924 (Offset + InsertSize <= DstTy.getSizeInBits())) {
9925 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
9927 unsigned Idx = 0;
9928 // Elements from Src before insert start Offset
9929 for (; Idx < Offset / EltSize; ++Idx) {
9930 DstElts.push_back(UnmergeSrc.getReg(Idx));
9931 }
9932
9933 // Replace elements in Src with elements from InsertSrc
9934 if (InsertTy.getSizeInBits() > EltSize) {
9935 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
9936 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
9937 ++Idx, ++i) {
9938 DstElts.push_back(UnmergeInsertSrc.getReg(i));
9939 }
9940 } else {
9941 if (InsertTy.isPointer() && !EltTy.isPointer())
9942 InsertSrc = MIRBuilder.buildPtrToInt(EltTy, InsertSrc).getReg(0);
9943 else if (!InsertTy.isPointer() && EltTy.isPointer())
9944 InsertSrc = MIRBuilder.buildIntToPtr(EltTy, InsertSrc).getReg(0);
9945 DstElts.push_back(InsertSrc);
9946 ++Idx;
9947 }
9948
9949 // Remaining elements from Src after insert
9950 for (; Idx < DstTy.getNumElements(); ++Idx) {
9951 DstElts.push_back(UnmergeSrc.getReg(Idx));
9952 }
9953
9954 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
9955 MI.eraseFromParent();
9956 return Legalized;
9957 }
9958 }
9959
9960 if (InsertTy.isVector() ||
9961 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
9962 return UnableToLegalize;
9963
9964 if (IsNonIntegralDst || IsNonIntegralInsert) {
9965 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9966 return UnableToLegalize;
9967 }
9968
9969 LLT IntDstTy = DstTy;
9970
9971 if (!DstTy.isScalar()) {
9972 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
9973 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
9974 }
9975
9976 if (!InsertTy.isScalar()) {
9977 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
9978 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
9979 }
9980
9981 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
9982 if (Offset != 0) {
9983 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
9984 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
9985 }
9986
9988 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
9989
9990 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
9991 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
9992 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
9993
9994 MIRBuilder.buildCast(Dst, Or);
9995 MI.eraseFromParent();
9996 return Legalized;
9997}
9998
10001 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
10002 MI.getFirst4RegLLTs();
10003 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
10004
10005 LLT Ty = Dst0Ty;
10006 LLT BoolTy = Dst1Ty;
10007
10008 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
10009
10010 if (IsAdd)
10011 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
10012 else
10013 MIRBuilder.buildSub(NewDst0, LHS, RHS);
10014
10015 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
10016
10017 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10018
10019 if (IsAdd) {
10020 // For an addition, the result should be less than one of the operands (LHS)
10021 // if and only if the other operand (RHS) is negative, otherwise there will
10022 // be overflow.
10023 auto ResultLowerThanLHS =
10024 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
10025 auto RHSNegative =
10026 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
10027 MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
10028 } else {
10029 // For subtraction, overflow occurs when the signed comparison of operands
10030 // doesn't match the sign of the result.
10031 auto LHSLessThanRHS =
10032 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
10033 auto ResultNegative =
10034 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
10035 MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
10036 }
10037
10038 MIRBuilder.buildCopy(Dst0, NewDst0);
10039 MI.eraseFromParent();
10040
10041 return Legalized;
10042}
10043
10045 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10046 const LLT Ty = MRI.getType(Res);
10047
10048 // sum = LHS + RHS + zext(CarryIn)
10049 auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);
10050 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10051 auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);
10052 MIRBuilder.buildCopy(Res, Sum);
10053
10054 // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 0
10055 auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);
10056 auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);
10057 auto T = MIRBuilder.buildAnd(Ty, AX, BX);
10058
10059 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10060 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10061
10062 MI.eraseFromParent();
10063 return Legalized;
10064}
10065
10067 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10068 const LLT Ty = MRI.getType(Res);
10069
10070 // Diff = LHS - (RHS + zext(CarryIn))
10071 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10072 auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
10073 auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);
10074 MIRBuilder.buildCopy(Res, Diff);
10075
10076 // ov = msb((LHS ^ RHS) & (LHS ^ Diff))
10077 auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);
10078 auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);
10079 auto T = MIRBuilder.buildAnd(Ty, X1, X2);
10080 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10081 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10082
10083 MI.eraseFromParent();
10084 return Legalized;
10085}
10086
10089 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10090 LLT Ty = MRI.getType(Res);
10091 bool IsSigned;
10092 bool IsAdd;
10093 unsigned BaseOp;
10094 switch (MI.getOpcode()) {
10095 default:
10096 llvm_unreachable("unexpected addsat/subsat opcode");
10097 case TargetOpcode::G_UADDSAT:
10098 IsSigned = false;
10099 IsAdd = true;
10100 BaseOp = TargetOpcode::G_ADD;
10101 break;
10102 case TargetOpcode::G_SADDSAT:
10103 IsSigned = true;
10104 IsAdd = true;
10105 BaseOp = TargetOpcode::G_ADD;
10106 break;
10107 case TargetOpcode::G_USUBSAT:
10108 IsSigned = false;
10109 IsAdd = false;
10110 BaseOp = TargetOpcode::G_SUB;
10111 break;
10112 case TargetOpcode::G_SSUBSAT:
10113 IsSigned = true;
10114 IsAdd = false;
10115 BaseOp = TargetOpcode::G_SUB;
10116 break;
10117 }
10118
10119 if (IsSigned) {
10120 // sadd.sat(a, b) ->
10121 // hi = 0x7fffffff - smax(a, 0)
10122 // lo = 0x80000000 - smin(a, 0)
10123 // a + smin(smax(lo, b), hi)
10124 // ssub.sat(a, b) ->
10125 // lo = smax(a, -1) - 0x7fffffff
10126 // hi = smin(a, -1) - 0x80000000
10127 // a - smin(smax(lo, b), hi)
10128 // TODO: AMDGPU can use a "median of 3" instruction here:
10129 // a +/- med3(lo, b, hi)
10130 uint64_t NumBits = Ty.getScalarSizeInBits();
10131 auto MaxVal =
10132 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
10133 auto MinVal =
10134 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10136 if (IsAdd) {
10137 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10138 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
10139 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
10140 } else {
10141 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
10142 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
10143 MaxVal);
10144 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
10145 MinVal);
10146 }
10147 auto RHSClamped =
10148 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
10149 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
10150 } else {
10151 // uadd.sat(a, b) -> a + umin(~a, b)
10152 // usub.sat(a, b) -> a - umin(a, b)
10153 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
10154 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
10155 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
10156 }
10157
10158 MI.eraseFromParent();
10159 return Legalized;
10160}
10161
10164 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10165 LLT Ty = MRI.getType(Res);
10166 LLT BoolTy = Ty.changeElementSize(1);
10167 bool IsSigned;
10168 bool IsAdd;
10169 unsigned OverflowOp;
10170 switch (MI.getOpcode()) {
10171 default:
10172 llvm_unreachable("unexpected addsat/subsat opcode");
10173 case TargetOpcode::G_UADDSAT:
10174 IsSigned = false;
10175 IsAdd = true;
10176 OverflowOp = TargetOpcode::G_UADDO;
10177 break;
10178 case TargetOpcode::G_SADDSAT:
10179 IsSigned = true;
10180 IsAdd = true;
10181 OverflowOp = TargetOpcode::G_SADDO;
10182 break;
10183 case TargetOpcode::G_USUBSAT:
10184 IsSigned = false;
10185 IsAdd = false;
10186 OverflowOp = TargetOpcode::G_USUBO;
10187 break;
10188 case TargetOpcode::G_SSUBSAT:
10189 IsSigned = true;
10190 IsAdd = false;
10191 OverflowOp = TargetOpcode::G_SSUBO;
10192 break;
10193 }
10194
10195 auto OverflowRes =
10196 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
10197 Register Tmp = OverflowRes.getReg(0);
10198 Register Ov = OverflowRes.getReg(1);
10199 MachineInstrBuilder Clamp;
10200 if (IsSigned) {
10201 // sadd.sat(a, b) ->
10202 // {tmp, ov} = saddo(a, b)
10203 // ov ? (tmp >>s 31) + 0x80000000 : r
10204 // ssub.sat(a, b) ->
10205 // {tmp, ov} = ssubo(a, b)
10206 // ov ? (tmp >>s 31) + 0x80000000 : r
10207 uint64_t NumBits = Ty.getScalarSizeInBits();
10208 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
10209 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
10210 auto MinVal =
10211 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10212 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
10213 } else {
10214 // uadd.sat(a, b) ->
10215 // {tmp, ov} = uaddo(a, b)
10216 // ov ? 0xffffffff : tmp
10217 // usub.sat(a, b) ->
10218 // {tmp, ov} = usubo(a, b)
10219 // ov ? 0 : tmp
10220 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
10221 }
10222 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
10223
10224 MI.eraseFromParent();
10225 return Legalized;
10226}
10227
10230 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
10231 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
10232 "Expected shlsat opcode!");
10233 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
10234 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10235 LLT Ty = MRI.getType(Res);
10236 LLT BoolTy = Ty.changeElementSize(1);
10237
10238 unsigned BW = Ty.getScalarSizeInBits();
10239 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
10240 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
10241 : MIRBuilder.buildLShr(Ty, Result, RHS);
10242
10243 MachineInstrBuilder SatVal;
10244 if (IsSigned) {
10245 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
10246 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
10247 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
10248 MIRBuilder.buildConstant(Ty, 0));
10249 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
10250 } else {
10251 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
10252 }
10253 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
10254 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
10255
10256 MI.eraseFromParent();
10257 return Legalized;
10258}
10259
10262 unsigned Opc = MI.getOpcode();
10263 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
10264 unsigned DstSize = DstTy.getScalarSizeInBits();
10265 unsigned SrcSize = SrcTy.getScalarSizeInBits();
10266
10267 if (Opc == TargetOpcode::G_TRUNC_SSAT_S) {
10268 auto Max = MIRBuilder.buildConstant(
10269 SrcTy, APInt::getSignedMaxValue(DstSize).sext(SrcSize));
10270 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10271 auto Min = MIRBuilder.buildConstant(
10272 SrcTy, APInt::getSignedMinValue(DstSize).sext(SrcSize));
10273 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10274 } else if (Opc == TargetOpcode::G_TRUNC_USAT_U) {
10275 auto Max = MIRBuilder.buildConstant(
10276 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10277 Src = MIRBuilder.buildUMin(SrcTy, Src, Max).getReg(0);
10278 } else if (Opc == TargetOpcode::G_TRUNC_SSAT_U) {
10279 auto Max = MIRBuilder.buildConstant(
10280 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10281 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10282 auto Min = MIRBuilder.buildConstant(SrcTy, APInt::getZero(SrcSize));
10283 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10284 } else {
10285 llvm_unreachable("Expected truncsat opcode!");
10286 }
10287
10288 MIRBuilder.buildTrunc(Dst, Src);
10289 MI.eraseFromParent();
10290 return Legalized;
10291}
10292
10294 auto [Dst, Src] = MI.getFirst2Regs();
10295 const LLT Ty = MRI.getType(Src);
10296 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
10297 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
10298
10299 // Swap most and least significant byte, set remaining bytes in Res to zero.
10300 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
10301 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
10302 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10303 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
10304
10305 // Set i-th high/low byte in Res to i-th low/high byte from Src.
10306 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
10307 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
10308 APInt APMask = APInt::getBitsSet(SizeInBytes * 8, i * 8, i * 8 + 8);
10309 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
10310 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
10311 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
10312 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
10313 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
10314 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
10315 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
10316 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10317 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
10318 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
10319 }
10320 Res.getInstr()->getOperand(0).setReg(Dst);
10321
10322 MI.eraseFromParent();
10323 return Legalized;
10324}
10325
10326//{ (Src & Mask) >> N } | { (Src << N) & Mask }
10328 MachineInstrBuilder Src, const APInt &Mask) {
10329 const LLT Ty = Dst.getLLTTy(*B.getMRI());
10330 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
10331 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
10332 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
10333 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
10334 return B.buildOr(Dst, LHS, RHS);
10335}
10336
10339 auto [Dst, Src] = MI.getFirst2Regs();
10340 const LLT SrcTy = MRI.getType(Src);
10341 unsigned Size = SrcTy.getScalarSizeInBits();
10342 unsigned VSize = SrcTy.getSizeInBits();
10343
10344 if (Size >= 8) {
10345 if (SrcTy.isVector() && (VSize % 8 == 0) &&
10346 (LI.isLegal({TargetOpcode::G_BITREVERSE,
10347 {LLT::fixed_vector(VSize / 8, LLT::integer(8)),
10348 LLT::fixed_vector(VSize / 8, LLT::integer(8))}}))) {
10349 // If bitreverse is legal for i8 vector of the same size, then cast
10350 // to i8 vector type.
10351 // e.g. v4s32 -> v16s8
10352 LLT VTy = LLT::fixed_vector(VSize / 8, LLT::integer(8));
10353 auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);
10354 auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);
10355 auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);
10356 MIRBuilder.buildBitcast(Dst, RBIT);
10357 } else {
10358 MachineInstrBuilder BSWAP =
10359 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});
10360
10361 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
10362 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
10363 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
10364 MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,
10365 APInt::getSplat(Size, APInt(8, 0xF0)));
10366
10367 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
10368 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
10369 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
10370 MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,
10371 APInt::getSplat(Size, APInt(8, 0xCC)));
10372
10373 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
10374 // 6|7
10375 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
10376 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
10377 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
10378 }
10379 } else {
10380 // Expand bitreverse for types smaller than 8 bits.
10382 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
10384 if (I < J) {
10385 auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);
10386 Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);
10387 } else {
10388 auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);
10389 Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);
10390 }
10391
10392 auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);
10393 Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);
10394 if (I == 0)
10395 Tmp = Tmp2;
10396 else
10397 Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);
10398 }
10399 MIRBuilder.buildCopy(Dst, Tmp);
10400 }
10401
10402 MI.eraseFromParent();
10403 return Legalized;
10404}
10405
10408 MachineFunction &MF = MIRBuilder.getMF();
10409
10410 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
10411 int NameOpIdx = IsRead ? 1 : 0;
10412 int ValRegIndex = IsRead ? 0 : 1;
10413
10414 Register ValReg = MI.getOperand(ValRegIndex).getReg();
10415 const LLT Ty = MRI.getType(ValReg);
10416 const MDString *RegStr = cast<MDString>(
10417 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
10418
10419 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
10420 if (!PhysReg) {
10421 const Function &Fn = MF.getFunction();
10423 "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +
10424 (IsRead ? "llvm.read_register" : "llvm.write_register"),
10425 Fn, MI.getDebugLoc()));
10426 if (IsRead)
10427 MIRBuilder.buildUndef(ValReg);
10428
10429 MI.eraseFromParent();
10430 return Legalized;
10431 }
10432
10433 if (IsRead)
10434 MIRBuilder.buildCopy(ValReg, PhysReg);
10435 else
10436 MIRBuilder.buildCopy(PhysReg, ValReg);
10437
10438 MI.eraseFromParent();
10439 return Legalized;
10440}
10441
10444 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
10445 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
10446 Register Result = MI.getOperand(0).getReg();
10447 LLT OrigTy = MRI.getType(Result);
10448 auto SizeInBits = OrigTy.getScalarSizeInBits();
10449 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
10450
10451 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
10452 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
10453 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
10454 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
10455
10456 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
10457 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
10458 MIRBuilder.buildTrunc(Result, Shifted);
10459
10460 MI.eraseFromParent();
10461 return Legalized;
10462}
10463
10466 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10467 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
10468
10469 if (Mask == fcNone) {
10470 MIRBuilder.buildConstant(DstReg, 0);
10471 MI.eraseFromParent();
10472 return Legalized;
10473 }
10474 if (Mask == fcAllFlags) {
10475 MIRBuilder.buildConstant(DstReg, 1);
10476 MI.eraseFromParent();
10477 return Legalized;
10478 }
10479
10480 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
10481 // version
10482
10483 unsigned BitSize = SrcTy.getScalarSizeInBits();
10484 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
10485
10486 LLT IntTy = SrcTy.changeElementType(LLT::integer(BitSize));
10487 auto AsInt = SrcTy == IntTy ? MIRBuilder.buildCopy(IntTy, SrcReg)
10488 : MIRBuilder.buildBitcast(IntTy, SrcReg);
10489
10490 // Various masks.
10491 APInt SignBit = APInt::getSignMask(BitSize);
10492 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
10493 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
10494 APInt ExpMask = Inf;
10495 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
10496 APInt QNaNBitMask =
10497 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
10498 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
10499
10500 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
10501 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
10502 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
10503 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
10504 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
10505
10506 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
10507 auto Sign =
10508 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
10509
10510 auto Res = MIRBuilder.buildConstant(DstTy, 0);
10511 // Clang doesn't support capture of structured bindings:
10512 LLT DstTyCopy = DstTy;
10513 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
10514 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
10515 };
10516
10517 // Tests that involve more than one class should be processed first.
10518 if ((Mask & fcFinite) == fcFinite) {
10519 // finite(V) ==> abs(V) u< exp_mask
10520 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10521 ExpMaskC));
10522 Mask &= ~fcFinite;
10523 } else if ((Mask & fcFinite) == fcPosFinite) {
10524 // finite(V) && V > 0 ==> V u< exp_mask
10525 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
10526 ExpMaskC));
10527 Mask &= ~fcPosFinite;
10528 } else if ((Mask & fcFinite) == fcNegFinite) {
10529 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
10530 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10531 ExpMaskC);
10532 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
10533 appendToRes(And);
10534 Mask &= ~fcNegFinite;
10535 }
10536
10537 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
10538 // fcZero | fcSubnormal => test all exponent bits are 0
10539 // TODO: Handle sign bit specific cases
10540 // TODO: Handle inverted case
10541 if (PartialCheck == (fcZero | fcSubnormal)) {
10542 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
10543 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10544 ExpBits, ZeroC));
10545 Mask &= ~PartialCheck;
10546 }
10547 }
10548
10549 // Check for individual classes.
10550 if (FPClassTest PartialCheck = Mask & fcZero) {
10551 if (PartialCheck == fcPosZero)
10552 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10553 AsInt, ZeroC));
10554 else if (PartialCheck == fcZero)
10555 appendToRes(
10556 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
10557 else // fcNegZero
10558 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10559 AsInt, SignBitC));
10560 }
10561
10562 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
10563 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
10564 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
10565 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
10566 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
10567 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
10568 auto SubnormalRes =
10569 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
10570 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
10571 if (PartialCheck == fcNegSubnormal)
10572 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
10573 appendToRes(SubnormalRes);
10574 }
10575
10576 if (FPClassTest PartialCheck = Mask & fcInf) {
10577 if (PartialCheck == fcPosInf)
10578 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10579 AsInt, InfC));
10580 else if (PartialCheck == fcInf)
10581 appendToRes(
10582 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
10583 else { // fcNegInf
10584 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
10585 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
10586 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10587 AsInt, NegInfC));
10588 }
10589 }
10590
10591 if (FPClassTest PartialCheck = Mask & fcNan) {
10592 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
10593 if (PartialCheck == fcNan) {
10594 // isnan(V) ==> abs(V) u> int(inf)
10595 appendToRes(
10596 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
10597 } else if (PartialCheck == fcQNan) {
10598 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
10599 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
10600 InfWithQnanBitC));
10601 } else { // fcSNan
10602 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
10603 // abs(V) u< (unsigned(Inf) | quiet_bit)
10604 auto IsNan =
10605 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
10606 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
10607 Abs, InfWithQnanBitC);
10608 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
10609 }
10610 }
10611
10612 if (FPClassTest PartialCheck = Mask & fcNormal) {
10613 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
10614 // (max_exp-1))
10615 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
10616 auto ExpMinusOne = MIRBuilder.buildSub(
10617 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
10618 APInt MaxExpMinusOne = ExpMask - ExpLSB;
10619 auto NormalRes =
10620 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
10621 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
10622 if (PartialCheck == fcNegNormal)
10623 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
10624 else if (PartialCheck == fcPosNormal) {
10625 auto PosSign = MIRBuilder.buildXor(
10626 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));
10627 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
10628 }
10629 appendToRes(NormalRes);
10630 }
10631
10632 MIRBuilder.buildCopy(DstReg, Res);
10633 MI.eraseFromParent();
10634 return Legalized;
10635}
10636
10638 // Implement G_SELECT in terms of XOR, AND, OR.
10639 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
10640 MI.getFirst4RegLLTs();
10641
10642 LLT Op1TyInt =
10643 Op1Ty.changeElementType(LLT::integer(Op1Ty.getScalarSizeInBits()));
10644
10645 bool IsEltPtr = DstTy.isPointerOrPointerVector();
10646 if (IsEltPtr) {
10647 LLT ScalarPtrTy = LLT::integer(DstTy.getScalarSizeInBits());
10648 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
10649 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
10650 Op1Ty = MRI.getType(Op1Reg);
10651 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
10652 Op2Ty = MRI.getType(Op2Reg);
10653 DstTy = NewTy;
10654 }
10655
10656 if (MaskTy.isScalar()) {
10657 // Turn the scalar condition into a vector condition mask if needed.
10658
10659 Register MaskElt = MaskReg;
10660
10661 // The condition was potentially zero extended before, but we want a sign
10662 // extended boolean.
10663 if (MaskTy != LLT::scalar(1))
10664 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
10665
10666 // Continue the sign extension (or truncate) to match the data type.
10667 MaskTy = DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10668 MaskElt =
10669 MIRBuilder.buildSExtOrTrunc(MaskTy.getScalarType(), MaskElt).getReg(0);
10670
10671 if (DstTy.isVector()) {
10672 // Generate a vector splat idiom.
10673 auto ShufSplat = MIRBuilder.buildShuffleSplat(MaskTy, MaskElt);
10674 MaskReg = ShufSplat.getReg(0);
10675 } else {
10676 MaskReg = MaskElt;
10677 }
10678 } else if (!DstTy.isVector()) {
10679 // Cannot handle the case that mask is a vector and dst is a scalar.
10680 return UnableToLegalize;
10681 }
10682
10683 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
10684 return UnableToLegalize;
10685 }
10686
10687 if (!Op1Ty.getScalarType().isAnyScalar() &&
10688 !Op1Ty.getScalarType().isInteger())
10689 Op1Reg = MIRBuilder.buildBitcast(Op1TyInt, Op1Reg).getReg(0);
10690
10691 if (!Op2Ty.getScalarType().isAnyScalar() &&
10692 !Op2Ty.getScalarType().isInteger()) {
10693 auto Op2TyInt =
10694 Op2Ty.changeElementType(LLT::integer(Op2Ty.getScalarSizeInBits()));
10695 Op2Reg = MIRBuilder.buildBitcast(Op2TyInt, Op2Reg).getReg(0);
10696 }
10697
10698 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
10699 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
10700 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
10701 if (IsEltPtr) {
10702 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
10703 MIRBuilder.buildIntToPtr(DstReg, Or);
10704 } else {
10705 if (DstTy == Op1TyInt)
10706 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
10707 else {
10708 auto Or = MIRBuilder.buildOr(Op1TyInt, NewOp1, NewOp2);
10709 MIRBuilder.buildBitcast(DstReg, Or.getReg(0));
10710 }
10711 }
10712 MI.eraseFromParent();
10713 return Legalized;
10714}
10715
10717 // Split DIVREM into individual instructions.
10718 unsigned Opcode = MI.getOpcode();
10719
10720 MIRBuilder.buildInstr(
10721 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
10722 : TargetOpcode::G_UDIV,
10723 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10724 MIRBuilder.buildInstr(
10725 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
10726 : TargetOpcode::G_UREM,
10727 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10728 MI.eraseFromParent();
10729 return Legalized;
10730}
10731
10734 // Expand %res = G_ABS %a into:
10735 // %v1 = G_ASHR %a, scalar_size-1
10736 // %v2 = G_ADD %a, %v1
10737 // %res = G_XOR %v2, %v1
10738 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
10739 Register OpReg = MI.getOperand(1).getReg();
10740 auto ShiftAmt =
10741 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
10742 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
10743 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
10744 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
10745 MI.eraseFromParent();
10746 return Legalized;
10747}
10748
10751 // Expand %res = G_ABS %a into:
10752 // %v1 = G_CONSTANT 0
10753 // %v2 = G_SUB %v1, %a
10754 // %res = G_SMAX %a, %v2
10755 Register SrcReg = MI.getOperand(1).getReg();
10756 LLT Ty = MRI.getType(SrcReg);
10757 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10758 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
10759 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
10760 MI.eraseFromParent();
10761 return Legalized;
10762}
10763
10766 Register SrcReg = MI.getOperand(1).getReg();
10767 Register DestReg = MI.getOperand(0).getReg();
10768 LLT Ty = MRI.getType(SrcReg), IType = LLT::integer(1);
10769 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
10770 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
10771 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
10772 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
10773 MI.eraseFromParent();
10774 return Legalized;
10775}
10776
10779 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10780 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10781 "Expected G_ABDS or G_ABDU instruction");
10782
10783 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10784 LLT Ty = MRI.getType(LHS);
10785
10786 // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10787 // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10788 Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);
10789 Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);
10790 CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)
10793 auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);
10794 MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);
10795
10796 MI.eraseFromParent();
10797 return Legalized;
10798}
10799
10802 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10803 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10804 "Expected G_ABDS or G_ABDU instruction");
10805
10806 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10807 LLT Ty = MRI.getType(LHS);
10808
10809 // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))
10810 // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))
10811 Register MaxReg, MinReg;
10812 if (MI.getOpcode() == TargetOpcode::G_ABDS) {
10813 MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);
10814 MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);
10815 } else {
10816 MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);
10817 MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);
10818 }
10819 MIRBuilder.buildSub(DstReg, MaxReg, MinReg);
10820
10821 MI.eraseFromParent();
10822 return Legalized;
10823}
10824
10826 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10827 LLT TyInt =
10828 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10829 Register CastedSrc = SrcReg;
10830
10831 if (!(SrcTy.getScalarType().isAnyScalar() ||
10832 SrcTy.getScalarType().isInteger())) {
10833 auto SrcTyInt =
10834 SrcTy.changeElementType(LLT::integer(SrcTy.getScalarSizeInBits()));
10835 CastedSrc = MIRBuilder.buildBitcast(SrcTyInt, SrcReg).getReg(0);
10836 }
10837
10838 if (MRI.getType(DstReg) != TyInt) {
10839 // Reset sign bit
10840 Register NewDst =
10842 .buildAnd(TyInt, CastedSrc,
10843 MIRBuilder.buildConstant(
10845 DstTy.getScalarSizeInBits())))
10846 .getReg(0);
10847
10848 MIRBuilder.buildBitcast(DstReg, NewDst);
10849 } else
10851 .buildAnd(
10852 DstReg, CastedSrc,
10853 MIRBuilder.buildConstant(
10854 TyInt, APInt::getSignedMaxValue(DstTy.getScalarSizeInBits())))
10855 .getReg(0);
10856
10857 MI.eraseFromParent();
10858 return Legalized;
10859}
10860
10863 Register SrcReg = MI.getOperand(1).getReg();
10864 LLT SrcTy = MRI.getType(SrcReg);
10865 LLT DstTy = MRI.getType(SrcReg);
10866
10867 // The source could be a scalar if the IR type was <1 x sN>.
10868 if (SrcTy.isScalar()) {
10869 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
10870 return UnableToLegalize; // FIXME: handle extension.
10871 // This can be just a plain copy.
10872 Observer.changingInstr(MI);
10873 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
10874 Observer.changedInstr(MI);
10875 return Legalized;
10876 }
10877 return UnableToLegalize;
10878}
10879
10881 MachineFunction &MF = *MI.getMF();
10882 const DataLayout &DL = MIRBuilder.getDataLayout();
10883 LLVMContext &Ctx = MF.getFunction().getContext();
10884 Register ListPtr = MI.getOperand(1).getReg();
10885 LLT PtrTy = MRI.getType(ListPtr);
10886
10887 // LstPtr is a pointer to the head of the list. Get the address
10888 // of the head of the list.
10889 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
10890 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
10891 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
10892 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
10893
10894 const Align A(MI.getOperand(2).getImm());
10895 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
10896 if (A > TLI.getMinStackArgumentAlignment()) {
10897 Register AlignAmt =
10898 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
10899 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
10900 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
10901 VAList = AndDst.getReg(0);
10902 }
10903
10904 // Increment the pointer, VAList, to the next vaarg
10905 // The list should be bumped by the size of element in the current head of
10906 // list.
10907 Register Dst = MI.getOperand(0).getReg();
10908 LLT LLTTy = MRI.getType(Dst);
10909 Type *Ty = getTypeForLLT(LLTTy, Ctx);
10910 auto IncAmt =
10911 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
10912 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
10913
10914 // Store the increment VAList to the legalized pointer
10916 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
10917 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
10918 // Load the actual argument out of the pointer VAList
10919 Align EltAlignment = DL.getABITypeAlign(Ty);
10920 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
10921 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
10922 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
10923
10924 MI.eraseFromParent();
10925 return Legalized;
10926}
10927
10929 unsigned OpCode = MI.getOpcode();
10930 assert((OpCode == TargetOpcode::G_SMULFIX ||
10931 OpCode == TargetOpcode::G_UMULFIX ||
10932 OpCode == TargetOpcode::G_SMULFIXSAT ||
10933 OpCode == TargetOpcode::G_UMULFIXSAT) &&
10934 "Operator must be either G_SMULFIX[SAT] or G_UMULFIX[SAT]!");
10935 auto [Dst, LHS, RHS] = MI.getFirst3Regs();
10936 LLT Ty = MRI.getType(Dst);
10937 unsigned Scale = MI.getOperand(3).getImm();
10938
10939 bool Saturating = (OpCode == TargetOpcode::G_SMULFIXSAT ||
10940 OpCode == TargetOpcode::G_UMULFIXSAT);
10941 bool IsSigned = (OpCode == TargetOpcode::G_SMULFIX ||
10942 OpCode == TargetOpcode::G_SMULFIXSAT);
10943
10944 if (!Saturating && Scale == 0) {
10945 MIRBuilder.buildMul(Dst, LHS, RHS);
10946 MI.eraseFromParent();
10947 return Legalized;
10948 }
10949
10950 // TODO: Port other lowering paths from SelectionDAG.
10951 LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
10952 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
10953 MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
10954 if (IsSigned) {
10955 ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
10956 ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
10957 } else {
10958 ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
10959 ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
10960 }
10961
10962 auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
10963 if (IsSigned)
10964 Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
10965 else
10966 Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
10967
10968 if (!Saturating)
10969 MIRBuilder.buildTrunc(Dst, Shift);
10970 else if (IsSigned)
10971 MIRBuilder.buildTruncSSatS(Dst, Shift);
10972 else
10973 MIRBuilder.buildTruncUSatU(Dst, Shift);
10974
10975 MI.eraseFromParent();
10976 return Legalized;
10977}
10978
10979// Get a vectorized representation of the memset value operand, GISel edition.
10981 MachineRegisterInfo &MRI = *MIB.getMRI();
10982 unsigned NumBits = Ty.getScalarSizeInBits();
10983 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
10984 if (!Ty.isVector() && ValVRegAndVal) {
10985 APInt Scalar = ValVRegAndVal->Value.trunc(8);
10986 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
10987 return MIB.buildConstant(Ty, SplatVal).getReg(0);
10988 }
10989
10990 // Extend the byte value to the larger type, and then multiply by a magic
10991 // value 0x010101... in order to replicate it across every byte.
10992 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
10993 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
10994 return MIB.buildConstant(Ty, 0).getReg(0);
10995 }
10996
10997 LLT ExtType = Ty.getScalarType();
10998 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
10999 if (NumBits > 8) {
11000 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
11001 auto MagicMI = MIB.buildConstant(ExtType, Magic);
11002 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
11003 }
11004
11005 // For vector types create a G_BUILD_VECTOR.
11006 if (Ty.isVector())
11007 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
11008
11009 return Val;
11010}
11011
11013LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
11014 uint64_t KnownLen, Align Alignment,
11015 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11016 auto &MF = *MI.getParent()->getParent();
11017 const auto &TLI = *MF.getSubtarget().getTargetLowering();
11018 auto &DL = MF.getDataLayout();
11019 LLVMContext &C = MF.getFunction().getContext();
11020
11021 assert(KnownLen != 0 && "Have a zero length memset length!");
11022 assert(!MemOps.empty() && "Expected at least one memory op");
11023
11024 MachineFrameInfo &MFI = MF.getFrameInfo();
11025 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11026 const auto &DstMMO = **MI.memoperands_begin();
11027
11028 if (DstAlignCanChange) {
11029 // Get an estimate of the type from the LLT.
11030 Type *IRTy = getTypeForLLT(MemOps[0], C);
11031 Align NewAlign = DL.getABITypeAlign(IRTy);
11032 if (NewAlign > Alignment) {
11033 Alignment = NewAlign;
11034 unsigned FI = FIDef->getOperand(1).getIndex();
11035 // Give the stack frame object a larger alignment if needed.
11036 if (MFI.getObjectAlign(FI) < Alignment)
11037 MFI.setObjectAlignment(FI, Alignment);
11038 }
11039 }
11040
11041 MachineIRBuilder MIB(MI);
11042 // Find the largest store and generate the bit pattern for it.
11043 LLT LargestTy = MemOps[0];
11044 for (unsigned i = 1; i < MemOps.size(); i++)
11045 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
11046 LargestTy = MemOps[i];
11047
11048 // The memset stored value is always defined as an s8, so in order to make it
11049 // work with larger store types we need to repeat the bit pattern across the
11050 // wider type.
11051 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
11052
11053 if (!MemSetValue)
11054 return UnableToLegalize;
11055
11056 // Generate the stores. For each store type in the list, we generate the
11057 // matching store of that type to the destination address.
11058 LLT PtrTy = MRI.getType(Dst);
11059 unsigned DstOff = 0;
11060 unsigned Size = KnownLen;
11061 for (unsigned I = 0; I < MemOps.size(); I++) {
11062 LLT Ty = MemOps[I];
11063 unsigned TySize = Ty.getSizeInBytes();
11064
11065 if (TySize > Size) {
11066 // Issuing a load / store pair that overlaps with the previous pair.
11067 // Adjust the offset accordingly.
11068 assert(I == MemOps.size() - 1 && I != 0);
11069 DstOff -= TySize - Size;
11070 }
11071
11072 // If this store is smaller than the largest store see whether we can get
11073 // the smaller value for free with a truncate.
11074 Register Value = MemSetValue;
11075 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
11076 MVT VT = getMVTForLLT(Ty);
11077 MVT LargestVT = getMVTForLLT(LargestTy);
11078 if (!LargestTy.isVector() && !Ty.isVector() &&
11079 TLI.isTruncateFree(LargestVT, VT))
11080 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
11081 else
11082 Value = getMemsetValue(Val, Ty, MIB);
11083 if (!Value)
11084 return UnableToLegalize;
11085 }
11086
11087 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
11088
11089 Register Ptr = Dst;
11090 if (DstOff != 0) {
11091 auto Offset =
11092 MIB.buildConstant(LLT::integer(PtrTy.getSizeInBits()), DstOff);
11093 Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);
11094 }
11095
11096 MIB.buildStore(Value, Ptr, *StoreMMO);
11097 DstOff += Ty.getSizeInBytes();
11098 Size -= TySize;
11099 }
11100
11101 MI.eraseFromParent();
11102 return Legalized;
11103}
11104
11106LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
11107 uint64_t KnownLen, Align Alignment,
11108 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11109 auto &MF = *MI.getParent()->getParent();
11110 auto &DL = MF.getDataLayout();
11111 LLVMContext &C = MF.getFunction().getContext();
11112
11113 assert(KnownLen != 0 && "Have a zero length memcpy length!");
11114 assert(!MemOps.empty() && "Expected at least one memory op");
11115
11116 MachineFrameInfo &MFI = MF.getFrameInfo();
11117 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11118
11119 // FIXME: infer better src pointer alignment like SelectionDAG does here.
11120 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
11121 // if the memcpy is in a tail call position.
11122
11123 const auto &DstMMO = **MI.memoperands_begin();
11124 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11125
11126 if (DstAlignCanChange) {
11127 // Get an estimate of the type from the LLT.
11128 Type *IRTy = getTypeForLLT(MemOps[0], C);
11129 Align NewAlign = DL.getABITypeAlign(IRTy);
11130
11131 // Don't promote to an alignment that would require dynamic stack
11132 // realignment.
11133 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11134 if (!TRI->hasStackRealignment(MF))
11135 if (MaybeAlign StackAlign = DL.getStackAlignment())
11136 NewAlign = std::min(NewAlign, *StackAlign);
11137
11138 if (NewAlign > Alignment) {
11139 Alignment = NewAlign;
11140 unsigned FI = FIDef->getOperand(1).getIndex();
11141 // Give the stack frame object a larger alignment if needed.
11142 if (MFI.getObjectAlign(FI) < Alignment)
11143 MFI.setObjectAlignment(FI, Alignment);
11144 }
11145 }
11146
11147 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
11148
11149 MachineIRBuilder MIB(MI);
11150 // Now we need to emit a pair of load and stores for each of the types we've
11151 // collected. I.e. for each type, generate a load from the source pointer of
11152 // that type width, and then generate a corresponding store to the dest buffer
11153 // of that value loaded. This can result in a sequence of loads and stores
11154 // mixed types, depending on what the target specifies as good types to use.
11155 unsigned CurrOffset = 0;
11156 unsigned Size = KnownLen;
11157 for (auto CopyTy : MemOps) {
11158 TypeSize TySize = CopyTy.getSizeInBytes();
11159
11160 // Issuing a load / store pair that overlaps with the previous pair. Adjust
11161 // the offset accordingly.
11162 if (TySize > Size) {
11163 unsigned Overlap = TySize - Size;
11164 assert(Overlap < CurrOffset &&
11165 "overlapping memcpy load/store spans the whole region or more");
11166 CurrOffset -= Overlap;
11167 }
11168
11169 // Construct MMOs for the accesses.
11170 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11171 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11172
11173 // Create the load.
11174 Register LoadPtr = Src;
11176 if (CurrOffset != 0) {
11177 LLT SrcTy = MRI.getType(Src);
11178 Offset =
11179 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset)
11180 .getReg(0);
11181 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11182 }
11183 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
11184
11185 // Create the store.
11186 Register StorePtr = Dst;
11187 if (CurrOffset != 0) {
11188 LLT DstTy = MRI.getType(Dst);
11189 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11190 }
11191 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
11192 CurrOffset += TySize;
11193 Size -= TySize;
11194 }
11195
11196 MI.eraseFromParent();
11197 return Legalized;
11198}
11199
11201LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
11202 uint64_t KnownLen, Align Alignment,
11203 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11204 auto &MF = *MI.getParent()->getParent();
11205 auto &DL = MF.getDataLayout();
11206 LLVMContext &C = MF.getFunction().getContext();
11207
11208 assert(KnownLen != 0 && "Have a zero length memmove length!");
11209 assert(!MemOps.empty() && "Expected at least one memory op");
11210
11211 MachineFrameInfo &MFI = MF.getFrameInfo();
11212 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11213 const auto &DstMMO = **MI.memoperands_begin();
11214 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11215
11216 if (DstAlignCanChange) {
11217 // Get an estimate of the type from the LLT.
11218 Type *IRTy = getTypeForLLT(MemOps[0], C);
11219 Align NewAlign = DL.getABITypeAlign(IRTy);
11220
11221 // Don't promote to an alignment that would require dynamic stack
11222 // realignment.
11223 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11224 if (!TRI->hasStackRealignment(MF))
11225 if (MaybeAlign StackAlign = DL.getStackAlignment())
11226 NewAlign = std::min(NewAlign, *StackAlign);
11227
11228 if (NewAlign > Alignment) {
11229 Alignment = NewAlign;
11230 unsigned FI = FIDef->getOperand(1).getIndex();
11231 // Give the stack frame object a larger alignment if needed.
11232 if (MFI.getObjectAlign(FI) < Alignment)
11233 MFI.setObjectAlignment(FI, Alignment);
11234 }
11235 }
11236
11237 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
11238
11239 MachineIRBuilder MIB(MI);
11240 // Memmove requires that we perform the loads first before issuing the stores.
11241 // Apart from that, this loop is pretty much doing the same thing as the
11242 // memcpy codegen function.
11243 unsigned CurrOffset = 0;
11244 unsigned Size = KnownLen;
11245 SmallVector<Register, 16> LoadVals;
11246 for (auto CopyTy : MemOps) {
11247 TypeSize TySize = CopyTy.getSizeInBytes();
11248
11249 // Issuing a load that overlaps with the previous load. Adjust the offset
11250 // accordingly.
11251 if (TySize > Size) {
11252 unsigned Overlap = TySize - Size;
11253 assert(Overlap < CurrOffset &&
11254 "overlapping memmove load spans the whole region or more");
11255 CurrOffset -= Overlap;
11256 }
11257
11258 // Construct MMO for the load.
11259 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11260
11261 // Create the load.
11262 Register LoadPtr = Src;
11263 if (CurrOffset != 0) {
11264 LLT SrcTy = MRI.getType(Src);
11265 auto Offset =
11266 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset);
11267 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11268 }
11269 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
11270 CurrOffset += TySize;
11271 Size -= TySize;
11272 }
11273
11274 CurrOffset = 0;
11275 Size = KnownLen;
11276 for (unsigned I = 0; I < MemOps.size(); ++I) {
11277 LLT CopyTy = MemOps[I];
11278 TypeSize TySize = CopyTy.getSizeInBytes();
11279
11280 // Issuing a store that overlaps with the previous store. Adjust the offset
11281 // accordingly.
11282 if (TySize > Size) {
11283 unsigned Overlap = TySize - Size;
11284 assert(Overlap < CurrOffset &&
11285 "overlapping memmove store spans the whole region or more");
11286 CurrOffset -= Overlap;
11287 }
11288
11289 // Now store the values loaded.
11290 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11291
11292 Register StorePtr = Dst;
11293 if (CurrOffset != 0) {
11294 LLT DstTy = MRI.getType(Dst);
11295 auto Offset =
11296 MIB.buildConstant(LLT::integer(DstTy.getSizeInBits()), CurrOffset);
11297 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11298 }
11299 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
11300 CurrOffset += TySize;
11301 Size -= TySize;
11302 }
11303 MI.eraseFromParent();
11304 return Legalized;
11305}
11306
11308 MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen,
11309 Align Alignment, bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11310 const unsigned Opc = MI.getOpcode();
11311 assert((Opc == TargetOpcode::G_MEMCPY ||
11312 Opc == TargetOpcode::G_MEMCPY_INLINE ||
11313 Opc == TargetOpcode::G_MEMMOVE || Opc == TargetOpcode::G_MEMSET ||
11314 Opc == TargetOpcode::G_MEMSET_INLINE) &&
11315 "Expected memcpy like instruction");
11316
11317 if (KnownLen == 0) {
11318 MI.eraseFromParent();
11319 return Legalized;
11320 }
11321
11322 if (Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMCPY_INLINE) {
11323 return lowerMemcpy(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11324 MemOps);
11325 }
11326 if (Opc == TargetOpcode::G_MEMMOVE)
11327 return lowerMemmove(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11328 MemOps);
11329 if (Opc == TargetOpcode::G_MEMSET || Opc == TargetOpcode::G_MEMSET_INLINE)
11330 return lowerMemset(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11331 MemOps);
11332 return UnableToLegalize;
11333}
11334
11337 Register Dst, Src;
11338 uint64_t KnownLen;
11339 Align Alignment;
11340 bool DstAlignCanChange;
11341 std::vector<LLT> MemOps;
11342 if (!canLowerMemCpyFamily(MI, MRI, MaxLen, Dst, Src, KnownLen, Alignment,
11343 DstAlignCanChange, MemOps))
11344 return UnableToLegalize;
11345 return lowerMemCpyFamily(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11346 MemOps);
11347}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned Imm
unsigned uint64_t
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:857
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file describes how to lower LLVM calls to machine code calls.
#define GISEL_VECREDUCE_CASES_NONSEQ
Definition Utils.h:79
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred)
#define RTLIBCASE_INT(LibcallPrefix)
static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI)
static Register buildBitFieldInsert(MachineIRBuilder &B, Register TargetReg, Register InsertReg, Register OffsetBits)
Emit code to insert InsertReg into TargetRet at OffsetBits in TargetReg, while preserving other bits ...
static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB)
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size)
static std::pair< RTLIB::Libcall, CmpInst::Predicate > getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size)
Returns the corresponding libcall for the given Pred and the ICMP predicate that should be generated ...
static void broadcastSrcOp(SmallVectorImpl< SrcOp > &Ops, unsigned N, MachineOperand &Op)
Operand Op is used on N sub-instructions.
static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result, MachineInstr &MI, const TargetInstrInfo &TII, MachineRegisterInfo &MRI)
True if an instruction is in tail position in its caller.
static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B, Register Idx, unsigned NewEltSize, unsigned OldEltSize)
Figure out the bit offset into a register when coercing a vector index for the wide element type.
static void makeDstOps(SmallVectorImpl< DstOp > &DstOps, LLT Ty, unsigned NumElts)
Fill DstOps with DstOps that have same number of elements combined as the Ty.
#define LCALL5(A)
static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B, MachineInstrBuilder Src, const APInt &Mask)
static bool hasSwiftErrorArg(MachineFunction &MF)
static LegalizerHelper::LegalizeResult loweri64tof16ITOFP(MachineInstr &MI, Register Dst, LLT DstTy, Register Src, LLT SrcTy, MachineIRBuilder &MIRBuilder)
i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16.
static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal, MachineIRBuilder &MIRBuilder)
static void getUnmergePieces(SmallVectorImpl< Register > &Pieces, MachineIRBuilder &B, Register Src, LLT Ty)
static CmpInst::Predicate minMaxToCompare(unsigned Opc)
static RTLIB::Libcall getStateLibraryFunctionFor(MachineInstr &MI, const TargetLowering &TLI)
static std::pair< int, int > getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy)
Try to break down OrigTy into NarrowTy sized pieces.
static bool hasSameNumEltsOnAllVectorOperands(GenericMachineInstr &MI, MachineRegisterInfo &MRI, std::initializer_list< unsigned > NonVecOpIndices)
Check that all vector operands have same number of elements.
static Register clampVectorIndex(MachineIRBuilder &B, Register IdxReg, LLT VecTy)
static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType, Type *FromType)
static void getUnmergeResults(SmallVectorImpl< Register > &Regs, const MachineInstr &MI)
Append the result registers of G_UNMERGE_VALUES MI to Regs.
static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo &MRI, Register Reg, unsigned BW)
#define RTLIBCASE(LibcallPrefix)
static Type * getFloatTypeForLLT(LLVMContext &Ctx, LLT Ty)
Interface for Targets to specify which operations they can successfully select and how the others sho...
Tracks DebugLocs between checkpoints and verifies that they are transferred.
Implement a low-level type suitable for MachineInstr level instruction selection.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
This file declares the MachineIRBuilder class.
Register Reg
Register const TargetRegisterInfo * TRI
#define R2(n)
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define T
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
uint64_t High
R600 Clause Merge
static constexpr MCPhysReg SPReg
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:365
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:377
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
Definition APFloat.h:1451
APInt bitcastToAPInt() const
Definition APFloat.h:1475
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1242
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1202
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
Definition APFloat.h:1213
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:231
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1056
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:226
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1561
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1533
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:969
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
Definition APInt.h:203
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
Definition APInt.h:1187
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
Definition APInt.h:255
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:377
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1693
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:206
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
Definition APInt.h:213
void negate()
Negate this APInt in place.
Definition APInt.h:1489
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:647
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:216
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1029
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:876
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:303
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:197
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:236
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:854
static APInt getBitsSetWithWrap(unsigned numBits, unsigned loBit, unsigned hiBit)
Wrap version of getBitsSet.
Definition APInt.h:267
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
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:329
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:356
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 isFloat() const
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr bool isScalable() const
Returns true if the LLT is a scalable vector.
constexpr bool isByteSized() const
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 lowerFCopySign(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastConcatVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerRotateWithReverseRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSADDE(MachineInstr &MI)
LLVM_ABI LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
LLVM_ABI LegalizeResult lowerFunnelShift(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize a vector instruction by splitting into multiple components, each acting on the same scalar t...
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
LLVM_ABI LegalizeResult conversionLibcall(MachineInstr &MI, Type *ToType, Type *FromType, LostDebugLocObserver &LocObserver, bool IsSigned=false) const
LLVM_ABI void bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a def by inserting a G_BITCAST from ...
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMad(MachineInstr &MI)
LLVM_ABI LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy)
Legalize an instruction by performing the operation on a wider scalar type (for example a 16-bit addi...
LLVM_ABI LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerFFloor(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExt(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult fewerElementsVectorSeqReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Register getDynStackAllocTargetPtr(Register SPReg, Register AllocSize, Align Alignment, LLT PtrTy)
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerUITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerShuffleVector(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerMergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult createMemLibcall(MachineRegisterInfo &MRI, MachineInstr &MI, LostDebugLocObserver &LocObserver) const
Create a libcall to memcpy et al.
LLVM_ABI LegalizeResult lowerVECTOR_COMPRESS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI)
LLVM_ABI void moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by producing a vector with und...
LLVM_ABI LegalizeResult bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_EXTRACT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF32WithSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult createLibcall(const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr) const
Helper function that creates a libcall to the given Name using the given calling convention CC.
LLVM_ABI LegalizeResult bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerDIVREM(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI Register buildVariableShiftPart(unsigned Opcode, Register MainOperand, Register ShiftAmt, LLT TargetTy, Register CarryOperand=Register())
Generates a shift part with carry for variable shifts.
LLVM_ABI void bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a use by inserting a G_BITCAST to Ca...
LLVM_ABI void narrowScalarDst(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx, unsigned ExtOpcode)
LLVM_ABI LegalizeResult libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Legalize an instruction by emiting a runtime library call instead.
LLVM_ABI LegalizeResult lowerStackRestore(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerTruncSat(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStackSave(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI void widenScalarDstUsingFPTrunc(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBswap(MachineInstr &MI)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
LLVM_ABI LegalizeResult narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LLVM_ABI Register coerceToInteger(Register Val)
Cast the given value to an LLT::integer with an equivalent size.
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LLVM_ABI LegalizeResult simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType, LostDebugLocObserver &LocObserver) const
LLVM_ABI LegalizeResult legalizeInstrStep(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Replace MI by a sequence of legal instructions that can implement the same operation.
LLVM_ABI LegalizeResult lowerFMinimumMaximum(MachineInstr &MI)
Tracks which library functions to use for a particular subtarget or function.
TypeSize getValue() const
void checkpoint(bool CheckDebugLocs=true)
Call this to indicate that it's a good point to assess whether locations have been lost.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:89
A single uniqued string.
Definition Metadata.h: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.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)
Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_UITOFP Src0.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildFPTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FPTRUNC Op.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
void setType(LLT NewTy)
Reset the tracked memory type.
LLT getMemoryType() const
Return the memory type of the memory reference.
void clearRanges()
Unset the tracked range metadata.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const MachinePointerInfo & getPointerInfo() const
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
const ConstantInt * getCImm() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setCImm(const ConstantInt *CI)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
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 bool supportSwiftError() const
Return true if the target supports swifterror attribute.
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 bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition TypeSize.h:180
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)
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOUINT(EVT OpVT, EVT RetVT)
getFPTOUINT - Return the FPTOUINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPEXT(EVT OpVT, EVT RetVT)
getFPEXT - Return the FPEXT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h: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:577
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h: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:380
LLVM_ABI LLVM_READNONE LLT getLCMType(LLT OrigTy, LLT TargetTy)
Return the least common multiple type of OrigTy and TargetTy, by changing the number of vector elemen...
Definition Utils.cpp: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:352
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h: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:368
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
SmallVector< ISD::ArgFlagsTy, 4 > Flags
CallingConv::ID CallConv
Calling convention to be used for the call.
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.