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