LLVM 24.0.0git
LegalizerHelper.cpp
Go to the documentation of this file.
1//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This file implements the LegalizerHelper class to legalize
10/// individual instructions and the LegalizeMachineIR wrapper pass for the
11/// primary legalization.
12//
13//===----------------------------------------------------------------------===//
14
36#include "llvm/Support/Debug.h"
40#include <cassert>
41#include <numeric>
42#include <optional>
43
44#define DEBUG_TYPE "legalizer"
45
46using namespace llvm;
47using namespace LegalizeActions;
48using namespace MIPatternMatch;
49
50/// Try to break down \p OrigTy into \p NarrowTy sized pieces.
51///
52/// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
53/// with any leftover piece as type \p LeftoverTy
54///
55/// Returns -1 in the first element of the pair if the breakdown is not
56/// satisfiable.
57static std::pair<int, int>
58getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
59 assert(!LeftoverTy.isValid() && "this is an out argument");
60
61 unsigned Size = OrigTy.getSizeInBits();
62 unsigned NarrowSize = NarrowTy.getSizeInBits();
63 unsigned NumParts = Size / NarrowSize;
64 unsigned LeftoverSize = Size - NumParts * NarrowSize;
65 assert(Size > NarrowSize);
66
67 if (LeftoverSize == 0)
68 return {NumParts, 0};
69
70 if (NarrowTy.isVector()) {
71 unsigned EltSize = OrigTy.getScalarSizeInBits();
72 if (LeftoverSize % EltSize != 0)
73 return {-1, -1};
74 LeftoverTy = OrigTy.changeElementCount(
75 ElementCount::getFixed(LeftoverSize / EltSize));
76 } else {
77 LeftoverTy = LLT::integer(LeftoverSize);
78 }
79
80 int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
81 return std::make_pair(NumParts, NumLeftover);
82}
83
85
86 if (!Ty.isScalar())
87 return nullptr;
88
89 switch (Ty.getSizeInBits()) {
90 case 16:
91 return Type::getHalfTy(Ctx);
92 case 32:
93 return Type::getFloatTy(Ctx);
94 case 64:
95 return Type::getDoubleTy(Ctx);
96 case 80:
97 return Type::getX86_FP80Ty(Ctx);
98 case 128:
99 return Type::getFP128Ty(Ctx);
100 default:
101 return nullptr;
102 }
103}
104
107 MachineIRBuilder &Builder,
108 const LibcallLoweringInfo *Libcalls)
109 : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
110 LI(*MF.getSubtarget().getLegalizerInfo()),
111 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls) {}
112
116 const LibcallLoweringInfo *Libcalls,
118 : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
119 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls), VT(VT) {}
120
123 LostDebugLocObserver &LocObserver) {
124 LLVM_DEBUG(dbgs() << "\nLegalizing: " << MI);
125
126 MIRBuilder.setInstrAndDebugLoc(MI);
127
128 if (isa<GIntrinsic>(MI))
129 return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
130 auto Step = LI.getAction(MI, MRI);
131 switch (Step.Action) {
132 case Legal:
133 LLVM_DEBUG(dbgs() << ".. Already legal\n");
134 return AlreadyLegal;
135 case Libcall:
136 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
137 return libcall(MI, LocObserver);
138 case NarrowScalar:
139 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
140 return narrowScalar(MI, Step.TypeIdx, Step.NewType);
141 case WidenScalar:
142 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
143 return widenScalar(MI, Step.TypeIdx, Step.NewType);
144 case Bitcast:
145 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
146 return bitcast(MI, Step.TypeIdx, Step.NewType);
147 case Lower:
148 LLVM_DEBUG(dbgs() << ".. Lower\n");
149 return lower(MI, Step.TypeIdx, Step.NewType);
150 case FewerElements:
151 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
152 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
153 case MoreElements:
154 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
155 return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
156 case Custom:
157 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
158 return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
160 default:
161 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
162 return UnableToLegalize;
163 }
164}
165
166void LegalizerHelper::insertParts(Register DstReg,
167 LLT ResultTy, LLT PartTy,
168 ArrayRef<Register> PartRegs,
169 LLT LeftoverTy,
170 ArrayRef<Register> LeftoverRegs) {
171 if (!LeftoverTy.isValid()) {
172 assert(LeftoverRegs.empty());
173
174 if (!ResultTy.isVector()) {
175 MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
176 return;
177 }
178
179 if (PartTy.isVector())
180 MIRBuilder.buildConcatVectors(DstReg, PartRegs);
181 else
182 MIRBuilder.buildBuildVector(DstReg, PartRegs);
183 return;
184 }
185
186 // Merge sub-vectors with different number of elements and insert into DstReg.
187 if (ResultTy.isVector()) {
188 assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
189 SmallVector<Register, 8> AllRegs(PartRegs);
190 AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());
191 return mergeMixedSubvectors(DstReg, AllRegs);
192 }
193
194 SmallVector<Register> GCDRegs;
195 LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
196 for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
197 extractGCDType(GCDRegs, GCDTy, PartReg);
198 LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
199 buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
200}
201
202void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
203 Register Reg) {
204 LLT Ty = MRI.getType(Reg);
206 extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
207 MIRBuilder, MRI);
208 Elts.append(RegElts);
209}
210
211/// Merge \p PartRegs with different types into \p DstReg.
212void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
213 ArrayRef<Register> PartRegs) {
215 for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
216 appendVectorElts(AllElts, PartRegs[i]);
217
218 Register Leftover = PartRegs[PartRegs.size() - 1];
219 if (!MRI.getType(Leftover).isVector())
220 AllElts.push_back(Leftover);
221 else
222 appendVectorElts(AllElts, Leftover);
223
224 MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
225}
226
227/// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
229 const MachineInstr &MI) {
230 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
231
232 const int StartIdx = Regs.size();
233 const int NumResults = MI.getNumOperands() - 1;
234 Regs.resize(Regs.size() + NumResults);
235 for (int I = 0; I != NumResults; ++I)
236 Regs[StartIdx + I] = MI.getOperand(I).getReg();
237}
238
239void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
240 LLT GCDTy, Register SrcReg) {
241 LLT SrcTy = MRI.getType(SrcReg);
242 if (SrcTy == GCDTy) {
243 // If the source already evenly divides the result type, we don't need to do
244 // anything.
245 Parts.push_back(SrcReg);
246 } else {
247 // Need to split into common type sized pieces.
248 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
249 getUnmergeResults(Parts, *Unmerge);
250 }
251}
252
253LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
254 LLT NarrowTy, Register SrcReg) {
255 LLT SrcTy = MRI.getType(SrcReg);
256 LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
257 extractGCDType(Parts, GCDTy, SrcReg);
258 return GCDTy;
259}
260
261LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
263 unsigned PadStrategy) {
264 LLT LCMTy = getLCMType(DstTy, NarrowTy);
265
266 int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
267 int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
268 int NumOrigSrc = VRegs.size();
269
270 Register PadReg;
271
272 // Get a value we can use to pad the source value if the sources won't evenly
273 // cover the result type.
274 if (NumOrigSrc < NumParts * NumSubParts) {
275 if (PadStrategy == TargetOpcode::G_ZEXT)
276 PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
277 else if (PadStrategy == TargetOpcode::G_ANYEXT)
278 PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
279 else {
280 assert(PadStrategy == TargetOpcode::G_SEXT);
281
282 // Shift the sign bit of the low register through the high register.
283 auto ShiftAmt =
284 MIRBuilder.buildConstant(LLT::integer(64), GCDTy.getSizeInBits() - 1);
285 PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
286 }
287 }
288
289 // Registers for the final merge to be produced.
290 SmallVector<Register, 4> Remerge(NumParts);
291
292 // Registers needed for intermediate merges, which will be merged into a
293 // source for Remerge.
294 SmallVector<Register, 4> SubMerge(NumSubParts);
295
296 // Once we've fully read off the end of the original source bits, we can reuse
297 // the same high bits for remaining padding elements.
298 Register AllPadReg;
299
300 // Build merges to the LCM type to cover the original result type.
301 for (int I = 0; I != NumParts; ++I) {
302 bool AllMergePartsArePadding = true;
303
304 // Build the requested merges to the requested type.
305 for (int J = 0; J != NumSubParts; ++J) {
306 int Idx = I * NumSubParts + J;
307 if (Idx >= NumOrigSrc) {
308 SubMerge[J] = PadReg;
309 continue;
310 }
311
312 SubMerge[J] = VRegs[Idx];
313
314 // There are meaningful bits here we can't reuse later.
315 AllMergePartsArePadding = false;
316 }
317
318 // If we've filled up a complete piece with padding bits, we can directly
319 // emit the natural sized constant if applicable, rather than a merge of
320 // smaller constants.
321 if (AllMergePartsArePadding && !AllPadReg) {
322 if (PadStrategy == TargetOpcode::G_ANYEXT)
323 AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
324 else if (PadStrategy == TargetOpcode::G_ZEXT)
325 AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
326
327 // If this is a sign extension, we can't materialize a trivial constant
328 // with the right type and have to produce a merge.
329 }
330
331 if (AllPadReg) {
332 // Avoid creating additional instructions if we're just adding additional
333 // copies of padding bits.
334 Remerge[I] = AllPadReg;
335 continue;
336 }
337
338 if (NumSubParts == 1)
339 Remerge[I] = SubMerge[0];
340 else
341 Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
342
343 // In the sign extend padding case, re-use the first all-signbit merge.
344 if (AllMergePartsArePadding && !AllPadReg)
345 AllPadReg = Remerge[I];
346 }
347
348 VRegs = std::move(Remerge);
349 return LCMTy;
350}
351
352void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
353 ArrayRef<Register> RemergeRegs) {
354 LLT DstTy = MRI.getType(DstReg);
355
356 // Create the merge to the widened source, and extract the relevant bits into
357 // the result.
358
359 if (DstTy == LCMTy) {
360 MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
361 return;
362 }
363
364 auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
365 if (DstTy.isScalar() && LCMTy.isScalar()) {
366 MIRBuilder.buildTrunc(DstReg, Remerge);
367 return;
368 }
369
370 if (LCMTy.isVector()) {
371 unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
372 SmallVector<Register, 8> UnmergeDefs(NumDefs);
373 UnmergeDefs[0] = DstReg;
374 for (unsigned I = 1; I != NumDefs; ++I)
375 UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
376
377 MIRBuilder.buildUnmerge(UnmergeDefs,
378 MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
379 return;
380 }
381
382 llvm_unreachable("unhandled case");
383}
384
385static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
386#define RTLIBCASE_INT(LibcallPrefix) \
387 do { \
388 switch (Size) { \
389 case 32: \
390 return RTLIB::LibcallPrefix##32; \
391 case 64: \
392 return RTLIB::LibcallPrefix##64; \
393 case 128: \
394 return RTLIB::LibcallPrefix##128; \
395 default: \
396 llvm_unreachable("unexpected size"); \
397 } \
398 } while (0)
399
400#define RTLIBCASE(LibcallPrefix) \
401 do { \
402 switch (Size) { \
403 case 32: \
404 return RTLIB::LibcallPrefix##32; \
405 case 64: \
406 return RTLIB::LibcallPrefix##64; \
407 case 80: \
408 return RTLIB::LibcallPrefix##80; \
409 case 128: \
410 return RTLIB::LibcallPrefix##128; \
411 default: \
412 llvm_unreachable("unexpected size"); \
413 } \
414 } while (0)
415
416 switch (Opcode) {
417 case TargetOpcode::G_LROUND:
418 RTLIBCASE(LROUND_F);
419 case TargetOpcode::G_LLROUND:
420 RTLIBCASE(LLROUND_F);
421 case TargetOpcode::G_MUL:
422 RTLIBCASE_INT(MUL_I);
423 case TargetOpcode::G_SDIV:
424 RTLIBCASE_INT(SDIV_I);
425 case TargetOpcode::G_UDIV:
426 RTLIBCASE_INT(UDIV_I);
427 case TargetOpcode::G_SREM:
428 RTLIBCASE_INT(SREM_I);
429 case TargetOpcode::G_UREM:
430 RTLIBCASE_INT(UREM_I);
431 case TargetOpcode::G_CTLZ_ZERO_POISON:
432 RTLIBCASE_INT(CTLZ_I);
433 case TargetOpcode::G_FADD:
434 RTLIBCASE(ADD_F);
435 case TargetOpcode::G_FSUB:
436 RTLIBCASE(SUB_F);
437 case TargetOpcode::G_FMUL:
438 RTLIBCASE(MUL_F);
439 case TargetOpcode::G_FDIV:
440 RTLIBCASE(DIV_F);
441 case TargetOpcode::G_FEXP:
442 RTLIBCASE(EXP_F);
443 case TargetOpcode::G_FEXP2:
444 RTLIBCASE(EXP2_F);
445 case TargetOpcode::G_FEXP10:
446 RTLIBCASE(EXP10_F);
447 case TargetOpcode::G_FREM:
448 RTLIBCASE(REM_F);
449 case TargetOpcode::G_FPOW:
450 RTLIBCASE(POW_F);
451 case TargetOpcode::G_FPOWI:
452 RTLIBCASE(POWI_F);
453 case TargetOpcode::G_FMA:
454 RTLIBCASE(FMA_F);
455 case TargetOpcode::G_FSIN:
456 RTLIBCASE(SIN_F);
457 case TargetOpcode::G_FCOS:
458 RTLIBCASE(COS_F);
459 case TargetOpcode::G_FTAN:
460 RTLIBCASE(TAN_F);
461 case TargetOpcode::G_FASIN:
462 RTLIBCASE(ASIN_F);
463 case TargetOpcode::G_FACOS:
464 RTLIBCASE(ACOS_F);
465 case TargetOpcode::G_FATAN:
466 RTLIBCASE(ATAN_F);
467 case TargetOpcode::G_FATAN2:
468 RTLIBCASE(ATAN2_F);
469 case TargetOpcode::G_FSINH:
470 RTLIBCASE(SINH_F);
471 case TargetOpcode::G_FCOSH:
472 RTLIBCASE(COSH_F);
473 case TargetOpcode::G_FTANH:
474 RTLIBCASE(TANH_F);
475 case TargetOpcode::G_FSINCOS:
476 RTLIBCASE(SINCOS_F);
477 case TargetOpcode::G_FMODF:
478 RTLIBCASE(MODF_F);
479 case TargetOpcode::G_FLOG10:
480 RTLIBCASE(LOG10_F);
481 case TargetOpcode::G_FLOG:
482 RTLIBCASE(LOG_F);
483 case TargetOpcode::G_FLOG2:
484 RTLIBCASE(LOG2_F);
485 case TargetOpcode::G_FLDEXP:
486 RTLIBCASE(LDEXP_F);
487 case TargetOpcode::G_FCEIL:
488 RTLIBCASE(CEIL_F);
489 case TargetOpcode::G_FFLOOR:
490 RTLIBCASE(FLOOR_F);
491 case TargetOpcode::G_FMINNUM:
492 RTLIBCASE(FMIN_F);
493 case TargetOpcode::G_FMAXNUM:
494 RTLIBCASE(FMAX_F);
495 case TargetOpcode::G_FMINIMUMNUM:
496 RTLIBCASE(FMINIMUM_NUM_F);
497 case TargetOpcode::G_FMAXIMUMNUM:
498 RTLIBCASE(FMAXIMUM_NUM_F);
499 case TargetOpcode::G_FSQRT:
500 RTLIBCASE(SQRT_F);
501 case TargetOpcode::G_FRINT:
502 RTLIBCASE(RINT_F);
503 case TargetOpcode::G_FNEARBYINT:
504 RTLIBCASE(NEARBYINT_F);
505 case TargetOpcode::G_INTRINSIC_TRUNC:
506 RTLIBCASE(TRUNC_F);
507 case TargetOpcode::G_INTRINSIC_ROUND:
508 RTLIBCASE(ROUND_F);
509 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
510 RTLIBCASE(ROUNDEVEN_F);
511 case TargetOpcode::G_INTRINSIC_LRINT:
512 RTLIBCASE(LRINT_F);
513 case TargetOpcode::G_INTRINSIC_LLRINT:
514 RTLIBCASE(LLRINT_F);
515 }
516 llvm_unreachable("Unknown libcall function");
517#undef RTLIBCASE_INT
518#undef RTLIBCASE
519}
520
522 const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
523 return TLI.supportSwiftError() &&
524 MF.getFunction().getAttributes().hasAttrSomewhere(
525 Attribute::SwiftError);
526}
527
528/// True if an instruction is in tail position in its caller. Intended for
529/// legalizing libcalls as tail calls when possible.
532 const TargetInstrInfo &TII,
533 MachineRegisterInfo &MRI) {
534 MachineBasicBlock &MBB = *MI.getParent();
535 const Function &F = MBB.getParent()->getFunction();
536
537 // Conservatively require the attributes of the call to match those of
538 // the return. Ignore NoAlias and NonNull because they don't affect the
539 // call sequence.
540 AttributeList CallerAttrs = F.getAttributes();
541 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
542 .removeAttribute(Attribute::NoAlias)
543 .removeAttribute(Attribute::NonNull)
544 .hasAttributes())
545 return false;
546
547 // It's not safe to eliminate the sign / zero extension of the return value.
548 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
549 CallerAttrs.hasRetAttr(Attribute::SExt))
550 return false;
551
552 // Only tail call if the following instruction is a standard return or if we
553 // have a `thisreturn` callee, and a sequence like:
554 //
555 // G_MEMCPY %0, %1, %2
556 // $x0 = COPY %0
557 // RET_ReallyLR implicit $x0
558 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
559 if (Next != MBB.instr_end() && Next->isCopy()) {
560 if (MI.getOpcode() == TargetOpcode::G_BZERO)
561 return false;
562
563 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
564 // mempy/etc routines return the same parameter. For other it will be the
565 // returned value.
566 Register VReg = MI.getOperand(0).getReg();
567 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
568 return false;
569
570 Register PReg = Next->getOperand(0).getReg();
571 if (!PReg.isPhysical())
572 return false;
573
574 auto Ret = next_nodbg(Next, MBB.instr_end());
575 if (Ret == MBB.instr_end() || !Ret->isReturn())
576 return false;
577
578 if (Ret->getNumImplicitOperands() != 1)
579 return false;
580
581 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
582 return false;
583
584 // Skip over the COPY that we just validated.
585 Next = Ret;
586 }
587
588 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
589 return false;
590
591 return true;
592}
593
595 const char *Name, const CallLowering::ArgInfo &Result,
597 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
598 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
599
601 Info.CallConv = CC;
602 Info.Callee = MachineOperand::CreateES(Name);
603 Info.OrigRet = Result;
604 if (MI)
605 Info.IsTailCall =
606 (Result.Ty->isVoidTy() ||
607 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
608 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
609 *MIRBuilder.getMRI()) &&
610 // Lowering doesn't support tail calling inside a function with
611 // a swifterror argument yet.
613
614 llvm::append_range(Info.OrigArgs, Args);
615 if (!CLI.lowerCall(MIRBuilder, Info))
617
618 if (MI && Info.LoweredTailCall) {
619 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
620
621 // Check debug locations before removing the return.
622 LocObserver.checkpoint(true);
623
624 // We must have a return following the call (or debug insts) to get past
625 // isLibCallInTailPosition.
626 do {
627 MachineInstr *Next = MI->getNextNode();
628 assert(Next &&
629 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
630 "Expected instr following MI to be return or debug inst?");
631 // We lowered a tail call, so the call is now the return from the block.
632 // Delete the old return.
633 Next->eraseFromParent();
634 } while (MI->getNextNode());
635
636 // We expect to lose the debug location from the return.
637 LocObserver.checkpoint(false);
638 }
640}
641
643 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
645 MachineInstr *MI) const {
646 if (!Libcalls)
648
649 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
650 if (LibcallImpl == RTLIB::Unsupported)
652
654 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
655 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
656}
657
658// Useful for libcalls where all operands have the same type.
661 unsigned Size, Type *OpType,
662 LostDebugLocObserver &LocObserver) const {
663 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
664
665 // FIXME: What does the original arg index mean here?
667 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
668 Args.push_back({MO.getReg(), OpType, 0});
669 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
670 LocObserver, &MI);
671}
672
673LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
674 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
675 LostDebugLocObserver &LocObserver) {
676 MachineFunction &MF = *MI.getMF();
678
679 Register DstSin = MI.getOperand(0).getReg();
680 Register DstCos = MI.getOperand(1).getReg();
681 Register Src = MI.getOperand(2).getReg();
682 LLT DstTy = MRI.getType(DstSin);
683
684 int MemSize = DstTy.getSizeInBytes();
685 Align Alignment = getStackTemporaryAlignment(DstTy);
687 unsigned AddrSpace = DL.getAllocaAddrSpace();
688 MachinePointerInfo PtrInfo;
689
690 Register StackPtrSin =
691 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
692 .getReg(0);
693 Register StackPtrCos =
694 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
695 .getReg(0);
696
697 auto &Ctx = MF.getFunction().getContext();
698 auto LibcallResult = createLibcall(
699 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
700 {{Src, OpType, 0},
701 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
702 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
703 LocObserver, &MI);
704
705 if (LibcallResult != LegalizeResult::Legalized)
707
709 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
711 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
712
713 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
714 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
715 MI.eraseFromParent();
716
718}
719
721LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
722 unsigned Size, Type *OpType,
723 LostDebugLocObserver &LocObserver) {
724 MachineFunction &MF = MIRBuilder.getMF();
725 MachineRegisterInfo &MRI = MF.getRegInfo();
726
727 Register DstFrac = MI.getOperand(0).getReg();
728 Register DstInt = MI.getOperand(1).getReg();
729 Register Src = MI.getOperand(2).getReg();
730 LLT DstTy = MRI.getType(DstFrac);
731
732 int MemSize = DstTy.getSizeInBytes();
734 const DataLayout &DL = MIRBuilder.getDataLayout();
735 unsigned AddrSpace = DL.getAllocaAddrSpace();
736 MachinePointerInfo PtrInfo;
737
738 Register StackPtrInt =
739 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
740 .getReg(0);
741
742 auto &Ctx = MF.getFunction().getContext();
743 auto LibcallResult = createLibcall(
744 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
745 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
746 LocObserver, &MI);
747
748 if (LibcallResult != LegalizeResult::Legalized)
750
752 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
753
754 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
755 MI.eraseFromParent();
756
758}
759
760static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
761 Type *FromType) {
762 auto ToMVT = MVT::getVT(ToType);
763 auto FromMVT = MVT::getVT(FromType);
764
765 switch (Opcode) {
766 case TargetOpcode::G_FPEXT:
767 return RTLIB::getFPEXT(FromMVT, ToMVT);
768 case TargetOpcode::G_FPTRUNC:
769 return RTLIB::getFPROUND(FromMVT, ToMVT);
770 case TargetOpcode::G_FPTOSI:
771 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
772 case TargetOpcode::G_FPTOUI:
773 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
774 case TargetOpcode::G_SITOFP:
775 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
776 case TargetOpcode::G_UITOFP:
777 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
778 }
779 llvm_unreachable("Unsupported libcall function");
780}
781
783 MachineInstr &MI, Type *ToType, Type *FromType,
784 LostDebugLocObserver &LocObserver, bool IsSigned) const {
785 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
786 if (FromType->isIntegerTy()) {
787 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
788 Arg.Flags[0].setSExt();
789 else
790 Arg.Flags[0].setZExt();
791 }
792
793 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
794 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
795 LocObserver, &MI);
796}
797
800 LostDebugLocObserver &LocObserver) const {
801 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
802
804 // Add all the args, except for the last which is an imm denoting 'tail'.
805 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
806 Register Reg = MI.getOperand(i).getReg();
807
808 // Need derive an IR type for call lowering.
809 LLT OpLLT = MRI.getType(Reg);
810 Type *OpTy = nullptr;
811 if (OpLLT.isPointer())
812 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
813 else
814 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
815 Args.push_back({Reg, OpTy, 0});
816 }
817
818 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
819 RTLIB::Libcall RTLibcall;
820 unsigned Opc = MI.getOpcode();
821 switch (Opc) {
822 case TargetOpcode::G_BZERO:
823 RTLibcall = RTLIB::BZERO;
824 break;
825 case TargetOpcode::G_MEMCPY:
826 RTLibcall = RTLIB::MEMCPY;
827 Args[0].Flags[0].setReturned();
828 break;
829 case TargetOpcode::G_MEMMOVE:
830 RTLibcall = RTLIB::MEMMOVE;
831 Args[0].Flags[0].setReturned();
832 break;
833 case TargetOpcode::G_MEMSET:
834 RTLibcall = RTLIB::MEMSET;
835 Args[0].Flags[0].setReturned();
836 break;
837 default:
838 llvm_unreachable("unsupported opcode");
839 }
840
841 if (!Libcalls) // FIXME: Should be mandatory
843
844 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
845
846 // Unsupported libcall on the target.
847 if (RTLibcallImpl == RTLIB::Unsupported) {
848 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
849 << MIRBuilder.getTII().getName(Opc) << "\n");
851 }
852
854 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
855
856 StringRef LibcallName =
858 Info.Callee = MachineOperand::CreateES(LibcallName.data());
859 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
860 Info.IsTailCall =
861 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
862 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI) &&
863 // Lowering doesn't support tail calling inside a function with
864 // a swifterror argument yet.
866
867 llvm::append_range(Info.OrigArgs, Args);
868 if (!CLI.lowerCall(MIRBuilder, Info))
870
871 if (Info.LoweredTailCall) {
872 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
873
874 // Check debug locations before removing the return.
875 LocObserver.checkpoint(true);
876
877 // We must have a return following the call (or debug insts) to get past
878 // isLibCallInTailPosition.
879 do {
880 MachineInstr *Next = MI.getNextNode();
881 assert(Next &&
882 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
883 "Expected instr following MI to be return or debug inst?");
884 // We lowered a tail call, so the call is now the return from the block.
885 // Delete the old return.
886 Next->eraseFromParent();
887 } while (MI.getNextNode());
888
889 // We expect to lose the debug location from the return.
890 LocObserver.checkpoint(false);
891 }
892
894}
895
896static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
897 unsigned Opc = MI.getOpcode();
898 auto &AtomicMI = cast<GMemOperation>(MI);
899 auto &MMO = AtomicMI.getMMO();
900 auto Ordering = MMO.getMergedOrdering();
901 LLT MemType = MMO.getMemoryType();
902 uint64_t MemSize = MemType.getSizeInBytes();
903 if (MemType.isVector())
904 return RTLIB::UNKNOWN_LIBCALL;
905
906#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
907#define LCALL5(A) \
908 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
909 switch (Opc) {
910 case TargetOpcode::G_ATOMIC_CMPXCHG:
911 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
912 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
913 return getOutlineAtomicHelper(LC, Ordering, MemSize);
914 }
915 case TargetOpcode::G_ATOMICRMW_XCHG: {
916 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
917 return getOutlineAtomicHelper(LC, Ordering, MemSize);
918 }
919 case TargetOpcode::G_ATOMICRMW_ADD:
920 case TargetOpcode::G_ATOMICRMW_SUB: {
921 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
922 return getOutlineAtomicHelper(LC, Ordering, MemSize);
923 }
924 case TargetOpcode::G_ATOMICRMW_AND: {
925 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
926 return getOutlineAtomicHelper(LC, Ordering, MemSize);
927 }
928 case TargetOpcode::G_ATOMICRMW_OR: {
929 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
930 return getOutlineAtomicHelper(LC, Ordering, MemSize);
931 }
932 case TargetOpcode::G_ATOMICRMW_XOR: {
933 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
934 return getOutlineAtomicHelper(LC, Ordering, MemSize);
935 }
936 default:
937 return RTLIB::UNKNOWN_LIBCALL;
938 }
939#undef LCALLS
940#undef LCALL5
941}
942
945 auto &Ctx = MIRBuilder.getContext();
946
947 Type *RetTy;
948 SmallVector<Register> RetRegs;
950 unsigned Opc = MI.getOpcode();
951 switch (Opc) {
952 case TargetOpcode::G_ATOMIC_CMPXCHG:
953 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
955 LLT SuccessLLT;
956 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
957 MI.getFirst4RegLLTs();
958 RetRegs.push_back(Ret);
959 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
960 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
961 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
962 NewLLT) = MI.getFirst5RegLLTs();
963 RetRegs.push_back(Success);
964 RetTy = StructType::get(
965 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
966 }
967 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
968 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
969 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
970 break;
971 }
972 case TargetOpcode::G_ATOMICRMW_XCHG:
973 case TargetOpcode::G_ATOMICRMW_ADD:
974 case TargetOpcode::G_ATOMICRMW_SUB:
975 case TargetOpcode::G_ATOMICRMW_AND:
976 case TargetOpcode::G_ATOMICRMW_OR:
977 case TargetOpcode::G_ATOMICRMW_XOR: {
978 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
979 RetRegs.push_back(Ret);
980 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
981 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
982 Val =
983 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
984 .getReg(0);
985 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
986 Val =
987 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
988 .getReg(0);
989 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
990 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
991 break;
992 }
993 default:
994 llvm_unreachable("unsupported opcode");
995 }
996
997 if (!Libcalls) // FIXME: Should be mandatory
999
1000 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
1001 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
1002 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
1003
1004 // Unsupported libcall on the target.
1005 if (RTLibcallImpl == RTLIB::Unsupported) {
1006 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
1007 << MIRBuilder.getTII().getName(Opc) << "\n");
1009 }
1010
1012 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1013
1014 StringRef LibcallName =
1016 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1017 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1018
1019 llvm::append_range(Info.OrigArgs, Args);
1020 if (!CLI.lowerCall(MIRBuilder, Info))
1022
1024}
1025
1026static RTLIB::Libcall
1028 RTLIB::Libcall RTLibcall;
1029 switch (MI.getOpcode()) {
1030 case TargetOpcode::G_GET_FPENV:
1031 RTLibcall = RTLIB::FEGETENV;
1032 break;
1033 case TargetOpcode::G_SET_FPENV:
1034 case TargetOpcode::G_RESET_FPENV:
1035 RTLibcall = RTLIB::FESETENV;
1036 break;
1037 case TargetOpcode::G_GET_FPMODE:
1038 RTLibcall = RTLIB::FEGETMODE;
1039 break;
1040 case TargetOpcode::G_SET_FPMODE:
1041 case TargetOpcode::G_RESET_FPMODE:
1042 RTLibcall = RTLIB::FESETMODE;
1043 break;
1044 default:
1045 llvm_unreachable("Unexpected opcode");
1046 }
1047 return RTLibcall;
1048}
1049
1050// Some library functions that read FP state (fegetmode, fegetenv) write the
1051// state into a region in memory. IR intrinsics that do the same operations
1052// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1053// intrinsics via the library functions, we need to use temporary variable,
1054// for example:
1055//
1056// %0:_(s32) = G_GET_FPMODE
1057//
1058// is transformed to:
1059//
1060// %1:_(p0) = G_FRAME_INDEX %stack.0
1061// BL &fegetmode
1062// %0:_(s32) = G_LOAD % 1
1063//
1065LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1066 LostDebugLocObserver &LocObserver) {
1067 const DataLayout &DL = MIRBuilder.getDataLayout();
1068 auto &MF = MIRBuilder.getMF();
1069 auto &MRI = *MIRBuilder.getMRI();
1070 auto &Ctx = MF.getFunction().getContext();
1071
1072 // Create temporary, where library function will put the read state.
1073 Register Dst = MI.getOperand(0).getReg();
1074 LLT StateTy = MRI.getType(Dst);
1075 TypeSize StateSize = StateTy.getSizeInBytes();
1076 Align TempAlign = getStackTemporaryAlignment(StateTy);
1077 MachinePointerInfo TempPtrInfo;
1078 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1079
1080 // Create a call to library function, with the temporary as an argument.
1081 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1082 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1083 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1084 auto Res = createLibcall(
1085 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1086 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1087 nullptr);
1088 if (Res != LegalizerHelper::Legalized)
1089 return Res;
1090
1091 // Create a load from the temporary.
1092 MachineMemOperand *MMO = MF.getMachineMemOperand(
1093 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1094 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1095
1097}
1098
1099// Similar to `createGetStateLibcall` the function calls a library function
1100// using transient space in stack. In this case the library function reads
1101// content of memory region.
1103LegalizerHelper::createSetStateLibcall(MachineInstr &MI,
1104 LostDebugLocObserver &LocObserver) {
1105 const DataLayout &DL = MIRBuilder.getDataLayout();
1106 auto &MF = MIRBuilder.getMF();
1107 auto &MRI = *MIRBuilder.getMRI();
1108 auto &Ctx = MF.getFunction().getContext();
1109
1110 // Create temporary, where library function will get the new state.
1111 Register Src = MI.getOperand(0).getReg();
1112 LLT StateTy = MRI.getType(Src);
1113 TypeSize StateSize = StateTy.getSizeInBytes();
1114 Align TempAlign = getStackTemporaryAlignment(StateTy);
1115 MachinePointerInfo TempPtrInfo;
1116 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1117
1118 // Put the new state into the temporary.
1119 MachineMemOperand *MMO = MF.getMachineMemOperand(
1120 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1121 MIRBuilder.buildStore(Src, Temp, *MMO);
1122
1123 // Create a call to library function, with the temporary as an argument.
1124 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1125 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1126 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1127 return createLibcall(RTLibcall,
1128 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1129 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1130 LocObserver, nullptr);
1131}
1132
1133/// Returns the corresponding libcall for the given Pred and
1134/// the ICMP predicate that should be generated to compare with #0
1135/// after the libcall.
1136static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1138#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1139 do { \
1140 switch (Size) { \
1141 case 32: \
1142 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1143 case 64: \
1144 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1145 case 128: \
1146 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1147 default: \
1148 llvm_unreachable("unexpected size"); \
1149 } \
1150 } while (0)
1151
1152 // These use the three-way (-1/0/1) compare libcalls, whose result is tested
1153 // against 0 with a signed integer predicate. Unordered (UO) is a boolean.
1154 switch (Pred) {
1155 case CmpInst::FCMP_OEQ:
1156 RTLIBCASE_CMP(FCMP3_PRED_OEQ_F, CmpInst::ICMP_EQ);
1157 case CmpInst::FCMP_UNE:
1158 RTLIBCASE_CMP(FCMP3_PRED_UNE_F, CmpInst::ICMP_NE);
1159 case CmpInst::FCMP_OGE:
1160 RTLIBCASE_CMP(FCMP3_PRED_OGE_F, CmpInst::ICMP_SGE);
1161 case CmpInst::FCMP_OLT:
1162 RTLIBCASE_CMP(FCMP3_PRED_OLT_F, CmpInst::ICMP_SLT);
1163 case CmpInst::FCMP_OLE:
1164 RTLIBCASE_CMP(FCMP3_PRED_OLE_F, CmpInst::ICMP_SLE);
1165 case CmpInst::FCMP_OGT:
1166 RTLIBCASE_CMP(FCMP3_PRED_OGT_F, CmpInst::ICMP_SGT);
1167 case CmpInst::FCMP_UNO:
1169 default:
1170 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1171 }
1172}
1173
1175LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1176 LostDebugLocObserver &LocObserver) {
1177 auto &MF = MIRBuilder.getMF();
1178 auto &Ctx = MF.getFunction().getContext();
1179 const GFCmp *Cmp = cast<GFCmp>(&MI);
1180
1181 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1182 unsigned Size = OpLLT.getSizeInBits();
1183 if ((Size != 32 && Size != 64 && Size != 128) ||
1184 OpLLT != MRI.getType(Cmp->getRHSReg()))
1185 return UnableToLegalize;
1186
1187 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1188
1189 // DstReg type is s32
1190 const Register DstReg = Cmp->getReg(0);
1191 LLT DstTy = MRI.getType(DstReg);
1192 const auto Cond = Cmp->getCond();
1193
1194 // Reference:
1195 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1196 // Generates a libcall followed by ICMP.
1197 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1198 const CmpInst::Predicate ICmpPred,
1199 const DstOp &Res) -> Register {
1200 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1201 LLT TempLLT = LLT::integer(32);
1202 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1203 // Generate libcall, holding result in Temp
1204 const auto Status = createLibcall(
1205 Libcall, {Temp, Type::getInt32Ty(Ctx), 0},
1206 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1207 LocObserver, &MI);
1208 if (Status != Legalized)
1209 return {};
1210
1211 // Compare temp with #0 to get the final result.
1212 return MIRBuilder
1213 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1214 .getReg(0);
1215 };
1216
1217 // Simple case if we have a direct mapping from predicate to libcall
1218 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1219 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1220 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1221 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1222 return Legalized;
1223 }
1224 return UnableToLegalize;
1225 }
1226
1227 // No direct mapping found, should be generated as combination of libcalls.
1228
1229 switch (Cond) {
1230 case CmpInst::FCMP_UEQ: {
1231 // FCMP_UEQ: unordered or equal
1232 // Convert into (FCMP_OEQ || FCMP_UNO).
1233
1234 const auto [OeqLibcall, OeqPred] =
1236 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1237
1238 const auto [UnoLibcall, UnoPred] =
1240 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1241 if (Oeq && Uno)
1242 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1243 else
1244 return UnableToLegalize;
1245
1246 break;
1247 }
1248 case CmpInst::FCMP_ONE: {
1249 // FCMP_ONE: ordered and operands are unequal
1250 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1251
1252 // We inverse the predicate instead of generating a NOT
1253 // to save one instruction.
1254 // On AArch64 isel can even select two cmp into a single ccmp.
1255 const auto [OeqLibcall, OeqPred] =
1257 const auto NotOeq =
1258 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1259
1260 const auto [UnoLibcall, UnoPred] =
1262 const auto NotUno =
1263 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1264
1265 if (NotOeq && NotUno)
1266 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1267 else
1268 return UnableToLegalize;
1269
1270 break;
1271 }
1272 case CmpInst::FCMP_ULT:
1273 case CmpInst::FCMP_UGE:
1274 case CmpInst::FCMP_UGT:
1275 case CmpInst::FCMP_ULE:
1276 case CmpInst::FCMP_ORD: {
1277 // Convert into: !(inverse(Pred))
1278 // E.g. FCMP_ULT becomes !FCMP_OGE
1279 // This is equivalent to the following, but saves some instructions.
1280 // MIRBuilder.buildNot(
1281 // PredTy,
1282 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1283 // Op1, Op2));
1284 const auto [InversedLibcall, InversedPred] =
1286 if (!BuildLibcall(InversedLibcall,
1287 CmpInst::getInversePredicate(InversedPred), DstReg))
1288 return UnableToLegalize;
1289 break;
1290 }
1291 default:
1292 return UnableToLegalize;
1293 }
1294
1295 return Legalized;
1296}
1297
1298// The function is used to legalize operations that set default environment
1299// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1300// On most targets supported in glibc FE_DFL_MODE is defined as
1301// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1302// it is not true, the target must provide custom lowering.
1304LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1305 LostDebugLocObserver &LocObserver) {
1306 const DataLayout &DL = MIRBuilder.getDataLayout();
1307 auto &MF = MIRBuilder.getMF();
1308 auto &Ctx = MF.getFunction().getContext();
1309
1310 // Create an argument for the library function.
1311 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1312 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1313 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1314 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1315 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1316 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1317 MIRBuilder.buildIntToPtr(Dest, DefValue);
1318
1319 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1320 return createLibcall(
1321 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1322 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1323}
1324
1327 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1328
1329 switch (MI.getOpcode()) {
1330 default:
1331 return UnableToLegalize;
1332 case TargetOpcode::G_MUL:
1333 case TargetOpcode::G_SDIV:
1334 case TargetOpcode::G_UDIV:
1335 case TargetOpcode::G_SREM:
1336 case TargetOpcode::G_UREM:
1337 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1338 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1339 unsigned Size = LLTy.getSizeInBits();
1340 Type *HLTy = IntegerType::get(Ctx, Size);
1341 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1342 if (Status != Legalized)
1343 return Status;
1344 break;
1345 }
1346 case TargetOpcode::G_FADD:
1347 case TargetOpcode::G_FSUB:
1348 case TargetOpcode::G_FMUL:
1349 case TargetOpcode::G_FDIV:
1350 case TargetOpcode::G_FMA:
1351 case TargetOpcode::G_FPOW:
1352 case TargetOpcode::G_FREM:
1353 case TargetOpcode::G_FCOS:
1354 case TargetOpcode::G_FSIN:
1355 case TargetOpcode::G_FTAN:
1356 case TargetOpcode::G_FACOS:
1357 case TargetOpcode::G_FASIN:
1358 case TargetOpcode::G_FATAN:
1359 case TargetOpcode::G_FATAN2:
1360 case TargetOpcode::G_FCOSH:
1361 case TargetOpcode::G_FSINH:
1362 case TargetOpcode::G_FTANH:
1363 case TargetOpcode::G_FLOG10:
1364 case TargetOpcode::G_FLOG:
1365 case TargetOpcode::G_FLOG2:
1366 case TargetOpcode::G_FEXP:
1367 case TargetOpcode::G_FEXP2:
1368 case TargetOpcode::G_FEXP10:
1369 case TargetOpcode::G_FCEIL:
1370 case TargetOpcode::G_FFLOOR:
1371 case TargetOpcode::G_FMINNUM:
1372 case TargetOpcode::G_FMAXNUM:
1373 case TargetOpcode::G_FMINIMUMNUM:
1374 case TargetOpcode::G_FMAXIMUMNUM:
1375 case TargetOpcode::G_FSQRT:
1376 case TargetOpcode::G_FRINT:
1377 case TargetOpcode::G_FNEARBYINT:
1378 case TargetOpcode::G_INTRINSIC_TRUNC:
1379 case TargetOpcode::G_INTRINSIC_ROUND:
1380 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1381 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1382 unsigned Size = LLTy.getSizeInBits();
1383 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1384 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1385 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1386 return UnableToLegalize;
1387 }
1388 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1389 if (Status != Legalized)
1390 return Status;
1391 break;
1392 }
1393 case TargetOpcode::G_FSINCOS: {
1394 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1395 unsigned Size = LLTy.getSizeInBits();
1396 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1397 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1398 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1399 return UnableToLegalize;
1400 }
1401 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1402 }
1403 case TargetOpcode::G_FMODF: {
1404 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1405 unsigned Size = LLTy.getSizeInBits();
1406 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1407 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1408 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1409 return UnableToLegalize;
1410 }
1411 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1412 }
1413 case TargetOpcode::G_LROUND:
1414 case TargetOpcode::G_LLROUND:
1415 case TargetOpcode::G_INTRINSIC_LRINT:
1416 case TargetOpcode::G_INTRINSIC_LLRINT: {
1417 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1418 unsigned Size = LLTy.getSizeInBits();
1419 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1420 Type *ITy = IntegerType::get(
1421 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1422 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1423 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1424 return UnableToLegalize;
1425 }
1426 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1428 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1429 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1430 if (Status != Legalized)
1431 return Status;
1432 MI.eraseFromParent();
1433 return Legalized;
1434 }
1435 case TargetOpcode::G_FPOWI:
1436 case TargetOpcode::G_FLDEXP: {
1437 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1438 unsigned Size = LLTy.getSizeInBits();
1439 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1440 Type *ITy = IntegerType::get(
1441 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1442 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1443 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1444 return UnableToLegalize;
1445 }
1446 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1448 {MI.getOperand(1).getReg(), HLTy, 0},
1449 {MI.getOperand(2).getReg(), ITy, 1}};
1450 Args[1].Flags[0].setSExt();
1452 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1453 if (Status != Legalized)
1454 return Status;
1455 break;
1456 }
1457 case TargetOpcode::G_FPEXT:
1458 case TargetOpcode::G_FPTRUNC: {
1459 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1460 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1461 if (!FromTy || !ToTy)
1462 return UnableToLegalize;
1463 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1464 if (Status != Legalized)
1465 return Status;
1466 break;
1467 }
1468 case TargetOpcode::G_FCMP: {
1469 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1470 if (Status != Legalized)
1471 return Status;
1472 MI.eraseFromParent();
1473 return Status;
1474 }
1475 case TargetOpcode::G_FPTOSI:
1476 case TargetOpcode::G_FPTOUI: {
1477 // FIXME: Support other types
1478 Type *FromTy =
1479 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1480 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1481 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1482 return UnableToLegalize;
1484 FromTy, LocObserver);
1485 if (Status != Legalized)
1486 return Status;
1487 break;
1488 }
1489 case TargetOpcode::G_SITOFP:
1490 case TargetOpcode::G_UITOFP: {
1491 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1492 Type *ToTy =
1493 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1494 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1495 return UnableToLegalize;
1496 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1498 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1499 if (Status != Legalized)
1500 return Status;
1501 break;
1502 }
1503 case TargetOpcode::G_ATOMICRMW_XCHG:
1504 case TargetOpcode::G_ATOMICRMW_ADD:
1505 case TargetOpcode::G_ATOMICRMW_SUB:
1506 case TargetOpcode::G_ATOMICRMW_AND:
1507 case TargetOpcode::G_ATOMICRMW_OR:
1508 case TargetOpcode::G_ATOMICRMW_XOR:
1509 case TargetOpcode::G_ATOMIC_CMPXCHG:
1510 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1512 if (Status != Legalized)
1513 return Status;
1514 break;
1515 }
1516 case TargetOpcode::G_BZERO:
1517 case TargetOpcode::G_MEMCPY:
1518 case TargetOpcode::G_MEMMOVE:
1519 case TargetOpcode::G_MEMSET: {
1520 LegalizeResult Result =
1521 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1522 if (Result != Legalized)
1523 return Result;
1524 MI.eraseFromParent();
1525 return Result;
1526 }
1527 case TargetOpcode::G_GET_FPENV:
1528 case TargetOpcode::G_GET_FPMODE: {
1529 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1530 if (Result != Legalized)
1531 return Result;
1532 break;
1533 }
1534 case TargetOpcode::G_SET_FPENV:
1535 case TargetOpcode::G_SET_FPMODE: {
1536 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1537 if (Result != Legalized)
1538 return Result;
1539 break;
1540 }
1541 case TargetOpcode::G_RESET_FPENV:
1542 case TargetOpcode::G_RESET_FPMODE: {
1543 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1544 if (Result != Legalized)
1545 return Result;
1546 break;
1547 }
1548 }
1549
1550 MI.eraseFromParent();
1551 return Legalized;
1552}
1553
1555 unsigned TypeIdx,
1556 LLT NarrowTy) {
1557 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1558 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1559
1560 switch (MI.getOpcode()) {
1561 default:
1562 return UnableToLegalize;
1563 case TargetOpcode::G_IMPLICIT_DEF: {
1564 Register DstReg = MI.getOperand(0).getReg();
1565 LLT DstTy = MRI.getType(DstReg);
1566
1567 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1568 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1569 // FIXME: Although this would also be legal for the general case, it causes
1570 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1571 // combines not being hit). This seems to be a problem related to the
1572 // artifact combiner.
1573 if (SizeOp0 % NarrowSize != 0) {
1574 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1575 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1576 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1577
1578 MI.eraseFromParent();
1579 return Legalized;
1580 }
1581
1582 int NumParts = SizeOp0 / NarrowSize;
1583
1585 for (int i = 0; i < NumParts; ++i)
1586 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1587
1588 if (DstTy.isVector())
1589 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1590 else
1591 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1592 MI.eraseFromParent();
1593 return Legalized;
1594 }
1595 case TargetOpcode::G_CONSTANT: {
1596 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1597 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1598 unsigned TotalSize = Ty.getSizeInBits();
1599 unsigned NarrowSize = NarrowTy.getSizeInBits();
1600 int NumParts = TotalSize / NarrowSize;
1601
1602 SmallVector<Register, 4> PartRegs;
1603 for (int I = 0; I != NumParts; ++I) {
1604 unsigned Offset = I * NarrowSize;
1605 auto K = MIRBuilder.buildConstant(NarrowTy,
1606 Val.lshr(Offset).trunc(NarrowSize));
1607 PartRegs.push_back(K.getReg(0));
1608 }
1609
1610 LLT LeftoverTy;
1611 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1612 SmallVector<Register, 1> LeftoverRegs;
1613 if (LeftoverBits != 0) {
1614 LeftoverTy = LLT::scalar(LeftoverBits);
1615 auto K = MIRBuilder.buildConstant(
1616 LeftoverTy,
1617 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1618 LeftoverRegs.push_back(K.getReg(0));
1619 }
1620
1621 insertParts(MI.getOperand(0).getReg(),
1622 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1623
1624 MI.eraseFromParent();
1625 return Legalized;
1626 }
1627 case TargetOpcode::G_SEXT:
1628 case TargetOpcode::G_ZEXT:
1629 case TargetOpcode::G_ANYEXT:
1630 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1631 case TargetOpcode::G_TRUNC: {
1632 if (TypeIdx != 1)
1633 return UnableToLegalize;
1634
1635 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1636 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1637 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1638 return UnableToLegalize;
1639 }
1640
1641 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1642 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1643 MI.eraseFromParent();
1644 return Legalized;
1645 }
1646 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1647 case TargetOpcode::G_FREEZE: {
1648 if (TypeIdx != 0)
1649 return UnableToLegalize;
1650
1651 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1652 // Should widen scalar first
1653 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1654 return UnableToLegalize;
1655
1656 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1658 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1659 Parts.push_back(
1660 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1661 .getReg(0));
1662 }
1663
1664 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1665 MI.eraseFromParent();
1666 return Legalized;
1667 }
1668 case TargetOpcode::G_ADD:
1669 case TargetOpcode::G_SUB:
1670 case TargetOpcode::G_SADDO:
1671 case TargetOpcode::G_SSUBO:
1672 case TargetOpcode::G_SADDE:
1673 case TargetOpcode::G_SSUBE:
1674 case TargetOpcode::G_UADDO:
1675 case TargetOpcode::G_USUBO:
1676 case TargetOpcode::G_UADDE:
1677 case TargetOpcode::G_USUBE:
1678 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1679 case TargetOpcode::G_MUL:
1680 case TargetOpcode::G_UMULH:
1681 return narrowScalarMul(MI, NarrowTy);
1682 case TargetOpcode::G_EXTRACT:
1683 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1684 case TargetOpcode::G_INSERT:
1685 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1686 case TargetOpcode::G_LOAD: {
1687 auto &LoadMI = cast<GLoad>(MI);
1688 Register DstReg = LoadMI.getDstReg();
1689 LLT DstTy = MRI.getType(DstReg);
1690 if (DstTy.isVector())
1691 return UnableToLegalize;
1692
1693 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1694 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1695 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1696 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1697 LoadMI.eraseFromParent();
1698 return Legalized;
1699 }
1700
1701 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1702 }
1703 case TargetOpcode::G_ZEXTLOAD:
1704 case TargetOpcode::G_SEXTLOAD:
1705 case TargetOpcode::G_FPEXTLOAD: {
1706 auto &LoadMI = cast<GExtLoad>(MI);
1707 Register DstReg = LoadMI.getDstReg();
1708 Register PtrReg = LoadMI.getPointerReg();
1709
1710 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1711 auto &MMO = LoadMI.getMMO();
1712 unsigned MemSize = MMO.getSizeInBits().getValue();
1713
1714 if (MemSize == NarrowSize) {
1715 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1716 } else if (MemSize < NarrowSize) {
1717 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1718 } else if (MemSize > NarrowSize) {
1719 // FIXME: Need to split the load.
1720 return UnableToLegalize;
1721 }
1722
1723 if (isa<GZExtLoad>(LoadMI))
1724 MIRBuilder.buildZExt(DstReg, TmpReg);
1725 else if (isa<GSExtLoad>(LoadMI))
1726 MIRBuilder.buildSExt(DstReg, TmpReg);
1727 else
1728 MIRBuilder.buildFPExt(DstReg, TmpReg);
1729
1730 LoadMI.eraseFromParent();
1731 return Legalized;
1732 }
1733 case TargetOpcode::G_STORE: {
1734 auto &StoreMI = cast<GStore>(MI);
1735
1736 Register SrcReg = StoreMI.getValueReg();
1737 LLT SrcTy = MRI.getType(SrcReg);
1738 if (SrcTy.isVector())
1739 return UnableToLegalize;
1740
1741 int NumParts = SizeOp0 / NarrowSize;
1742 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1743 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1744 if (SrcTy.isVector() && LeftoverBits != 0)
1745 return UnableToLegalize;
1746
1747 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1748 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1749 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1750 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1751 StoreMI.eraseFromParent();
1752 return Legalized;
1753 }
1754
1755 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1756 }
1757 case TargetOpcode::G_FPTRUNCSTORE: {
1758 auto &StoreMI = cast<GFPTruncStore>(MI);
1759 Register SrcReg = StoreMI.getValueReg();
1760 Register PtrReg = StoreMI.getPointerReg();
1761
1762 auto &MMO = StoreMI.getMMO();
1763 unsigned MemSize = MMO.getSizeInBits().getValue();
1764 if (MemSize > NarrowSize) {
1765 return UnableToLegalize;
1766 }
1767
1768 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1769 if (MemSize == NarrowSize) {
1770 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1771 } else if (MemSize < NarrowSize) {
1772 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1773 MMO);
1774 }
1775
1776 StoreMI.eraseFromParent();
1777 return Legalized;
1778 }
1779 case TargetOpcode::G_SELECT:
1780 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1781 case TargetOpcode::G_AND:
1782 case TargetOpcode::G_OR:
1783 case TargetOpcode::G_XOR: {
1784 // Legalize bitwise operation:
1785 // A = BinOp<Ty> B, C
1786 // into:
1787 // B1, ..., BN = G_UNMERGE_VALUES B
1788 // C1, ..., CN = G_UNMERGE_VALUES C
1789 // A1 = BinOp<Ty/N> B1, C2
1790 // ...
1791 // AN = BinOp<Ty/N> BN, CN
1792 // A = G_MERGE_VALUES A1, ..., AN
1793 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1794 }
1795 case TargetOpcode::G_SHL:
1796 case TargetOpcode::G_LSHR:
1797 case TargetOpcode::G_ASHR:
1798 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1799 case TargetOpcode::G_CTLZ:
1800 case TargetOpcode::G_CTLZ_ZERO_POISON:
1801 case TargetOpcode::G_CTTZ:
1802 case TargetOpcode::G_CTTZ_ZERO_POISON:
1803 case TargetOpcode::G_CTLS:
1804 case TargetOpcode::G_CTPOP:
1805 if (TypeIdx == 1)
1806 switch (MI.getOpcode()) {
1807 case TargetOpcode::G_CTLZ:
1808 case TargetOpcode::G_CTLZ_ZERO_POISON:
1809 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1810 case TargetOpcode::G_CTTZ:
1811 case TargetOpcode::G_CTTZ_ZERO_POISON:
1812 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1813 case TargetOpcode::G_CTPOP:
1814 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1815 case TargetOpcode::G_CTLS:
1816 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1817 default:
1818 return UnableToLegalize;
1819 }
1820
1821 Observer.changingInstr(MI);
1822 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1823 Observer.changedInstr(MI);
1824 return Legalized;
1825 case TargetOpcode::G_INTTOPTR:
1826 if (TypeIdx != 1)
1827 return UnableToLegalize;
1828
1829 Observer.changingInstr(MI);
1830 narrowScalarSrc(MI, NarrowTy, 1);
1831 Observer.changedInstr(MI);
1832 return Legalized;
1833 case TargetOpcode::G_PTRTOINT:
1834 if (TypeIdx != 0)
1835 return UnableToLegalize;
1836
1837 Observer.changingInstr(MI);
1838 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1839 Observer.changedInstr(MI);
1840 return Legalized;
1841 case TargetOpcode::G_PHI: {
1842 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1843 // NarrowSize.
1844 if (SizeOp0 % NarrowSize != 0)
1845 return UnableToLegalize;
1846
1847 unsigned NumParts = SizeOp0 / NarrowSize;
1848 SmallVector<Register, 2> DstRegs(NumParts);
1849 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1850 Observer.changingInstr(MI);
1851 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1852 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1853 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1854 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1855 SrcRegs[i / 2], MIRBuilder, MRI);
1856 }
1857 MachineBasicBlock &MBB = *MI.getParent();
1858 MIRBuilder.setInsertPt(MBB, MI);
1859 for (unsigned i = 0; i < NumParts; ++i) {
1860 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1862 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1863 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1864 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1865 }
1866 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1867 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1868 Observer.changedInstr(MI);
1869 MI.eraseFromParent();
1870 return Legalized;
1871 }
1872 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1873 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1874 if (TypeIdx != 2)
1875 return UnableToLegalize;
1876
1877 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1878 Observer.changingInstr(MI);
1879 narrowScalarSrc(MI, NarrowTy, OpIdx);
1880 Observer.changedInstr(MI);
1881 return Legalized;
1882 }
1883 case TargetOpcode::G_ICMP: {
1884 Register LHS = MI.getOperand(2).getReg();
1885 LLT SrcTy = MRI.getType(LHS);
1886 CmpInst::Predicate Pred =
1887 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1888
1889 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1890 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1891 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1892 LHSLeftoverRegs, MIRBuilder, MRI))
1893 return UnableToLegalize;
1894
1895 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1896 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1897 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1898 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1899 return UnableToLegalize;
1900
1901 // We now have the LHS and RHS of the compare split into narrow-type
1902 // registers, plus potentially some leftover type.
1903 Register Dst = MI.getOperand(0).getReg();
1904 LLT ResTy = MRI.getType(Dst);
1905 if (ICmpInst::isEquality(Pred)) {
1906 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1907 // them together. For each equal part, the result should be all 0s. For
1908 // each non-equal part, we'll get at least one 1.
1909 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1911 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1912 auto LHS = std::get<0>(LHSAndRHS);
1913 auto RHS = std::get<1>(LHSAndRHS);
1914 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1915 Xors.push_back(Xor);
1916 }
1917
1918 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1919 // to the desired narrow type so that we can OR them together later.
1920 SmallVector<Register, 4> WidenedXors;
1921 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1922 auto LHS = std::get<0>(LHSAndRHS);
1923 auto RHS = std::get<1>(LHSAndRHS);
1924 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1925 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1926 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1927 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1928 llvm::append_range(Xors, WidenedXors);
1929 }
1930
1931 // Now, for each part we broke up, we know if they are equal/not equal
1932 // based off the G_XOR. We can OR these all together and compare against
1933 // 0 to get the result.
1934 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1935 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1936 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1937 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1938 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1939 } else {
1940 Register CmpIn;
1941 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1942 Register CmpOut;
1943 CmpInst::Predicate PartPred;
1944
1945 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1946 PartPred = Pred;
1947 CmpOut = Dst;
1948 } else {
1949 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1950 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1951 }
1952
1953 if (!CmpIn) {
1954 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1955 RHSPartRegs[I]);
1956 } else {
1957 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1958 RHSPartRegs[I]);
1959 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1960 LHSPartRegs[I], RHSPartRegs[I]);
1961 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1962 }
1963
1964 CmpIn = CmpOut;
1965 }
1966
1967 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1968 Register CmpOut;
1969 CmpInst::Predicate PartPred;
1970
1971 if (I == E - 1) {
1972 PartPred = Pred;
1973 CmpOut = Dst;
1974 } else {
1975 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1976 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1977 }
1978
1979 if (!CmpIn) {
1980 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1981 RHSLeftoverRegs[I]);
1982 } else {
1983 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1984 RHSLeftoverRegs[I]);
1985 auto CmpEq =
1986 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1987 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1988 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1989 }
1990
1991 CmpIn = CmpOut;
1992 }
1993 }
1994 MI.eraseFromParent();
1995 return Legalized;
1996 }
1997 case TargetOpcode::G_FCMP:
1998 if (TypeIdx != 0)
1999 return UnableToLegalize;
2000
2001 Observer.changingInstr(MI);
2002 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
2003 Observer.changedInstr(MI);
2004 return Legalized;
2005
2006 case TargetOpcode::G_SEXT_INREG: {
2007 if (TypeIdx != 0)
2008 return UnableToLegalize;
2009
2010 int64_t SizeInBits = MI.getOperand(2).getImm();
2011
2012 // So long as the new type has more bits than the bits we're extending we
2013 // don't need to break it apart.
2014 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2015 Observer.changingInstr(MI);
2016 // We don't lose any non-extension bits by truncating the src and
2017 // sign-extending the dst.
2018 MachineOperand &MO1 = MI.getOperand(1);
2019 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2020 MO1.setReg(TruncMIB.getReg(0));
2021
2022 MachineOperand &MO2 = MI.getOperand(0);
2023 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2024 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2025 MIRBuilder.buildSExt(MO2, DstExt);
2026 MO2.setReg(DstExt);
2027 Observer.changedInstr(MI);
2028 return Legalized;
2029 }
2030
2031 // Break it apart. Components below the extension point are unmodified. The
2032 // component containing the extension point becomes a narrower SEXT_INREG.
2033 // Components above it are ashr'd from the component containing the
2034 // extension point.
2035 if (SizeOp0 % NarrowSize != 0)
2036 return UnableToLegalize;
2037 int NumParts = SizeOp0 / NarrowSize;
2038
2039 // List the registers where the destination will be scattered.
2041 // List the registers where the source will be split.
2043
2044 // Create all the temporary registers.
2045 for (int i = 0; i < NumParts; ++i) {
2046 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2047
2048 SrcRegs.push_back(SrcReg);
2049 }
2050
2051 // Explode the big arguments into smaller chunks.
2052 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2053
2054 Register AshrCstReg =
2055 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2056 .getReg(0);
2057 Register FullExtensionReg;
2058 Register PartialExtensionReg;
2059
2060 // Do the operation on each small part.
2061 for (int i = 0; i < NumParts; ++i) {
2062 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2063 DstRegs.push_back(SrcRegs[i]);
2064 PartialExtensionReg = DstRegs.back();
2065 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2066 assert(PartialExtensionReg &&
2067 "Expected to visit partial extension before full");
2068 if (FullExtensionReg) {
2069 DstRegs.push_back(FullExtensionReg);
2070 continue;
2071 }
2072 DstRegs.push_back(
2073 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2074 .getReg(0));
2075 FullExtensionReg = DstRegs.back();
2076 } else {
2077 DstRegs.push_back(
2079 .buildInstr(
2080 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2081 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2082 .getReg(0));
2083 PartialExtensionReg = DstRegs.back();
2084 }
2085 }
2086
2087 // Gather the destination registers into the final destination.
2088 Register DstReg = MI.getOperand(0).getReg();
2089 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2090 MI.eraseFromParent();
2091 return Legalized;
2092 }
2093 case TargetOpcode::G_BSWAP:
2094 case TargetOpcode::G_BITREVERSE: {
2095 if (SizeOp0 % NarrowSize != 0)
2096 return UnableToLegalize;
2097
2098 Observer.changingInstr(MI);
2099 SmallVector<Register, 2> SrcRegs, DstRegs;
2100 unsigned NumParts = SizeOp0 / NarrowSize;
2101 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2102 MIRBuilder, MRI);
2103
2104 for (unsigned i = 0; i < NumParts; ++i) {
2105 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2106 {SrcRegs[NumParts - 1 - i]});
2107 DstRegs.push_back(DstPart.getReg(0));
2108 }
2109
2110 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2111
2112 Observer.changedInstr(MI);
2113 MI.eraseFromParent();
2114 return Legalized;
2115 }
2116 case TargetOpcode::G_PTR_ADD:
2117 case TargetOpcode::G_PTRMASK: {
2118 if (TypeIdx != 1)
2119 return UnableToLegalize;
2120 Observer.changingInstr(MI);
2121 narrowScalarSrc(MI, NarrowTy, 2);
2122 Observer.changedInstr(MI);
2123 return Legalized;
2124 }
2125 case TargetOpcode::G_FPTOUI:
2126 case TargetOpcode::G_FPTOSI:
2127 case TargetOpcode::G_FPTOUI_SAT:
2128 case TargetOpcode::G_FPTOSI_SAT:
2129 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2130 case TargetOpcode::G_FPEXT:
2131 if (TypeIdx != 0)
2132 return UnableToLegalize;
2133 Observer.changingInstr(MI);
2134 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2135 Observer.changedInstr(MI);
2136 return Legalized;
2137 case TargetOpcode::G_FLDEXP:
2138 case TargetOpcode::G_STRICT_FLDEXP:
2139 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2140 case TargetOpcode::G_VSCALE: {
2141 Register Dst = MI.getOperand(0).getReg();
2142 LLT Ty = MRI.getType(Dst);
2143
2144 // Assume VSCALE(1) fits into a legal integer
2145 const APInt One(NarrowTy.getSizeInBits(), 1);
2146 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2147 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2148 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2149 MIRBuilder.buildMul(Dst, ZExt, C);
2150
2151 MI.eraseFromParent();
2152 return Legalized;
2153 }
2154 }
2155}
2156
2158 LLT Ty = MRI.getType(Val);
2159 if (Ty.isScalar() && !Ty.isFloat())
2160 return Val;
2161
2162 const DataLayout &DL = MIRBuilder.getDataLayout();
2163 LLT NewTy = LLT::integer(Ty.getSizeInBits());
2164
2165 if (Ty.isFloat())
2166 return MIRBuilder.buildBitcast(NewTy, Val).getReg(0);
2167
2168 if (Ty.isPointer()) {
2169 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2170 return Register();
2171 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2172 }
2173
2174 Register NewVal = Val;
2175
2176 assert(Ty.isVector());
2177 if (Ty.isPointerVector())
2178 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2179 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2180}
2181
2183 unsigned OpIdx, unsigned ExtOpcode) {
2184 MachineOperand &MO = MI.getOperand(OpIdx);
2185 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2186 MO.setReg(ExtB.getReg(0));
2187}
2188
2190 unsigned OpIdx) {
2191 MachineOperand &MO = MI.getOperand(OpIdx);
2192 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2193 MI.getFlags());
2194 MO.setReg(ExtB.getReg(0));
2195}
2196
2198 unsigned OpIdx) {
2199 MachineOperand &MO = MI.getOperand(OpIdx);
2200 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2201 MO.setReg(ExtB.getReg(0));
2202}
2203
2205 unsigned OpIdx, unsigned TruncOpcode) {
2206 MachineOperand &MO = MI.getOperand(OpIdx);
2207 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2208 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2209 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2210 MO.setReg(DstExt);
2211}
2212
2214 unsigned OpIdx) {
2215 MachineOperand &MO = MI.getOperand(OpIdx);
2216 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2217 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2218 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2219 MO.setReg(DstExt);
2220}
2221
2223 unsigned OpIdx, unsigned ExtOpcode) {
2224 MachineOperand &MO = MI.getOperand(OpIdx);
2225 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2226 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2227 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2228 MO.setReg(DstTrunc);
2229}
2230
2232 unsigned OpIdx) {
2233 MachineOperand &MO = MI.getOperand(OpIdx);
2234 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2235 Register Dst = MO.getReg();
2236 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2237 MO.setReg(DstExt);
2238 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2239}
2240
2242 unsigned OpIdx) {
2243 MachineOperand &MO = MI.getOperand(OpIdx);
2244 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2245}
2246
2247void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2248 MachineOperand &Op = MI.getOperand(OpIdx);
2249 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2250}
2251
2252void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2253 MachineOperand &MO = MI.getOperand(OpIdx);
2254 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2255 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2256 MIRBuilder.buildBitcast(MO, CastDst);
2257 MO.setReg(CastDst);
2258}
2259
2261LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2262 LLT WideTy) {
2263 if (TypeIdx != 1)
2264 return UnableToLegalize;
2265
2266 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2267 if (DstTy.isVector())
2268 return UnableToLegalize;
2269
2270 LLT SrcTy = MRI.getType(Src1Reg);
2271 const int DstSize = DstTy.getSizeInBits();
2272 const int SrcSize = SrcTy.getSizeInBits();
2273 const int WideSize = WideTy.getSizeInBits();
2274 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2275
2276 unsigned NumOps = MI.getNumOperands();
2277 unsigned NumSrc = MI.getNumOperands() - 1;
2278 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2279
2280 if (WideSize >= DstSize) {
2281 // Directly pack the bits in the target type.
2282 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2283
2284 for (unsigned I = 2; I != NumOps; ++I) {
2285 const unsigned Offset = (I - 1) * PartSize;
2286
2287 Register SrcReg = MI.getOperand(I).getReg();
2288 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2289
2290 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2291
2292 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2293 MRI.createGenericVirtualRegister(WideTy);
2294
2295 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2296 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2297 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2298 ResultReg = NextResult;
2299 }
2300
2301 if (WideSize > DstSize)
2302 MIRBuilder.buildTrunc(DstReg, ResultReg);
2303 else if (DstTy.isPointer())
2304 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2305 else if (DstTy != WideTy)
2306 MIRBuilder.buildBitcast(DstReg, ResultReg);
2307
2308 MI.eraseFromParent();
2309 return Legalized;
2310 }
2311
2312 // Unmerge the original values to the GCD type, and recombine to the next
2313 // multiple greater than the original type.
2314 //
2315 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2316 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2317 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2318 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2319 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2320 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2321 // %12:_(s12) = G_MERGE_VALUES %10, %11
2322 //
2323 // Padding with undef if necessary:
2324 //
2325 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2326 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2327 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2328 // %7:_(s2) = G_IMPLICIT_DEF
2329 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2330 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2331 // %10:_(s12) = G_MERGE_VALUES %8, %9
2332
2333 const int GCD = std::gcd(SrcSize, WideSize);
2334 LLT GCDTy = WideTy.changeElementSize(GCD);
2335
2336 SmallVector<Register, 8> NewMergeRegs;
2337 SmallVector<Register, 8> Unmerges;
2338 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2339
2340 // Decompose the original operands if they don't evenly divide.
2341 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2342 Register SrcReg = MO.getReg();
2343 if (GCD == SrcSize) {
2344 Unmerges.push_back(SrcReg);
2345 } else {
2346 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2347 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2348 Unmerges.push_back(Unmerge.getReg(J));
2349 }
2350 }
2351
2352 // Pad with undef to the next size that is a multiple of the requested size.
2353 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2354 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2355 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2356 Unmerges.push_back(UndefReg);
2357 }
2358
2359 const int PartsPerGCD = WideSize / GCD;
2360
2361 // Build merges of each piece.
2362 ArrayRef<Register> Slicer(Unmerges);
2363 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2364 auto Merge =
2365 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2366 NewMergeRegs.push_back(Merge.getReg(0));
2367 }
2368
2369 // A truncate may be necessary if the requested type doesn't evenly divide the
2370 // original result type.
2371 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2372 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2373 } else {
2374 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2375 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2376 }
2377
2378 MI.eraseFromParent();
2379 return Legalized;
2380}
2381
2383LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2384 LLT WideTy) {
2385 if (TypeIdx != 0)
2386 return UnableToLegalize;
2387
2388 int NumDst = MI.getNumOperands() - 1;
2389 Register SrcReg = MI.getOperand(NumDst).getReg();
2390 LLT SrcTy = MRI.getType(SrcReg);
2391 if (SrcTy.isVector())
2392 return UnableToLegalize;
2393
2394 Register Dst0Reg = MI.getOperand(0).getReg();
2395 LLT DstTy = MRI.getType(Dst0Reg);
2396 if (!DstTy.isScalar())
2397 return UnableToLegalize;
2398
2399 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2400 if (SrcTy.isPointer()) {
2401 const DataLayout &DL = MIRBuilder.getDataLayout();
2402 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2403 LLVM_DEBUG(
2404 dbgs() << "Not casting non-integral address space integer\n");
2405 return UnableToLegalize;
2406 }
2407
2408 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2409 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2410 }
2411
2412 // Widen SrcTy to WideTy. This does not affect the result, but since the
2413 // user requested this size, it is probably better handled than SrcTy and
2414 // should reduce the total number of legalization artifacts.
2415 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2416 SrcTy = WideTy;
2417 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2418 }
2419
2420 // Theres no unmerge type to target. Directly extract the bits from the
2421 // source type
2422 unsigned DstSize = DstTy.getSizeInBits();
2423
2424 if (SrcTy.isFloat()) {
2425 SrcReg = coerceToInteger(SrcReg);
2426 SrcTy = MRI.getType(SrcReg);
2427 }
2428
2429 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2430 for (int I = 1; I != NumDst; ++I) {
2431 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2432 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2433 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2434 }
2435
2436 MI.eraseFromParent();
2437 return Legalized;
2438 }
2439
2440 // Extend the source to a wider type.
2441 LLT LCMTy = getLCMType(SrcTy, WideTy);
2442
2443 Register WideSrc = SrcReg;
2444 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2445 // TODO: If this is an integral address space, cast to integer and anyext.
2446 if (SrcTy.isPointer()) {
2447 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2448 return UnableToLegalize;
2449 }
2450
2451 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2452 }
2453
2454 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2455
2456 // Create a sequence of unmerges and merges to the original results. Since we
2457 // may have widened the source, we will need to pad the results with dead defs
2458 // to cover the source register.
2459 // e.g. widen s48 to s64:
2460 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2461 //
2462 // =>
2463 // %4:_(s192) = G_ANYEXT %0:_(s96)
2464 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2465 // ; unpack to GCD type, with extra dead defs
2466 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2467 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2468 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2469 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2470 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2471 const LLT GCDTy = getGCDType(WideTy, DstTy);
2472 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2473 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2474
2475 // Directly unmerge to the destination without going through a GCD type
2476 // if possible
2477 if (PartsPerRemerge == 1) {
2478 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2479
2480 for (int I = 0; I != NumUnmerge; ++I) {
2481 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2482
2483 for (int J = 0; J != PartsPerUnmerge; ++J) {
2484 int Idx = I * PartsPerUnmerge + J;
2485 if (Idx < NumDst)
2486 MIB.addDef(MI.getOperand(Idx).getReg());
2487 else {
2488 // Create dead def for excess components.
2489 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2490 }
2491 }
2492
2493 MIB.addUse(Unmerge.getReg(I));
2494 }
2495 } else {
2496 SmallVector<Register, 16> Parts;
2497 for (int J = 0; J != NumUnmerge; ++J)
2498 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2499
2500 SmallVector<Register, 8> RemergeParts;
2501 for (int I = 0; I != NumDst; ++I) {
2502 for (int J = 0; J < PartsPerRemerge; ++J) {
2503 const int Idx = I * PartsPerRemerge + J;
2504 RemergeParts.emplace_back(Parts[Idx]);
2505 }
2506
2507 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2508 RemergeParts.clear();
2509 }
2510 }
2511
2512 MI.eraseFromParent();
2513 return Legalized;
2514}
2515
2517LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2518 LLT WideTy) {
2519 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2520 unsigned Offset = MI.getOperand(2).getImm();
2521
2522 if (TypeIdx == 0) {
2523 if (SrcTy.isVector() || DstTy.isVector())
2524 return UnableToLegalize;
2525
2526 SrcOp Src(SrcReg);
2527 if (SrcTy.isPointer()) {
2528 // Extracts from pointers can be handled only if they are really just
2529 // simple integers.
2530 const DataLayout &DL = MIRBuilder.getDataLayout();
2531 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2532 return UnableToLegalize;
2533
2534 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2535 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2536 SrcTy = SrcAsIntTy;
2537 }
2538
2539 if (DstTy.isPointer())
2540 return UnableToLegalize;
2541
2542 if (Offset == 0) {
2543 // Avoid a shift in the degenerate case.
2544 MIRBuilder.buildTrunc(DstReg,
2545 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2546 MI.eraseFromParent();
2547 return Legalized;
2548 }
2549
2550 // Do a shift in the source type.
2551 LLT ShiftTy = SrcTy;
2552 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2553 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2554 ShiftTy = WideTy;
2555 }
2556
2557 auto LShr = MIRBuilder.buildLShr(
2558 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2559 MIRBuilder.buildTrunc(DstReg, LShr);
2560 MI.eraseFromParent();
2561 return Legalized;
2562 }
2563
2564 if (SrcTy.isScalar()) {
2565 Observer.changingInstr(MI);
2566 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2567 Observer.changedInstr(MI);
2568 return Legalized;
2569 }
2570
2571 if (!SrcTy.isVector())
2572 return UnableToLegalize;
2573
2574 if (DstTy != SrcTy.getElementType())
2575 return UnableToLegalize;
2576
2577 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2578 return UnableToLegalize;
2579
2580 Observer.changingInstr(MI);
2581 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2582
2583 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2584 Offset);
2585 widenScalarDst(MI, WideTy.getScalarType(), 0);
2586 Observer.changedInstr(MI);
2587 return Legalized;
2588}
2589
2591LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2592 LLT WideTy) {
2593 if (TypeIdx != 0 || WideTy.isVector())
2594 return UnableToLegalize;
2595 Observer.changingInstr(MI);
2596 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2597 widenScalarDst(MI, WideTy);
2598 Observer.changedInstr(MI);
2599 return Legalized;
2600}
2601
2603LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2604 LLT WideTy) {
2605 unsigned Opcode;
2606 unsigned ExtOpcode;
2607 std::optional<Register> CarryIn;
2608 switch (MI.getOpcode()) {
2609 default:
2610 llvm_unreachable("Unexpected opcode!");
2611 case TargetOpcode::G_SADDO:
2612 Opcode = TargetOpcode::G_ADD;
2613 ExtOpcode = TargetOpcode::G_SEXT;
2614 break;
2615 case TargetOpcode::G_SSUBO:
2616 Opcode = TargetOpcode::G_SUB;
2617 ExtOpcode = TargetOpcode::G_SEXT;
2618 break;
2619 case TargetOpcode::G_UADDO:
2620 Opcode = TargetOpcode::G_ADD;
2621 ExtOpcode = TargetOpcode::G_ZEXT;
2622 break;
2623 case TargetOpcode::G_USUBO:
2624 Opcode = TargetOpcode::G_SUB;
2625 ExtOpcode = TargetOpcode::G_ZEXT;
2626 break;
2627 case TargetOpcode::G_SADDE:
2628 Opcode = TargetOpcode::G_UADDE;
2629 ExtOpcode = TargetOpcode::G_SEXT;
2630 CarryIn = MI.getOperand(4).getReg();
2631 break;
2632 case TargetOpcode::G_SSUBE:
2633 Opcode = TargetOpcode::G_USUBE;
2634 ExtOpcode = TargetOpcode::G_SEXT;
2635 CarryIn = MI.getOperand(4).getReg();
2636 break;
2637 case TargetOpcode::G_UADDE:
2638 Opcode = TargetOpcode::G_UADDE;
2639 ExtOpcode = TargetOpcode::G_ZEXT;
2640 CarryIn = MI.getOperand(4).getReg();
2641 break;
2642 case TargetOpcode::G_USUBE:
2643 Opcode = TargetOpcode::G_USUBE;
2644 ExtOpcode = TargetOpcode::G_ZEXT;
2645 CarryIn = MI.getOperand(4).getReg();
2646 break;
2647 }
2648
2649 if (TypeIdx == 1) {
2650 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2651
2652 Observer.changingInstr(MI);
2653 if (CarryIn)
2654 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2655 widenScalarDst(MI, WideTy, 1);
2656
2657 Observer.changedInstr(MI);
2658 return Legalized;
2659 }
2660
2661 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2662 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2663 // Do the arithmetic in the larger type.
2664 Register NewOp;
2665 if (CarryIn) {
2666 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2667 NewOp = MIRBuilder
2668 .buildInstr(Opcode, {WideTy, CarryOutTy},
2669 {LHSExt, RHSExt, *CarryIn})
2670 .getReg(0);
2671 } else {
2672 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2673 }
2674 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2675 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2676 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2677 // There is no overflow if the ExtOp is the same as NewOp.
2678 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2679 // Now trunc the NewOp to the original result.
2680 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2681 MI.eraseFromParent();
2682 return Legalized;
2683}
2684
2686LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2687 LLT WideTy) {
2688 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2689 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2690 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2691 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2692 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2693 // We can convert this to:
2694 // 1. Any extend iN to iM
2695 // 2. SHL by M-N
2696 // 3. [US][ADD|SUB|SHL]SAT
2697 // 4. L/ASHR by M-N
2698 //
2699 // It may be more efficient to lower this to a min and a max operation in
2700 // the higher precision arithmetic if the promoted operation isn't legal,
2701 // but this decision is up to the target's lowering request.
2702 Register DstReg = MI.getOperand(0).getReg();
2703
2704 unsigned NewBits = WideTy.getScalarSizeInBits();
2705 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2706
2707 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2708 // must not left shift the RHS to preserve the shift amount.
2709 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2710 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2711 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2712 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2713 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2714 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2715
2716 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2717 {ShiftL, ShiftR}, MI.getFlags());
2718
2719 // Use a shift that will preserve the number of sign bits when the trunc is
2720 // folded away.
2721 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2722 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2723
2724 MIRBuilder.buildTrunc(DstReg, Result);
2725 MI.eraseFromParent();
2726 return Legalized;
2727}
2728
2730LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2731 LLT WideTy) {
2732 if (TypeIdx == 1) {
2733 Observer.changingInstr(MI);
2734 widenScalarDst(MI, WideTy, 1);
2735 Observer.changedInstr(MI);
2736 return Legalized;
2737 }
2738
2739 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2740 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2741 LLT SrcTy = MRI.getType(LHS);
2742 LLT OverflowTy = MRI.getType(OriginalOverflow);
2743 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2744
2745 // To determine if the result overflowed in the larger type, we extend the
2746 // input to the larger type, do the multiply (checking if it overflows),
2747 // then also check the high bits of the result to see if overflow happened
2748 // there.
2749 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2750 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2751 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2752
2753 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2754 // so we don't need to check the overflow result of larger type Mulo.
2755 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2756
2757 unsigned MulOpc =
2758 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2759
2760 MachineInstrBuilder Mulo;
2761 if (WideMulCanOverflow)
2762 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2763 {LeftOperand, RightOperand});
2764 else
2765 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2766
2767 auto Mul = Mulo->getOperand(0);
2768 MIRBuilder.buildTrunc(Result, Mul);
2769
2770 MachineInstrBuilder ExtResult;
2771 // Overflow occurred if it occurred in the larger type, or if the high part
2772 // of the result does not zero/sign-extend the low part. Check this second
2773 // possibility first.
2774 if (IsSigned) {
2775 // For signed, overflow occurred when the high part does not sign-extend
2776 // the low part.
2777 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2778 } else {
2779 // Unsigned overflow occurred when the high part does not zero-extend the
2780 // low part.
2781 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2782 }
2783
2784 if (WideMulCanOverflow) {
2785 auto Overflow =
2786 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2787 // Finally check if the multiplication in the larger type itself overflowed.
2788 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2789 } else {
2790 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2791 }
2792 MI.eraseFromParent();
2793 return Legalized;
2794}
2795
2798 unsigned Opcode = MI.getOpcode();
2799 switch (Opcode) {
2800 default:
2801 return UnableToLegalize;
2802 case TargetOpcode::G_ATOMICRMW_XCHG:
2803 case TargetOpcode::G_ATOMICRMW_ADD:
2804 case TargetOpcode::G_ATOMICRMW_SUB:
2805 case TargetOpcode::G_ATOMICRMW_AND:
2806 case TargetOpcode::G_ATOMICRMW_OR:
2807 case TargetOpcode::G_ATOMICRMW_XOR:
2808 case TargetOpcode::G_ATOMICRMW_MIN:
2809 case TargetOpcode::G_ATOMICRMW_MAX:
2810 case TargetOpcode::G_ATOMICRMW_UMIN:
2811 case TargetOpcode::G_ATOMICRMW_UMAX:
2812 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2813 Observer.changingInstr(MI);
2814 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2815 widenScalarDst(MI, WideTy, 0);
2816 Observer.changedInstr(MI);
2817 return Legalized;
2818 case TargetOpcode::G_ATOMIC_CMPXCHG:
2819 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2820 Observer.changingInstr(MI);
2821 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2822 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2823 widenScalarDst(MI, WideTy, 0);
2824 Observer.changedInstr(MI);
2825 return Legalized;
2826 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2827 if (TypeIdx == 0) {
2828 Observer.changingInstr(MI);
2829 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2830 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2831 widenScalarDst(MI, WideTy, 0);
2832 Observer.changedInstr(MI);
2833 return Legalized;
2834 }
2835 assert(TypeIdx == 1 &&
2836 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2837 Observer.changingInstr(MI);
2838 widenScalarDst(MI, WideTy, 1);
2839 Observer.changedInstr(MI);
2840 return Legalized;
2841 case TargetOpcode::G_EXTRACT:
2842 return widenScalarExtract(MI, TypeIdx, WideTy);
2843 case TargetOpcode::G_INSERT:
2844 return widenScalarInsert(MI, TypeIdx, WideTy);
2845 case TargetOpcode::G_MERGE_VALUES:
2846 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2847 case TargetOpcode::G_UNMERGE_VALUES:
2848 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2849 case TargetOpcode::G_SADDO:
2850 case TargetOpcode::G_SSUBO:
2851 case TargetOpcode::G_UADDO:
2852 case TargetOpcode::G_USUBO:
2853 case TargetOpcode::G_SADDE:
2854 case TargetOpcode::G_SSUBE:
2855 case TargetOpcode::G_UADDE:
2856 case TargetOpcode::G_USUBE:
2857 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2858 case TargetOpcode::G_UMULO:
2859 case TargetOpcode::G_SMULO:
2860 return widenScalarMulo(MI, TypeIdx, WideTy);
2861 case TargetOpcode::G_SADDSAT:
2862 case TargetOpcode::G_SSUBSAT:
2863 case TargetOpcode::G_SSHLSAT:
2864 case TargetOpcode::G_UADDSAT:
2865 case TargetOpcode::G_USUBSAT:
2866 case TargetOpcode::G_USHLSAT:
2867 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2868 case TargetOpcode::G_CTTZ:
2869 case TargetOpcode::G_CTTZ_ZERO_POISON:
2870 case TargetOpcode::G_CTLZ:
2871 case TargetOpcode::G_CTLZ_ZERO_POISON:
2872 case TargetOpcode::G_CTLS:
2873 case TargetOpcode::G_CTPOP: {
2874 if (TypeIdx == 0) {
2875 Observer.changingInstr(MI);
2876 widenScalarDst(MI, WideTy, 0);
2877 Observer.changedInstr(MI);
2878 return Legalized;
2879 }
2880
2881 Register SrcReg = MI.getOperand(1).getReg();
2882
2883 // First extend the input.
2884 unsigned ExtOpc;
2885 switch (Opcode) {
2886 case TargetOpcode::G_CTTZ:
2887 case TargetOpcode::G_CTTZ_ZERO_POISON:
2888 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2889 ExtOpc = TargetOpcode::G_ANYEXT;
2890 break;
2891 case TargetOpcode::G_CTLS:
2892 ExtOpc = TargetOpcode::G_SEXT;
2893 break;
2894 default:
2895 ExtOpc = TargetOpcode::G_ZEXT;
2896 }
2897
2898 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2899 LLT CurTy = MRI.getType(SrcReg);
2900 unsigned NewOpc = Opcode;
2901 if (NewOpc == TargetOpcode::G_CTTZ) {
2902 // The count is the same in the larger type except if the original
2903 // value was zero. This can be handled by setting the bit just off
2904 // the top of the original type.
2905 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2906 CurTy.getScalarSizeInBits());
2907 MIBSrc = MIRBuilder.buildOr(
2908 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2909 // Now we know the operand is non-zero, use the more relaxed opcode.
2910 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2911 }
2912
2913 unsigned SizeDiff =
2914 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2915
2916 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2917 // An optimization where the result is the CTLZ after the left shift by
2918 // (Difference in widety and current ty), that is,
2919 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2920 // Result = ctlz MIBSrc
2921 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2922 MIRBuilder.buildConstant(WideTy, SizeDiff));
2923 }
2924
2925 // Perform the operation at the larger size.
2926 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2927 // This is already the correct result for CTPOP and CTTZs
2928 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2929 // The correct result is NewOp - (Difference in widety and current ty).
2930 // At this stage SUB is guaranteed to be positive no-wrap,
2931 // that to be used in further KnownBits optimizations for CTLZ.
2932 MIBNewOp = MIRBuilder.buildSub(
2933 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2934 Opcode == TargetOpcode::G_CTLZ
2935 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2936 : std::nullopt);
2937 }
2938
2939 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2940 MI.eraseFromParent();
2941 return Legalized;
2942 }
2943 case TargetOpcode::G_BSWAP: {
2944 Observer.changingInstr(MI);
2945 Register DstReg = MI.getOperand(0).getReg();
2946
2947 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2948 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2949 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2950 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2951
2952 MI.getOperand(0).setReg(DstExt);
2953
2954 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2955
2956 LLT Ty = MRI.getType(DstReg);
2957 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2958 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2959 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2960
2961 MIRBuilder.buildTrunc(DstReg, ShrReg);
2962 Observer.changedInstr(MI);
2963 return Legalized;
2964 }
2965 case TargetOpcode::G_BITREVERSE: {
2966 Observer.changingInstr(MI);
2967
2968 Register DstReg = MI.getOperand(0).getReg();
2969 LLT Ty = MRI.getType(DstReg);
2970 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2971
2972 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2973 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2974 MI.getOperand(0).setReg(DstExt);
2975 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2976
2977 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2978 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2979 MIRBuilder.buildTrunc(DstReg, Shift);
2980 Observer.changedInstr(MI);
2981 return Legalized;
2982 }
2983 case TargetOpcode::G_FREEZE:
2984 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2985 Observer.changingInstr(MI);
2986 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2987 widenScalarDst(MI, WideTy);
2988 Observer.changedInstr(MI);
2989 return Legalized;
2990
2991 case TargetOpcode::G_ABS:
2992 Observer.changingInstr(MI);
2993 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2994 widenScalarDst(MI, WideTy);
2995 Observer.changedInstr(MI);
2996 return Legalized;
2997
2998 case TargetOpcode::G_ADD:
2999 case TargetOpcode::G_AND:
3000 case TargetOpcode::G_MUL:
3001 case TargetOpcode::G_OR:
3002 case TargetOpcode::G_XOR:
3003 case TargetOpcode::G_SUB:
3004 case TargetOpcode::G_SHUFFLE_VECTOR:
3005 // Perform operation at larger width (any extension is fines here, high bits
3006 // don't affect the result) and then truncate the result back to the
3007 // original type.
3008 Observer.changingInstr(MI);
3009 // The G_ANYEXTs below leave the new high bits unconstrained, so no-wrap and
3010 // disjoint claims proved at the narrow width no longer hold. Paths that
3011 // widen with value-preserving G_ZEXT/G_SEXT keep their flags.
3014 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3015 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3016 widenScalarDst(MI, WideTy);
3017 Observer.changedInstr(MI);
3018 return Legalized;
3019
3020 case TargetOpcode::G_SBFX:
3021 case TargetOpcode::G_UBFX:
3022 Observer.changingInstr(MI);
3023
3024 if (TypeIdx == 0) {
3025 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3026 widenScalarDst(MI, WideTy);
3027 } else {
3028 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3029 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3030 }
3031
3032 Observer.changedInstr(MI);
3033 return Legalized;
3034
3035 case TargetOpcode::G_SHL:
3036 Observer.changingInstr(MI);
3037
3038 if (TypeIdx == 0) {
3039 // Widening the result with G_ANYEXT invalidates the no-wrap flags, as in
3040 // the G_ADD/G_SUB/G_MUL case above. TypeIdx 1 widens only the shift
3041 // amount, which is value-preserving, so it keeps them.
3043 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3044 widenScalarDst(MI, WideTy);
3045 } else {
3046 assert(TypeIdx == 1);
3047 // The "number of bits to shift" operand must preserve its value as an
3048 // unsigned integer:
3049 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3050 }
3051
3052 Observer.changedInstr(MI);
3053 return Legalized;
3054
3055 case TargetOpcode::G_ROTR:
3056 case TargetOpcode::G_ROTL:
3057 if (TypeIdx != 1)
3058 return UnableToLegalize;
3059
3060 Observer.changingInstr(MI);
3061 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3062 Observer.changedInstr(MI);
3063 return Legalized;
3064
3065 case TargetOpcode::G_SDIV:
3066 case TargetOpcode::G_SREM:
3067 case TargetOpcode::G_SMIN:
3068 case TargetOpcode::G_SMAX:
3069 case TargetOpcode::G_ABDS:
3070 Observer.changingInstr(MI);
3071 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3072 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3073 widenScalarDst(MI, WideTy);
3074 Observer.changedInstr(MI);
3075 return Legalized;
3076
3077 case TargetOpcode::G_SDIVREM:
3078 Observer.changingInstr(MI);
3079 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3080 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3081 widenScalarDst(MI, WideTy);
3082 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3083 widenScalarDst(MI, WideTy, 1);
3084 Observer.changedInstr(MI);
3085 return Legalized;
3086
3087 case TargetOpcode::G_ASHR:
3088 case TargetOpcode::G_LSHR:
3089 Observer.changingInstr(MI);
3090
3091 if (TypeIdx == 0) {
3092 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3093 : TargetOpcode::G_ZEXT;
3094
3095 widenScalarSrc(MI, WideTy, 1, CvtOp);
3096 widenScalarDst(MI, WideTy);
3097 } else {
3098 assert(TypeIdx == 1);
3099 // The "number of bits to shift" operand must preserve its value as an
3100 // unsigned integer:
3101 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3102 }
3103
3104 Observer.changedInstr(MI);
3105 return Legalized;
3106 case TargetOpcode::G_UDIV:
3107 case TargetOpcode::G_UREM:
3108 case TargetOpcode::G_ABDU:
3109 Observer.changingInstr(MI);
3110 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3111 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3112 widenScalarDst(MI, WideTy);
3113 Observer.changedInstr(MI);
3114 return Legalized;
3115 case TargetOpcode::G_UDIVREM:
3116 Observer.changingInstr(MI);
3117 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3118 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3119 widenScalarDst(MI, WideTy);
3120 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3121 widenScalarDst(MI, WideTy, 1);
3122 Observer.changedInstr(MI);
3123 return Legalized;
3124 case TargetOpcode::G_UMIN:
3125 case TargetOpcode::G_UMAX: {
3126 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3127
3128 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3129 unsigned ExtOpc =
3130 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3131 getApproximateEVTForLLT(WideTy, Ctx))
3132 ? TargetOpcode::G_SEXT
3133 : TargetOpcode::G_ZEXT;
3134
3135 Observer.changingInstr(MI);
3136 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3137 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3138 widenScalarDst(MI, WideTy);
3139 Observer.changedInstr(MI);
3140 return Legalized;
3141 }
3142
3143 case TargetOpcode::G_SELECT:
3144 Observer.changingInstr(MI);
3145 if (TypeIdx == 0) {
3146 // Perform operation at larger width (any extension is fine here, high
3147 // bits don't affect the result) and then truncate the result back to the
3148 // original type.
3149 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3150 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3151 widenScalarDst(MI, WideTy);
3152 } else {
3153 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3154 // Explicit extension is required here since high bits affect the result.
3155 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3156 }
3157 Observer.changedInstr(MI);
3158 return Legalized;
3159
3160 case TargetOpcode::G_FPEXT:
3161 if (TypeIdx != 1)
3162 return UnableToLegalize;
3163
3164 Observer.changingInstr(MI);
3165 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3166 Observer.changedInstr(MI);
3167 return Legalized;
3168 case TargetOpcode::G_FPTOSI:
3169 case TargetOpcode::G_FPTOUI:
3170 case TargetOpcode::G_INTRINSIC_LRINT:
3171 case TargetOpcode::G_INTRINSIC_LLRINT:
3172 case TargetOpcode::G_IS_FPCLASS:
3173 Observer.changingInstr(MI);
3174
3175 if (TypeIdx == 0)
3176 widenScalarDst(MI, WideTy);
3177 else
3178 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3179
3180 Observer.changedInstr(MI);
3181 return Legalized;
3182 case TargetOpcode::G_SITOFP:
3183 Observer.changingInstr(MI);
3184
3185 if (TypeIdx == 0)
3186 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3187 else
3188 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3189
3190 Observer.changedInstr(MI);
3191 return Legalized;
3192 case TargetOpcode::G_UITOFP:
3193 Observer.changingInstr(MI);
3194
3195 if (TypeIdx == 0)
3196 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3197 else
3198 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3199
3200 Observer.changedInstr(MI);
3201 return Legalized;
3202 case TargetOpcode::G_FPTOSI_SAT:
3203 case TargetOpcode::G_FPTOUI_SAT:
3204 Observer.changingInstr(MI);
3205
3206 if (TypeIdx == 0) {
3207 Register OldDst = MI.getOperand(0).getReg();
3208 LLT Ty = MRI.getType(OldDst);
3209 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3210 Register NewDst;
3211 MI.getOperand(0).setReg(ExtReg);
3212 uint64_t ShortBits = Ty.getScalarSizeInBits();
3213 uint64_t WideBits = WideTy.getScalarSizeInBits();
3214 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3215 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3216 // z = i16 fptosi_sat(a)
3217 // ->
3218 // x = i32 fptosi_sat(a)
3219 // y = smin(x, 32767)
3220 // z = smax(y, -32768)
3221 auto MaxVal = MIRBuilder.buildConstant(
3222 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3223 auto MinVal = MIRBuilder.buildConstant(
3224 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3225 Register MidReg =
3226 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3227 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3228 } else {
3229 // z = i16 fptoui_sat(a)
3230 // ->
3231 // x = i32 fptoui_sat(a)
3232 // y = smin(x, 65535)
3233 auto MaxVal = MIRBuilder.buildConstant(
3234 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3235 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3236 }
3237 MIRBuilder.buildTrunc(OldDst, NewDst);
3238 } else
3239 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3240
3241 Observer.changedInstr(MI);
3242 return Legalized;
3243 case TargetOpcode::G_LOAD:
3244 case TargetOpcode::G_SEXTLOAD:
3245 case TargetOpcode::G_ZEXTLOAD:
3246 case TargetOpcode::G_FPEXTLOAD:
3247 Observer.changingInstr(MI);
3248 widenScalarDst(MI, WideTy);
3249 Observer.changedInstr(MI);
3250 return Legalized;
3251
3252 case TargetOpcode::G_STORE: {
3253 if (TypeIdx != 0)
3254 return UnableToLegalize;
3255
3256 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3257 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3258 if (!Ty.isScalar()) {
3259 // We need to widen the vector element type.
3260 Observer.changingInstr(MI);
3261 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3262 // We also need to adjust the MMO to turn this into a truncating store.
3263 MachineMemOperand &MMO = **MI.memoperands_begin();
3264 MachineFunction &MF = MIRBuilder.getMF();
3265 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3266 MI.setMemRefs(MF, {NewMMO});
3267 Observer.changedInstr(MI);
3268 return Legalized;
3269 }
3270
3271 Observer.changingInstr(MI);
3272
3273 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3274 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3275 widenScalarSrc(MI, WideTy, 0, ExtType);
3276
3277 Observer.changedInstr(MI);
3278 return Legalized;
3279 }
3280 case TargetOpcode::G_FPTRUNCSTORE:
3281 if (TypeIdx != 0)
3282 return UnableToLegalize;
3283 Observer.changingInstr(MI);
3284 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3285 Observer.changedInstr(MI);
3286 return Legalized;
3287 case TargetOpcode::G_CONSTANT: {
3288 MachineOperand &SrcMO = MI.getOperand(1);
3289 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3290 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3291 MRI.getType(MI.getOperand(0).getReg()));
3292 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3293 ExtOpc == TargetOpcode::G_ANYEXT) &&
3294 "Illegal Extend");
3295 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3296 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3297 ? SrcVal.sext(WideTy.getSizeInBits())
3298 : SrcVal.zext(WideTy.getSizeInBits());
3299 Observer.changingInstr(MI);
3300 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3301
3302 widenScalarDst(MI, WideTy);
3303 Observer.changedInstr(MI);
3304 return Legalized;
3305 }
3306 case TargetOpcode::G_FCONSTANT: {
3307 // To avoid changing the bits of the constant due to extension to a larger
3308 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3309 MachineOperand &SrcMO = MI.getOperand(1);
3310 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3311 MIRBuilder.setInstrAndDebugLoc(MI);
3312 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3313 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3314 MI.eraseFromParent();
3315 return Legalized;
3316 }
3317 case TargetOpcode::G_IMPLICIT_DEF: {
3318 Observer.changingInstr(MI);
3319 widenScalarDst(MI, WideTy);
3320 Observer.changedInstr(MI);
3321 return Legalized;
3322 }
3323 case TargetOpcode::G_BRCOND:
3324 Observer.changingInstr(MI);
3325 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3326 Observer.changedInstr(MI);
3327 return Legalized;
3328
3329 case TargetOpcode::G_FCMP:
3330 Observer.changingInstr(MI);
3331 if (TypeIdx == 0)
3332 widenScalarDst(MI, WideTy);
3333 else {
3334 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3335 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3336 }
3337 Observer.changedInstr(MI);
3338 return Legalized;
3339
3340 case TargetOpcode::G_ICMP:
3341 Observer.changingInstr(MI);
3342 if (TypeIdx == 0)
3343 widenScalarDst(MI, WideTy);
3344 else {
3345 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3346 CmpInst::Predicate Pred =
3347 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3348
3349 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3350 unsigned ExtOpcode =
3351 (CmpInst::isSigned(Pred) ||
3352 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3353 getApproximateEVTForLLT(WideTy, Ctx)))
3354 ? TargetOpcode::G_SEXT
3355 : TargetOpcode::G_ZEXT;
3356 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3357 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3358 }
3359 Observer.changedInstr(MI);
3360 return Legalized;
3361
3362 case TargetOpcode::G_PTR_ADD:
3363 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3364 Observer.changingInstr(MI);
3365 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3366 Observer.changedInstr(MI);
3367 return Legalized;
3368
3369 case TargetOpcode::G_PHI: {
3370 assert(TypeIdx == 0 && "Expecting only Idx 0");
3371
3372 Observer.changingInstr(MI);
3373 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3374 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3375 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3376 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3377 }
3378
3379 MachineBasicBlock &MBB = *MI.getParent();
3380 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3381 widenScalarDst(MI, WideTy);
3382 Observer.changedInstr(MI);
3383 return Legalized;
3384 }
3385 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3386 if (TypeIdx == 0) {
3387 Register VecReg = MI.getOperand(1).getReg();
3388 LLT VecTy = MRI.getType(VecReg);
3389 Observer.changingInstr(MI);
3390
3391 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3392 TargetOpcode::G_ANYEXT);
3393
3394 widenScalarDst(MI, WideTy, 0);
3395 Observer.changedInstr(MI);
3396 return Legalized;
3397 }
3398
3399 if (TypeIdx != 2)
3400 return UnableToLegalize;
3401 Observer.changingInstr(MI);
3402 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3403 Observer.changedInstr(MI);
3404 return Legalized;
3405 }
3406 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3407 if (TypeIdx == 0) {
3408 Observer.changingInstr(MI);
3409 const LLT WideEltTy = WideTy.getElementType();
3410
3411 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3412 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3413 widenScalarDst(MI, WideTy, 0);
3414 Observer.changedInstr(MI);
3415 return Legalized;
3416 }
3417
3418 if (TypeIdx == 1) {
3419 Observer.changingInstr(MI);
3420
3421 Register VecReg = MI.getOperand(1).getReg();
3422 LLT VecTy = MRI.getType(VecReg);
3423 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3424
3425 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3426 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3427 widenScalarDst(MI, WideVecTy, 0);
3428 Observer.changedInstr(MI);
3429 return Legalized;
3430 }
3431
3432 if (TypeIdx == 2) {
3433 Observer.changingInstr(MI);
3434 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3435 Observer.changedInstr(MI);
3436 return Legalized;
3437 }
3438
3439 return UnableToLegalize;
3440 }
3441 case TargetOpcode::G_FADD:
3442 case TargetOpcode::G_FMUL:
3443 case TargetOpcode::G_FSUB:
3444 case TargetOpcode::G_FMA:
3445 case TargetOpcode::G_FMAD:
3446 case TargetOpcode::G_FNEG:
3447 case TargetOpcode::G_FABS:
3448 case TargetOpcode::G_FCANONICALIZE:
3449 case TargetOpcode::G_FMINNUM:
3450 case TargetOpcode::G_FMAXNUM:
3451 case TargetOpcode::G_FMINNUM_IEEE:
3452 case TargetOpcode::G_FMAXNUM_IEEE:
3453 case TargetOpcode::G_FMINIMUM:
3454 case TargetOpcode::G_FMAXIMUM:
3455 case TargetOpcode::G_FMINIMUMNUM:
3456 case TargetOpcode::G_FMAXIMUMNUM:
3457 case TargetOpcode::G_FDIV:
3458 case TargetOpcode::G_FREM:
3459 case TargetOpcode::G_FCEIL:
3460 case TargetOpcode::G_FFLOOR:
3461 case TargetOpcode::G_FCOS:
3462 case TargetOpcode::G_FSIN:
3463 case TargetOpcode::G_FTAN:
3464 case TargetOpcode::G_FACOS:
3465 case TargetOpcode::G_FASIN:
3466 case TargetOpcode::G_FATAN:
3467 case TargetOpcode::G_FATAN2:
3468 case TargetOpcode::G_FCOSH:
3469 case TargetOpcode::G_FSINH:
3470 case TargetOpcode::G_FTANH:
3471 case TargetOpcode::G_FLOG10:
3472 case TargetOpcode::G_FLOG:
3473 case TargetOpcode::G_FLOG2:
3474 case TargetOpcode::G_FRINT:
3475 case TargetOpcode::G_FNEARBYINT:
3476 case TargetOpcode::G_FSQRT:
3477 case TargetOpcode::G_FEXP:
3478 case TargetOpcode::G_FEXP2:
3479 case TargetOpcode::G_FEXP10:
3480 case TargetOpcode::G_FPOW:
3481 case TargetOpcode::G_INTRINSIC_TRUNC:
3482 case TargetOpcode::G_INTRINSIC_ROUND:
3483 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3484 assert(TypeIdx == 0);
3485 Observer.changingInstr(MI);
3486
3487 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3488 widenScalarSrcUsingFPExt(MI, WideTy, I);
3489
3490 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3491 Observer.changedInstr(MI);
3492 return Legalized;
3493 case TargetOpcode::G_FMODF: {
3494 Observer.changingInstr(MI);
3495 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3496
3497 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3498 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3499 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3500 Observer.changedInstr(MI);
3501 return Legalized;
3502 }
3503 case TargetOpcode::G_FPOWI:
3504 case TargetOpcode::G_FLDEXP:
3505 case TargetOpcode::G_STRICT_FLDEXP: {
3506 if (TypeIdx == 0) {
3507 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3508 return UnableToLegalize;
3509
3510 Observer.changingInstr(MI);
3511 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3512 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3513 Observer.changedInstr(MI);
3514 return Legalized;
3515 }
3516
3517 if (TypeIdx == 1) {
3518 // For some reason SelectionDAG tries to promote to a libcall without
3519 // actually changing the integer type for promotion.
3520 Observer.changingInstr(MI);
3521 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3522 Observer.changedInstr(MI);
3523 return Legalized;
3524 }
3525
3526 return UnableToLegalize;
3527 }
3528 case TargetOpcode::G_FFREXP: {
3529 Observer.changingInstr(MI);
3530
3531 if (TypeIdx == 0) {
3532 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3533 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3534 } else {
3535 widenScalarDst(MI, WideTy, 1);
3536 }
3537
3538 Observer.changedInstr(MI);
3539 return Legalized;
3540 }
3541 case TargetOpcode::G_LROUND:
3542 case TargetOpcode::G_LLROUND:
3543 Observer.changingInstr(MI);
3544
3545 if (TypeIdx == 0)
3546 widenScalarDst(MI, WideTy);
3547 else
3548 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3549
3550 Observer.changedInstr(MI);
3551 return Legalized;
3552
3553 case TargetOpcode::G_INTTOPTR:
3554 if (TypeIdx != 1)
3555 return UnableToLegalize;
3556
3557 Observer.changingInstr(MI);
3558 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3559 Observer.changedInstr(MI);
3560 return Legalized;
3561 case TargetOpcode::G_PTRTOINT:
3562 if (TypeIdx != 0)
3563 return UnableToLegalize;
3564
3565 Observer.changingInstr(MI);
3566 widenScalarDst(MI, WideTy, 0);
3567 Observer.changedInstr(MI);
3568 return Legalized;
3569 case TargetOpcode::G_BUILD_VECTOR: {
3570 Observer.changingInstr(MI);
3571
3572 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3573 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3574 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3575
3576 // Avoid changing the result vector type if the source element type was
3577 // requested.
3578 if (TypeIdx == 1) {
3579 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3580 } else {
3581 widenScalarDst(MI, WideTy, 0);
3582 }
3583
3584 Observer.changedInstr(MI);
3585 return Legalized;
3586 }
3587 case TargetOpcode::G_SEXT_INREG:
3588 if (TypeIdx != 0)
3589 return UnableToLegalize;
3590
3591 Observer.changingInstr(MI);
3592 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3593 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3594 Observer.changedInstr(MI);
3595 return Legalized;
3596 case TargetOpcode::G_PTRMASK: {
3597 if (TypeIdx != 1)
3598 return UnableToLegalize;
3599 Observer.changingInstr(MI);
3600 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3601 Observer.changedInstr(MI);
3602 return Legalized;
3603 }
3604 case TargetOpcode::G_VECREDUCE_ADD: {
3605 if (TypeIdx != 1)
3606 return UnableToLegalize;
3607 Observer.changingInstr(MI);
3608 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3609 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3610 Observer.changedInstr(MI);
3611 return Legalized;
3612 }
3613 case TargetOpcode::G_VECREDUCE_FADD:
3614 case TargetOpcode::G_VECREDUCE_FMUL:
3615 case TargetOpcode::G_VECREDUCE_FMIN:
3616 case TargetOpcode::G_VECREDUCE_FMAX:
3617 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3618 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3619 if (TypeIdx != 0)
3620 return UnableToLegalize;
3621 Observer.changingInstr(MI);
3622 Register VecReg = MI.getOperand(1).getReg();
3623 LLT VecTy = MRI.getType(VecReg);
3624 LLT WideVecTy = VecTy.changeElementType(WideTy);
3625 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3626 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3627 Observer.changedInstr(MI);
3628 return Legalized;
3629 }
3630 case TargetOpcode::G_VSCALE: {
3631 MachineOperand &SrcMO = MI.getOperand(1);
3632 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3633 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3634 // The CImm is always a signed value
3635 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3636 Observer.changingInstr(MI);
3637 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3638 widenScalarDst(MI, WideTy);
3639 Observer.changedInstr(MI);
3640 return Legalized;
3641 }
3642 case TargetOpcode::G_SPLAT_VECTOR: {
3643 if (TypeIdx != 1)
3644 return UnableToLegalize;
3645
3646 Observer.changingInstr(MI);
3647 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3648 Observer.changedInstr(MI);
3649 return Legalized;
3650 }
3651 case TargetOpcode::G_INSERT_SUBVECTOR: {
3652 if (TypeIdx != 0)
3653 return UnableToLegalize;
3654
3656 Register BigVec = IS.getBigVec();
3657 Register SubVec = IS.getSubVec();
3658
3659 LLT SubVecTy = MRI.getType(SubVec);
3660 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3661
3662 // Widen the G_INSERT_SUBVECTOR
3663 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3664 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3665 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3666 IS.getIndexImm());
3667
3668 // Truncate back down
3669 auto SplatZero = MIRBuilder.buildSplatVector(
3670 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3671 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3672 SplatZero);
3673
3674 MI.eraseFromParent();
3675
3676 return Legalized;
3677 }
3678 case TargetOpcode::G_BITCAST:
3679 if (WideTy.isVector())
3680 return UnableToLegalize;
3681 Observer.changingInstr(MI);
3682 if (TypeIdx == 0)
3683 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3684 else
3685 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3686 Observer.changedInstr(MI);
3687
3688 Register Dst = MI.getOperand(0).getReg();
3689 Register Src = MI.getOperand(1).getReg();
3690 if (MRI.getType(Dst) == MRI.getType(Src)) {
3691 Observer.changingAllUsesOfReg(MRI, Dst);
3692 MRI.replaceRegWith(Dst, Src);
3693 Observer.finishedChangingAllUsesOfReg();
3694 MI.eraseFromParent();
3695 }
3696
3697 return Legalized;
3698 }
3699}
3700
3702 MachineIRBuilder &B, Register Src, LLT Ty) {
3703 auto Unmerge = B.buildUnmerge(Ty, Src);
3704 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3705 Pieces.push_back(Unmerge.getReg(I));
3706}
3707
3708static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3709 MachineIRBuilder &MIRBuilder) {
3710 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3711 MachineFunction &MF = MIRBuilder.getMF();
3712 const DataLayout &DL = MIRBuilder.getDataLayout();
3713 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3714 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3715 LLT DstLLT = MRI.getType(DstReg);
3716
3717 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3718
3719 auto Addr = MIRBuilder.buildConstantPool(
3720 AddrPtrTy,
3721 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3722
3723 MachineMemOperand *MMO =
3725 MachineMemOperand::MOLoad, DstLLT, Alignment);
3726
3727 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3728}
3729
3732 const MachineOperand &ConstOperand = MI.getOperand(1);
3733 const Constant *ConstantVal = ConstOperand.getCImm();
3734
3735 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3736 MI.eraseFromParent();
3737
3738 return Legalized;
3739}
3740
3743 const MachineOperand &ConstOperand = MI.getOperand(1);
3744 const Constant *ConstantVal = ConstOperand.getFPImm();
3745
3746 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3747 MI.eraseFromParent();
3748
3749 return Legalized;
3750}
3751
3754 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3755 if (SrcTy.isVector()) {
3756 LLT SrcEltTy = SrcTy.getElementType();
3758
3759 if (DstTy.isVector()) {
3760 int NumDstElt = DstTy.getNumElements();
3761 int NumSrcElt = SrcTy.getNumElements();
3762
3763 LLT DstEltTy = DstTy.getElementType();
3764 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3765 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3766
3767 // If there's an element size mismatch, insert intermediate casts to match
3768 // the result element type.
3769 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3770 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3771 //
3772 // =>
3773 //
3774 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3775 // %3:_(<2 x s8>) = G_BITCAST %2
3776 // %4:_(<2 x s8>) = G_BITCAST %3
3777 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3778 DstCastTy = DstTy.changeVectorElementCount(
3779 ElementCount::getFixed(NumDstElt / NumSrcElt));
3780 SrcPartTy = SrcEltTy;
3781 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3782 //
3783 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3784 //
3785 // =>
3786 //
3787 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3788 // %3:_(s16) = G_BITCAST %2
3789 // %4:_(s16) = G_BITCAST %3
3790 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3791 SrcPartTy = SrcTy.changeVectorElementCount(
3792 ElementCount::getFixed(NumSrcElt / NumDstElt));
3793 DstCastTy = DstEltTy;
3794 }
3795
3796 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3797 for (Register &SrcReg : SrcRegs)
3798 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3799 } else
3800 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3801
3802 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3803 MI.eraseFromParent();
3804 return Legalized;
3805 }
3806
3807 if (DstTy.isVector()) {
3809 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3810 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3811 MI.eraseFromParent();
3812 return Legalized;
3813 }
3814
3815 return UnableToLegalize;
3816}
3817
3818/// Figure out the bit offset into a register when coercing a vector index for
3819/// the wide element type. This is only for the case when promoting vector to
3820/// one with larger elements.
3821//
3822///
3823/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3824/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3826 Register Idx,
3827 unsigned NewEltSize,
3828 unsigned OldEltSize) {
3829 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3830 LLT IdxTy = B.getMRI()->getType(Idx);
3831
3832 // Now figure out the amount we need to shift to get the target bits.
3833 auto OffsetMask = B.buildConstant(
3834 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3835 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3836 return B.buildShl(IdxTy, OffsetIdx,
3837 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3838}
3839
3840/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3841/// is casting to a vector with a smaller element size, perform multiple element
3842/// extracts and merge the results. If this is coercing to a vector with larger
3843/// elements, index the bitcasted vector and extract the target element with bit
3844/// operations. This is intended to force the indexing in the native register
3845/// size for architectures that can dynamically index the register file.
3848 LLT CastTy) {
3849 if (TypeIdx != 1)
3850 return UnableToLegalize;
3851
3852 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3853
3854 LLT SrcEltTy = SrcVecTy.getElementType();
3855 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3856 unsigned OldNumElts = SrcVecTy.getNumElements();
3857
3858 LLT NewEltTy = CastTy.getScalarType();
3859 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3860
3861 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3862 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3863 if (NewNumElts > OldNumElts) {
3864 // Decreasing the vector element size
3865 //
3866 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3867 // =>
3868 // v4i32:castx = bitcast x:v2i64
3869 //
3870 // i64 = bitcast
3871 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3872 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3873 //
3874 if (NewNumElts % OldNumElts != 0)
3875 return UnableToLegalize;
3876
3877 // Type of the intermediate result vector.
3878 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3879 LLT MidTy =
3880 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3881
3882 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3883
3884 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3885 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3886
3887 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3888 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3889 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3890 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3891 NewOps[I] = Elt.getReg(0);
3892 }
3893
3894 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3895 MIRBuilder.buildBitcast(Dst, NewVec);
3896 MI.eraseFromParent();
3897 return Legalized;
3898 }
3899
3900 if (NewNumElts < OldNumElts) {
3901 if (NewEltSize % OldEltSize != 0)
3902 return UnableToLegalize;
3903
3904 // This only depends on powers of 2 because we use bit tricks to figure out
3905 // the bit offset we need to shift to get the target element. A general
3906 // expansion could emit division/multiply.
3907 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3908 return UnableToLegalize;
3909
3910 // Increasing the vector element size.
3911 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3912 //
3913 // =>
3914 //
3915 // %cast = G_BITCAST %vec
3916 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3917 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3918 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3919 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3920 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3921 // %elt = G_TRUNC %elt_bits
3922
3923 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3924 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3925
3926 // Divide to get the index in the wider element type.
3927 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3928
3929 Register WideElt = CastVec;
3930 if (CastTy.isVector()) {
3931 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3932 ScaledIdx).getReg(0);
3933 }
3934
3935 // Compute the bit offset into the register of the target element.
3937 MIRBuilder, Idx, NewEltSize, OldEltSize);
3938
3939 // Shift the wide element to get the target element.
3940 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3941 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3942 MI.eraseFromParent();
3943 return Legalized;
3944 }
3945
3946 return UnableToLegalize;
3947}
3948
3949/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3950/// TargetReg, while preserving other bits in \p TargetReg.
3951///
3952/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3954 Register TargetReg, Register InsertReg,
3955 Register OffsetBits) {
3956 LLT TargetTy = B.getMRI()->getType(TargetReg);
3957 LLT InsertTy = B.getMRI()->getType(InsertReg);
3958 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3959 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3960
3961 // Produce a bitmask of the value to insert
3962 auto EltMask = B.buildConstant(
3963 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3964 InsertTy.getSizeInBits()));
3965 // Shift it into position
3966 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3967 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3968
3969 // Clear out the bits in the wide element
3970 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3971
3972 // The value to insert has all zeros already, so stick it into the masked
3973 // wide element.
3974 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3975}
3976
3977/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3978/// is increasing the element size, perform the indexing in the target element
3979/// type, and use bit operations to insert at the element position. This is
3980/// intended for architectures that can dynamically index the register file and
3981/// want to force indexing in the native register size.
3984 LLT CastTy) {
3985 if (TypeIdx != 0)
3986 return UnableToLegalize;
3987
3988 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3989 MI.getFirst4RegLLTs();
3990 LLT VecTy = DstTy;
3991
3992 LLT VecEltTy = VecTy.getElementType();
3993 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3994 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3995 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3996
3997 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3998 unsigned OldNumElts = VecTy.getNumElements();
3999
4000 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
4001 if (NewNumElts < OldNumElts) {
4002 if (NewEltSize % OldEltSize != 0)
4003 return UnableToLegalize;
4004
4005 // This only depends on powers of 2 because we use bit tricks to figure out
4006 // the bit offset we need to shift to get the target element. A general
4007 // expansion could emit division/multiply.
4008 if (!isPowerOf2_32(NewEltSize / OldEltSize))
4009 return UnableToLegalize;
4010
4011 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4012 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4013
4014 // Divide to get the index in the wider element type.
4015 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4016
4017 Register ExtractedElt = CastVec;
4018 if (CastTy.isVector()) {
4019 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4020 ScaledIdx).getReg(0);
4021 }
4022
4023 // Compute the bit offset into the register of the target element.
4025 MIRBuilder, Idx, NewEltSize, OldEltSize);
4026
4027 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
4028 Val, OffsetBits);
4029 if (CastTy.isVector()) {
4030 InsertedElt = MIRBuilder.buildInsertVectorElement(
4031 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
4032 }
4033
4034 MIRBuilder.buildBitcast(Dst, InsertedElt);
4035 MI.eraseFromParent();
4036 return Legalized;
4037 }
4038
4039 return UnableToLegalize;
4040}
4041
4042// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4043// those that have smaller than legal operands.
4044//
4045// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4046//
4047// ===>
4048//
4049// s32 = G_BITCAST <4 x s8>
4050// s32 = G_BITCAST <4 x s8>
4051// s32 = G_BITCAST <4 x s8>
4052// s32 = G_BITCAST <4 x s8>
4053// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4054// <16 x s8> = G_BITCAST <4 x s32>
4057 LLT CastTy) {
4058 // Convert it to CONCAT instruction
4059 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4060 if (!ConcatMI) {
4061 return UnableToLegalize;
4062 }
4063
4064 // Check if bitcast is Legal
4065 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4066 LLT SrcScalTy = CastTy.getScalarType();
4067
4068 // Check if the build vector is Legal
4069 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4070 return UnableToLegalize;
4071 }
4072
4073 // Bitcast the sources
4074 SmallVector<Register> BitcastRegs;
4075 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4076 BitcastRegs.push_back(
4077 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4078 .getReg(0));
4079 }
4080
4081 // Build the scalar values into a vector
4082 Register BuildReg =
4083 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4084 MIRBuilder.buildBitcast(DstReg, BuildReg);
4085
4086 MI.eraseFromParent();
4087 return Legalized;
4088}
4089
4090// This bitcasts a shuffle vector to a different type currently of the same
4091// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4092// will be used instead.
4093//
4094// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4095// ===>
4096// <4 x s64> = G_PTRTOINT <4 x p0>
4097// <4 x s64> = G_PTRTOINT <4 x p0>
4098// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4099// <16 x p0> = G_INTTOPTR <16 x s64>
4102 LLT CastTy) {
4103 auto ShuffleMI = cast<GShuffleVector>(&MI);
4104 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4105 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4106
4107 // We currently only handle vectors of the same size.
4108 if (TypeIdx != 0 ||
4109 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4110 CastTy.getElementCount() != DstTy.getElementCount())
4111 return UnableToLegalize;
4112
4113 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4114
4115 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4116 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4117 auto Shuf =
4118 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4119 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4120
4121 MI.eraseFromParent();
4122 return Legalized;
4123}
4124
4125/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4126///
4127/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4128///
4129/// ===>
4130///
4131/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4132/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4133/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4136 LLT CastTy) {
4137 auto ES = cast<GExtractSubvector>(&MI);
4138
4139 if (!CastTy.isVector())
4140 return UnableToLegalize;
4141
4142 if (TypeIdx != 0)
4143 return UnableToLegalize;
4144
4145 Register Dst = ES->getReg(0);
4146 Register Src = ES->getSrcVec();
4147 uint64_t Idx = ES->getIndexImm();
4148
4149 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4150
4151 LLT DstTy = MRI.getType(Dst);
4152 LLT SrcTy = MRI.getType(Src);
4153 ElementCount DstTyEC = DstTy.getElementCount();
4154 ElementCount SrcTyEC = SrcTy.getElementCount();
4155 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4156 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4157
4158 if (DstTy == CastTy)
4159 return Legalized;
4160
4161 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4162 return UnableToLegalize;
4163
4164 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4165 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4166 if (CastEltSize < DstEltSize)
4167 return UnableToLegalize;
4168
4169 auto AdjustAmt = CastEltSize / DstEltSize;
4170 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4171 SrcTyMinElts % AdjustAmt != 0)
4172 return UnableToLegalize;
4173
4174 Idx /= AdjustAmt;
4175 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4176 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4177 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4178 MIRBuilder.buildBitcast(Dst, PromotedES);
4179
4180 ES->eraseFromParent();
4181 return Legalized;
4182}
4183
4184/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4185///
4186/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4187/// <vscale x 8 x i1>,
4188/// N
4189///
4190/// ===>
4191///
4192/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4193/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4194/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4195/// <vscale x 1 x i8>, N / 8
4196/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4199 LLT CastTy) {
4200 auto ES = cast<GInsertSubvector>(&MI);
4201
4202 if (!CastTy.isVector())
4203 return UnableToLegalize;
4204
4205 if (TypeIdx != 0)
4206 return UnableToLegalize;
4207
4208 Register Dst = ES->getReg(0);
4209 Register BigVec = ES->getBigVec();
4210 Register SubVec = ES->getSubVec();
4211 uint64_t Idx = ES->getIndexImm();
4212
4213 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4214
4215 LLT DstTy = MRI.getType(Dst);
4216 LLT BigVecTy = MRI.getType(BigVec);
4217 LLT SubVecTy = MRI.getType(SubVec);
4218
4219 if (DstTy == CastTy)
4220 return Legalized;
4221
4222 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4223 return UnableToLegalize;
4224
4225 ElementCount DstTyEC = DstTy.getElementCount();
4226 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4227 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4228 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4229 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4230 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4231
4232 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4233 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4234 if (CastEltSize < DstEltSize)
4235 return UnableToLegalize;
4236
4237 auto AdjustAmt = CastEltSize / DstEltSize;
4238 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4239 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4240 return UnableToLegalize;
4241
4242 Idx /= AdjustAmt;
4243 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4244 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4245 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4246 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4247 auto PromotedIS =
4248 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4249 MIRBuilder.buildBitcast(Dst, PromotedIS);
4250
4251 ES->eraseFromParent();
4252 return Legalized;
4253}
4254
4256 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4257 Register DstReg = LoadMI.getDstReg();
4258 Register PtrReg = LoadMI.getPointerReg();
4259 LLT DstTy = MRI.getType(DstReg);
4260 MachineMemOperand &MMO = LoadMI.getMMO();
4261 LLT MemTy = MMO.getMemoryType();
4262 MachineFunction &MF = MIRBuilder.getMF();
4263
4264 LLT EltTy = MemTy.getScalarType();
4265
4266 unsigned MemSizeInBits = MemTy.getSizeInBits();
4267 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4268
4269 if (MemSizeInBits != MemStoreSizeInBits) {
4270 if (MemTy.isVector())
4271 return UnableToLegalize;
4272
4273 // Promote to a byte-sized load if not loading an integral number of
4274 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4275 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4276 MachineMemOperand *NewMMO =
4277 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4278
4279 Register LoadReg = DstReg;
4280 LLT LoadTy = DstTy;
4281
4282 // If this wasn't already an extending load, we need to widen the result
4283 // register to avoid creating a load with a narrower result than the source.
4284 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4285 LoadTy = WideMemTy;
4286 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4287 }
4288
4289 if (isa<GSExtLoad>(LoadMI)) {
4290 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4291 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4292 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4293 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4294 // The extra bits are guaranteed to be zero, since we stored them that
4295 // way. A zext load from Wide thus automatically gives zext from MemVT.
4296 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4297 } else {
4298 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4299 }
4300
4301 if (DstTy != LoadTy)
4302 MIRBuilder.buildTrunc(DstReg, LoadReg);
4303
4304 LoadMI.eraseFromParent();
4305 return Legalized;
4306 }
4307
4308 // Big endian lowering not implemented.
4309 if (MIRBuilder.getDataLayout().isBigEndian())
4310 return UnableToLegalize;
4311
4312 // This load needs splitting into power of 2 sized loads.
4313 //
4314 // Our strategy here is to generate anyextending loads for the smaller
4315 // types up to next power-2 result type, and then combine the two larger
4316 // result values together, before truncating back down to the non-pow-2
4317 // type.
4318 // E.g. v1 = i24 load =>
4319 // v2 = i32 zextload (2 byte)
4320 // v3 = i32 load (1 byte)
4321 // v4 = i32 shl v3, 16
4322 // v5 = i32 or v4, v2
4323 // v1 = i24 trunc v5
4324 // By doing this we generate the correct truncate which should get
4325 // combined away as an artifact with a matching extend.
4326
4327 uint64_t LargeSplitSize, SmallSplitSize;
4328
4329 if (!isPowerOf2_32(MemSizeInBits)) {
4330 // This load needs splitting into power of 2 sized loads.
4331 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4332 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4333 } else {
4334 // This is already a power of 2, but we still need to split this in half.
4335 //
4336 // Assume we're being asked to decompose an unaligned load.
4337 // TODO: If this requires multiple splits, handle them all at once.
4338 auto &Ctx = MF.getFunction().getContext();
4339 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4340 return UnableToLegalize;
4341
4342 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4343 }
4344
4345 if (MemTy.isVector()) {
4346 // TODO: Handle vector extloads
4347 if (MemTy != DstTy)
4348 return UnableToLegalize;
4349
4350 Align Alignment = LoadMI.getAlign();
4351 // Given an alignment larger than the size of the memory, we can increase
4352 // the size of the load without needing to scalarize it.
4353 if (Alignment.value() * 8 > MemSizeInBits &&
4355 LLT MoreTy = DstTy.changeVectorElementCount(
4357 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4358 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4359 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4360 NewLoad.getReg(0));
4361 LoadMI.eraseFromParent();
4362 return Legalized;
4363 }
4364
4365 // TODO: We can do better than scalarizing the vector and at least split it
4366 // in half.
4367 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4368 }
4369
4370 MachineMemOperand *LargeMMO =
4371 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4372 MachineMemOperand *SmallMMO =
4373 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4374
4375 LLT PtrTy = MRI.getType(PtrReg);
4376 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4377
4378 LLT AnyExtTy;
4379 LLT OffsetCstRes;
4380 if (EltTy.isPointer()) {
4381 AnyExtTy = LLT::scalar(AnyExtSize);
4382 OffsetCstRes = LLT::scalar(PtrTy.getSizeInBits());
4383 } else {
4384 AnyExtTy = DstTy.changeElementSize(AnyExtSize);
4385 OffsetCstRes = DstTy.changeElementSize(PtrTy.getSizeInBits());
4386 }
4387
4388 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4389 PtrReg, *LargeMMO);
4390
4391 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4392 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4393 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4394 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4395 SmallPtr, *SmallMMO);
4396
4397 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4398 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4399
4400 if (AnyExtTy == DstTy)
4401 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4402 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4403 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4404 MIRBuilder.buildTrunc(DstReg, {Or});
4405 } else {
4406 assert(DstTy.isPointer() && "expected pointer");
4407 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4408
4409 // FIXME: We currently consider this to be illegal for non-integral address
4410 // spaces, but we need still need a way to reinterpret the bits.
4411 MIRBuilder.buildIntToPtr(DstReg, Or);
4412 }
4413
4414 LoadMI.eraseFromParent();
4415 return Legalized;
4416}
4417
4419 // Lower a non-power of 2 store into multiple pow-2 stores.
4420 // E.g. split an i24 store into an i16 store + i8 store.
4421 // We do this by first extending the stored value to the next largest power
4422 // of 2 type, and then using truncating stores to store the components.
4423 // By doing this, likewise with G_LOAD, generate an extend that can be
4424 // artifact-combined away instead of leaving behind extracts.
4425 Register SrcReg = StoreMI.getValueReg();
4426 Register PtrReg = StoreMI.getPointerReg();
4427 LLT SrcTy = MRI.getType(SrcReg);
4428 MachineFunction &MF = MIRBuilder.getMF();
4429 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4430 LLT MemTy = MMO.getMemoryType();
4431
4432 unsigned StoreWidth = MemTy.getSizeInBits();
4433 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4434
4435 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4436 // Promote to a byte-sized store with upper bits zero if not
4437 // storing an integral number of bytes. For example, promote
4438 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4439 LLT WideTy = LLT::integer(StoreSizeInBits);
4440
4441 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4442 // Avoid creating a store with a narrower source than result.
4443 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4444 SrcTy = WideTy;
4445 }
4446
4447 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4448
4449 MachineMemOperand *NewMMO =
4450 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4451 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4452 StoreMI.eraseFromParent();
4453 return Legalized;
4454 }
4455
4456 if (MemTy.isVector()) {
4457 if (MemTy != SrcTy)
4458 return scalarizeVectorBooleanStore(StoreMI);
4459
4460 // TODO: We can do better than scalarizing the vector and at least split it
4461 // in half.
4462 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4463 }
4464
4465 unsigned MemSizeInBits = MemTy.getSizeInBits();
4466 uint64_t LargeSplitSize, SmallSplitSize;
4467
4468 if (!isPowerOf2_32(MemSizeInBits)) {
4469 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4470 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4471 } else {
4472 auto &Ctx = MF.getFunction().getContext();
4473 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4474 return UnableToLegalize; // Don't know what we're being asked to do.
4475
4476 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4477 }
4478
4479 // Extend to the next pow-2. If this store was itself the result of lowering,
4480 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4481 // that's wider than the stored size.
4482 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4483 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4484
4485 if (SrcTy.isPointer()) {
4486 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4487 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4488 }
4489
4490 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4491
4492 // Obtain the smaller value by shifting away the larger value.
4493 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4494 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4495
4496 // Generate the PtrAdd and truncating stores.
4497 LLT PtrTy = MRI.getType(PtrReg);
4498 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4499 LargeSplitSize / 8);
4500 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4501
4502 MachineMemOperand *LargeMMO =
4503 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4504 MachineMemOperand *SmallMMO =
4505 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4506 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4507 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4508 StoreMI.eraseFromParent();
4509 return Legalized;
4510}
4511
4514 Register SrcReg = StoreMI.getValueReg();
4515 Register PtrReg = StoreMI.getPointerReg();
4516 LLT SrcTy = MRI.getType(SrcReg);
4517 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4518 LLT MemTy = MMO.getMemoryType();
4519 LLT MemScalarTy = MemTy.getElementType();
4520 MachineFunction &MF = MIRBuilder.getMF();
4521
4522 assert(SrcTy.isVector() && "Expect a vector store type");
4523
4524 if (!MemScalarTy.isByteSized()) {
4525 // We need to build an integer scalar of the vector bit pattern.
4526 // It's not legal for us to add padding when storing a vector.
4527 unsigned NumBits = MemTy.getSizeInBits();
4528 LLT IntTy = LLT::integer(NumBits);
4529 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4530 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4531
4532 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4533 auto Elt = MIRBuilder.buildExtractVectorElement(
4534 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4535 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4536 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4537 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4538 ? (MemTy.getNumElements() - 1) - I
4539 : I;
4540 auto ShiftAmt = MIRBuilder.buildConstant(
4541 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4542 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4543 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4544 }
4545 auto PtrInfo = MMO.getPointerInfo();
4546 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4547 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4548 StoreMI.eraseFromParent();
4549 return Legalized;
4550 }
4551
4552 // TODO: implement simple scalarization.
4553 return UnableToLegalize;
4554}
4555
4557LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4558 switch (MI.getOpcode()) {
4559 case TargetOpcode::G_LOAD: {
4560 if (TypeIdx != 0)
4561 return UnableToLegalize;
4562 MachineMemOperand &MMO = **MI.memoperands_begin();
4563
4564 // Not sure how to interpret a bitcast of an extending load.
4565 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4566 return UnableToLegalize;
4567
4568 Observer.changingInstr(MI);
4569 bitcastDst(MI, CastTy, 0);
4570 MMO.setType(CastTy);
4571 // The range metadata is no longer valid when reinterpreted as a different
4572 // type.
4573 MMO.clearRanges();
4574 Observer.changedInstr(MI);
4575 return Legalized;
4576 }
4577 case TargetOpcode::G_STORE: {
4578 if (TypeIdx != 0)
4579 return UnableToLegalize;
4580
4581 MachineMemOperand &MMO = **MI.memoperands_begin();
4582
4583 // Not sure how to interpret a bitcast of a truncating store.
4584 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4585 return UnableToLegalize;
4586
4587 Observer.changingInstr(MI);
4588 bitcastSrc(MI, CastTy, 0);
4589 MMO.setType(CastTy);
4590 Observer.changedInstr(MI);
4591 return Legalized;
4592 }
4593 case TargetOpcode::G_SELECT: {
4594 if (TypeIdx != 0)
4595 return UnableToLegalize;
4596
4597 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4598 LLVM_DEBUG(
4599 dbgs() << "bitcast action not implemented for vector select\n");
4600 return UnableToLegalize;
4601 }
4602
4603 Observer.changingInstr(MI);
4604 bitcastSrc(MI, CastTy, 2);
4605 bitcastSrc(MI, CastTy, 3);
4606 bitcastDst(MI, CastTy, 0);
4607 Observer.changedInstr(MI);
4608 return Legalized;
4609 }
4610 case TargetOpcode::G_AND:
4611 case TargetOpcode::G_OR:
4612 case TargetOpcode::G_XOR: {
4613 Observer.changingInstr(MI);
4614 bitcastSrc(MI, CastTy, 1);
4615 bitcastSrc(MI, CastTy, 2);
4616 bitcastDst(MI, CastTy, 0);
4617 Observer.changedInstr(MI);
4618 return Legalized;
4619 }
4620 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4621 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4622 case TargetOpcode::G_INSERT_VECTOR_ELT:
4623 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4624 case TargetOpcode::G_CONCAT_VECTORS:
4625 return bitcastConcatVector(MI, TypeIdx, CastTy);
4626 case TargetOpcode::G_SHUFFLE_VECTOR:
4627 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4628 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4629 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4630 case TargetOpcode::G_INSERT_SUBVECTOR:
4631 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4632 default:
4633 return UnableToLegalize;
4634 }
4635}
4636
4637// Legalize an instruction by changing the opcode in place.
4638void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4640 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4642}
4643
4645LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4646 using namespace TargetOpcode;
4647 switch(MI.getOpcode()) {
4648 default:
4649 return UnableToLegalize;
4650 case TargetOpcode::G_FCONSTANT:
4651 return lowerFConstant(MI);
4652 case TargetOpcode::G_BITCAST:
4653 return lowerBitcast(MI);
4654 case TargetOpcode::G_SREM:
4655 case TargetOpcode::G_UREM: {
4656 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4657 auto Quot =
4658 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4659 {MI.getOperand(1), MI.getOperand(2)});
4660
4661 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4662 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4663 MI.eraseFromParent();
4664 return Legalized;
4665 }
4666 case TargetOpcode::G_SADDO:
4667 case TargetOpcode::G_SSUBO:
4668 return lowerSADDO_SSUBO(MI);
4669 case TargetOpcode::G_SADDE:
4670 return lowerSADDE(MI);
4671 case TargetOpcode::G_SSUBE:
4672 return lowerSSUBE(MI);
4673 case TargetOpcode::G_UMULH:
4674 case TargetOpcode::G_SMULH:
4675 return lowerSMULH_UMULH(MI);
4676 case TargetOpcode::G_SMULO:
4677 case TargetOpcode::G_UMULO: {
4678 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4679 // result.
4680 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4681 LLT Ty = MRI.getType(Res);
4682
4683 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4684 ? TargetOpcode::G_SMULH
4685 : TargetOpcode::G_UMULH;
4686
4687 Observer.changingInstr(MI);
4688 const auto &TII = MIRBuilder.getTII();
4689 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4690 MI.removeOperand(1);
4691 Observer.changedInstr(MI);
4692
4693 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4694 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4695
4696 // Move insert point forward so we can use the Res register if needed.
4697 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4698
4699 // For *signed* multiply, overflow is detected by checking:
4700 // (hi != (lo >> bitwidth-1))
4701 if (Opcode == TargetOpcode::G_SMULH) {
4702 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4703 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4704 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4705 } else {
4706 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4707 }
4708 return Legalized;
4709 }
4710 case TargetOpcode::G_FNEG: {
4711 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4712 LLT TyInt =
4713 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4714 Register CastedSubByReg = SubByReg;
4715
4716 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4717 !SubByRegTy.getScalarType().isInteger()) {
4718 auto BitcastDst = SubByRegTy.changeElementType(
4719 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4720 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4721 }
4722
4723 auto SignMask = MIRBuilder.buildConstant(
4724 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4725
4726 if (ResTy != TyInt) {
4727 Register NewDst =
4728 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4729 MIRBuilder.buildBitcast(Res, NewDst);
4730 } else
4731 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4732
4733 MI.eraseFromParent();
4734 return Legalized;
4735 }
4736 case TargetOpcode::G_FSUB:
4737 case TargetOpcode::G_STRICT_FSUB: {
4738 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4739 LLT Ty = MRI.getType(Res);
4740
4741 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4742 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4743
4744 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4745 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4746 else
4747 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4748
4749 MI.eraseFromParent();
4750 return Legalized;
4751 }
4752 case TargetOpcode::G_FMAD:
4753 return lowerFMad(MI);
4754 case TargetOpcode::G_FFLOOR:
4755 return lowerFFloor(MI);
4756 case TargetOpcode::G_LROUND:
4757 case TargetOpcode::G_LLROUND: {
4758 Register DstReg = MI.getOperand(0).getReg();
4759 Register SrcReg = MI.getOperand(1).getReg();
4760 LLT SrcTy = MRI.getType(SrcReg);
4761 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4762 {SrcReg});
4763 MIRBuilder.buildFPTOSI(DstReg, Round);
4764 MI.eraseFromParent();
4765 return Legalized;
4766 }
4767 case TargetOpcode::G_INTRINSIC_ROUND:
4768 return lowerIntrinsicRound(MI);
4769 case TargetOpcode::G_FRINT: {
4770 // Since round even is the assumed rounding mode for unconstrained FP
4771 // operations, rint and roundeven are the same operation.
4772 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4773 return Legalized;
4774 }
4775 case TargetOpcode::G_INTRINSIC_LRINT:
4776 case TargetOpcode::G_INTRINSIC_LLRINT: {
4777 Register DstReg = MI.getOperand(0).getReg();
4778 Register SrcReg = MI.getOperand(1).getReg();
4779 LLT SrcTy = MRI.getType(SrcReg);
4780 auto Round =
4781 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4782 MIRBuilder.buildFPTOSI(DstReg, Round);
4783 MI.eraseFromParent();
4784 return Legalized;
4785 }
4786 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4787 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4788 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4789 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4790 **MI.memoperands_begin());
4791 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4792 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4793 MI.eraseFromParent();
4794 return Legalized;
4795 }
4796 case TargetOpcode::G_LOAD:
4797 case TargetOpcode::G_SEXTLOAD:
4798 case TargetOpcode::G_ZEXTLOAD:
4799 return lowerLoad(cast<GAnyLoad>(MI));
4800 case TargetOpcode::G_STORE:
4801 return lowerStore(cast<GStore>(MI));
4802 case TargetOpcode::G_CTLZ_ZERO_POISON:
4803 case TargetOpcode::G_CTTZ_ZERO_POISON:
4804 case TargetOpcode::G_CTLZ:
4805 case TargetOpcode::G_CTTZ:
4806 case TargetOpcode::G_CTPOP:
4807 case TargetOpcode::G_CTLS:
4808 return lowerBitCount(MI);
4809 case G_UADDO: {
4810 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4811
4812 Register NewRes = MRI.cloneVirtualRegister(Res);
4813
4814 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4815 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4816
4817 MIRBuilder.buildCopy(Res, NewRes);
4818
4819 MI.eraseFromParent();
4820 return Legalized;
4821 }
4822 case G_UADDE: {
4823 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4824 const LLT CondTy = MRI.getType(CarryOut);
4825 const LLT Ty = MRI.getType(Res);
4826
4827 Register NewRes = MRI.cloneVirtualRegister(Res);
4828
4829 // Initial add of the two operands.
4830 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4831
4832 // Initial check for carry.
4833 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4834
4835 // Add the sum and the carry.
4836 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4837 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4838
4839 // Second check for carry. We can only carry if the initial sum is all 1s
4840 // and the carry is set, resulting in a new sum of 0.
4841 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4842 auto ResEqZero =
4843 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4844 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4845 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4846
4847 MIRBuilder.buildCopy(Res, NewRes);
4848
4849 MI.eraseFromParent();
4850 return Legalized;
4851 }
4852 case G_USUBO: {
4853 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4854
4855 MIRBuilder.buildSub(Res, LHS, RHS);
4856 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4857
4858 MI.eraseFromParent();
4859 return Legalized;
4860 }
4861 case G_USUBE: {
4862 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4863 const LLT CondTy = MRI.getType(BorrowOut);
4864 const LLT Ty = MRI.getType(Res);
4865
4866 // Initial subtract of the two operands.
4867 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4868
4869 // Initial check for borrow.
4870 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4871
4872 // Subtract the borrow from the first subtract.
4873 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4874 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4875
4876 // Second check for borrow. We can only borrow if the initial difference is
4877 // 0 and the borrow is set, resulting in a new difference of all 1s.
4878 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4879 auto TmpResEqZero =
4880 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4881 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4882 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4883
4884 MI.eraseFromParent();
4885 return Legalized;
4886 }
4887 case G_UITOFP:
4888 return lowerUITOFP(MI);
4889 case G_SITOFP:
4890 return lowerSITOFP(MI);
4891 case G_FPTOUI:
4892 return lowerFPTOUI(MI);
4893 case G_FPTOSI:
4894 return lowerFPTOSI(MI);
4895 case G_FPTOUI_SAT:
4896 case G_FPTOSI_SAT:
4897 return lowerFPTOINT_SAT(MI);
4898 case G_FPEXT:
4899 return lowerFPEXT(MI);
4900 case G_FPTRUNC:
4901 return lowerFPTRUNC(MI);
4902 case G_FPOWI:
4903 return lowerFPOWI(MI);
4904 case G_FMODF:
4905 return lowerFMODF(MI);
4906 case G_SMIN:
4907 case G_SMAX:
4908 case G_UMIN:
4909 case G_UMAX:
4910 return lowerMinMax(MI);
4911 case G_SCMP:
4912 case G_UCMP:
4913 return lowerThreewayCompare(MI);
4914 case G_FCOPYSIGN:
4915 return lowerFCopySign(MI);
4916 case G_FMINNUM:
4917 case G_FMAXNUM:
4918 case G_FMINIMUMNUM:
4919 case G_FMAXIMUMNUM:
4920 return lowerFMinNumMaxNum(MI);
4921 case G_FMINIMUM:
4922 case G_FMAXIMUM:
4923 return lowerFMinimumMaximum(MI);
4924 case G_MERGE_VALUES:
4925 return lowerMergeValues(MI);
4926 case G_UNMERGE_VALUES:
4927 return lowerUnmergeValues(MI);
4928 case TargetOpcode::G_SEXT_INREG: {
4929 assert(MI.getOperand(2).isImm() && "Expected immediate");
4930 int64_t SizeInBits = MI.getOperand(2).getImm();
4931
4932 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4933 LLT DstTy = MRI.getType(DstReg);
4934 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4935
4936 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4937 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4938 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4939 MI.eraseFromParent();
4940 return Legalized;
4941 }
4942 case G_EXTRACT_VECTOR_ELT:
4943 case G_INSERT_VECTOR_ELT:
4945 case G_SHUFFLE_VECTOR:
4946 return lowerShuffleVector(MI);
4947 case G_VECTOR_COMPRESS:
4948 return lowerVECTOR_COMPRESS(MI);
4949 case G_DYN_STACKALLOC:
4950 return lowerDynStackAlloc(MI);
4951 case G_INSERT_SUBVECTOR: {
4952 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
4953 MRI.getType(MI.getOperand(2).getReg()).isScalable())
4954 return UnableToLegalize;
4955
4956 // Check that subvector is half size of main vector
4957 Register Vector = MI.getOperand(1).getReg();
4958 Register Subvector = MI.getOperand(2).getReg();
4959 auto InsertionPointImm = MI.getOperand(3).getImm();
4960
4961 LLT VectorTy = MRI.getType(Vector);
4962 LLT DstTy = MRI.getType(Subvector);
4963 // If so, -> concat(subvector, extract(half of vector))
4964 // (Operands can be either way round depending on insertion point
4965 if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
4966 bool InsertInLowHalf = InsertionPointImm == 0;
4967 auto Extract = MIRBuilder.buildExtractSubvector(
4968 DstTy, Vector,
4969 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
4970
4971 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
4972 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
4973
4974 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
4975 {LowHalf, HighHalf});
4976 MI.eraseFromParent();
4977 return Legalized;
4978 }
4979 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
4980 else {
4981 // Extend subvector to same size as vector
4982 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
4983 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
4984
4985 // Calculate mask required for this shuffle
4986 SmallVector<int> Mask;
4987 for (int i = 0; i < VectorTy.getNumElements(); i++) {
4988 // If this index is within bounds, put subvector's index into mask
4989 if (i >= InsertionPointImm &&
4990 i < InsertionPointImm + DstTy.getNumElements())
4991 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
4992 else
4993 Mask.push_back(i);
4994 }
4995
4996 // Build shuffle
4997 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
4998 Mask);
4999 MI.eraseFromParent();
5000 return Legalized;
5001 }
5002 }
5003 case G_EXTRACT_SUBVECTOR: {
5004 Register DstReg = MI.getOperand(0).getReg();
5005 Register SrcReg = MI.getOperand(1).getReg();
5006 uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
5007
5008 LLT SrcTy = MRI.getType(SrcReg);
5009 LLT DstTy = MRI.getType(DstReg);
5010
5011 if (SrcTy.isScalable())
5012 return UnableToLegalize;
5013
5014 if (SrcTy.getScalarType() != DstTy.getScalarType())
5015 return UnableToLegalize;
5016
5017 // extract_subvector = build_vector(extract_element, extract_element, ...)
5018 SmallVector<Register> ExtractedElements;
5019 for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
5020 ExtractedElements.push_back(
5022 .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
5023 ExtractionPointImm + i)
5024 .getReg(0));
5025 }
5026
5027 MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
5028 MI.eraseFromParent();
5029 return Legalized;
5030 }
5031 case G_STACKSAVE:
5032 return lowerStackSave(MI);
5033 case G_STACKRESTORE:
5034 return lowerStackRestore(MI);
5035 case G_EXTRACT:
5036 return lowerExtract(MI);
5037 case G_INSERT:
5038 return lowerInsert(MI);
5039 case G_BSWAP:
5040 return lowerBswap(MI);
5041 case G_BITREVERSE:
5042 return lowerBitreverse(MI);
5043 case G_READ_REGISTER:
5044 case G_WRITE_REGISTER:
5045 return lowerReadWriteRegister(MI);
5046 case G_UADDSAT:
5047 case G_USUBSAT: {
5048 // Try to make a reasonable guess about which lowering strategy to use. The
5049 // target can override this with custom lowering and calling the
5050 // implementation functions.
5051 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5052 if (LI.isLegalOrCustom({G_UMIN, Ty}))
5053 return lowerAddSubSatToMinMax(MI);
5055 }
5056 case G_SADDSAT:
5057 case G_SSUBSAT: {
5058 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5059
5060 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5061 // since it's a shorter expansion. However, we would need to figure out the
5062 // preferred boolean type for the carry out for the query.
5063 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5064 return lowerAddSubSatToMinMax(MI);
5066 }
5067 case G_SSHLSAT:
5068 case G_USHLSAT:
5069 return lowerShlSat(MI);
5070 case G_TRUNC_SSAT_S:
5071 case G_TRUNC_USAT_U:
5072 case G_TRUNC_SSAT_U:
5073 return lowerTruncSat(MI);
5074 case G_ABS:
5075 return lowerAbsToAddXor(MI);
5076 case G_ABDS:
5077 case G_ABDU: {
5078 bool IsSigned = MI.getOpcode() == G_ABDS;
5079 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5080 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5081 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5082 return lowerAbsDiffToMinMax(MI);
5083 }
5084 return lowerAbsDiffToSelect(MI);
5085 }
5086 case G_FABS:
5087 return lowerFAbs(MI);
5088 case G_SELECT:
5089 return lowerSelect(MI);
5090 case G_IS_FPCLASS:
5091 return lowerISFPCLASS(MI);
5092 case G_SDIVREM:
5093 case G_UDIVREM:
5094 return lowerDIVREM(MI);
5095 case G_FSHL:
5096 case G_FSHR:
5097 return lowerFunnelShift(MI);
5098 case G_ROTL:
5099 case G_ROTR:
5100 return lowerRotate(MI);
5101 case G_MEMSET:
5102 case G_MEMCPY:
5103 case G_MEMMOVE:
5104 case G_MEMCPY_INLINE:
5105 case G_MEMSET_INLINE:
5106 return lowerMemCpyFamily(MI);
5107 case G_ZEXT:
5108 case G_SEXT:
5109 case G_ANYEXT:
5110 return lowerEXT(MI);
5111 case G_TRUNC:
5112 return lowerTRUNC(MI);
5114 return lowerVectorReduction(MI);
5115 case G_VAARG:
5116 return lowerVAArg(MI);
5117 case G_ATOMICRMW_SUB: {
5118 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5119 const LLT ValTy = MRI.getType(Val);
5120 MachineMemOperand *MMO = *MI.memoperands_begin();
5121
5122 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5123 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5124 MI.eraseFromParent();
5125 return Legalized;
5126 }
5127 case G_SMULFIX:
5128 case G_UMULFIX:
5129 case G_SMULFIXSAT:
5130 case G_UMULFIXSAT:
5131 return lowerMulfix(MI);
5132 }
5133}
5134
5136 Align MinAlign) const {
5137 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5138 // datalayout for the preferred alignment. Also there should be a target hook
5139 // for this to allow targets to reduce the alignment and ignore the
5140 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5141 // the type.
5142 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5143}
5144
5147 MachinePointerInfo &PtrInfo) {
5148 MachineFunction &MF = MIRBuilder.getMF();
5149 const DataLayout &DL = MIRBuilder.getDataLayout();
5150 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5151
5152 unsigned AddrSpace = DL.getAllocaAddrSpace();
5153 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5154
5155 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5156 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5157}
5158
5160 const SrcOp &Val) {
5161 LLT SrcTy = Val.getLLTTy(MRI);
5162 Align StackTypeAlign =
5163 std::max(getStackTemporaryAlignment(SrcTy),
5165 MachinePointerInfo PtrInfo;
5166 auto StackTemp =
5167 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5168
5169 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5170 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5171}
5172
5174 LLT VecTy) {
5175 LLT IdxTy = B.getMRI()->getType(IdxReg);
5176 unsigned NElts = VecTy.getNumElements();
5177
5178 int64_t IdxVal;
5179 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5180 if (IdxVal < VecTy.getNumElements())
5181 return IdxReg;
5182 // If a constant index would be out of bounds, clamp it as well.
5183 }
5184
5185 if (isPowerOf2_32(NElts)) {
5187 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5188 }
5189
5190 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5191 .getReg(0);
5192}
5193
5195 Register Index) {
5196 LLT EltTy = VecTy.getElementType();
5197
5198 // Calculate the element offset and add it to the pointer.
5199 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5200 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5201 "Converting bits to bytes lost precision");
5202
5203 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5204
5205 // Convert index to the correct size for the address space.
5206 const DataLayout &DL = MIRBuilder.getDataLayout();
5207 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5208 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5209 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5210 if (IdxTy != MRI.getType(Index))
5211 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5212
5213 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5214 MIRBuilder.buildConstant(IdxTy, EltSize));
5215
5216 LLT PtrTy = MRI.getType(VecPtr);
5217 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5218}
5219
5220#ifndef NDEBUG
5221/// Check that all vector operands have same number of elements. Other operands
5222/// should be listed in NonVecOp.
5225 std::initializer_list<unsigned> NonVecOpIndices) {
5226 if (MI.getNumMemOperands() != 0)
5227 return false;
5228
5229 LLT VecTy = MRI.getType(MI.getReg(0));
5230 if (!VecTy.isVector())
5231 return false;
5232 unsigned NumElts = VecTy.getNumElements();
5233
5234 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5235 MachineOperand &Op = MI.getOperand(OpIdx);
5236 if (!Op.isReg()) {
5237 if (!is_contained(NonVecOpIndices, OpIdx))
5238 return false;
5239 continue;
5240 }
5241
5242 LLT Ty = MRI.getType(Op.getReg());
5243 if (!Ty.isVector()) {
5244 if (!is_contained(NonVecOpIndices, OpIdx))
5245 return false;
5246 continue;
5247 }
5248
5249 if (Ty.getNumElements() != NumElts)
5250 return false;
5251 }
5252
5253 return true;
5254}
5255#endif
5256
5257/// Fill \p DstOps with DstOps that have same number of elements combined as
5258/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5259/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5260/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5261static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5262 unsigned NumElts) {
5263 LLT LeftoverTy;
5264 assert(Ty.isVector() && "Expected vector type");
5265 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5266 int NumParts, NumLeftover;
5267 std::tie(NumParts, NumLeftover) =
5268 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5269
5270 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5271 for (int i = 0; i < NumParts; ++i) {
5272 DstOps.push_back(NarrowTy);
5273 }
5274
5275 if (LeftoverTy.isValid()) {
5276 assert(NumLeftover == 1 && "expected exactly one leftover");
5277 DstOps.push_back(LeftoverTy);
5278 }
5279}
5280
5281/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5282/// made from \p Op depending on operand type.
5284 MachineOperand &Op) {
5285 for (unsigned i = 0; i < N; ++i) {
5286 if (Op.isReg())
5287 Ops.push_back(Op.getReg());
5288 else if (Op.isImm())
5289 Ops.push_back(Op.getImm());
5290 else if (Op.isPredicate())
5291 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5292 else
5293 llvm_unreachable("Unsupported type");
5294 }
5295}
5296
5297// Handle splitting vector operations which need to have the same number of
5298// elements in each type index, but each type index may have a different element
5299// type.
5300//
5301// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5302// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5303// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5304//
5305// Also handles some irregular breakdown cases, e.g.
5306// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5307// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5308// s64 = G_SHL s64, s32
5311 GenericMachineInstr &MI, unsigned NumElts,
5312 std::initializer_list<unsigned> NonVecOpIndices) {
5313 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5314 "Non-compatible opcode or not specified non-vector operands");
5315 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5316
5317 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5318 unsigned NumDefs = MI.getNumDefs();
5319
5320 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5321 // Build instructions with DstOps to use instruction found by CSE directly.
5322 // CSE copies found instruction into given vreg when building with vreg dest.
5323 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5324 // Output registers will be taken from created instructions.
5325 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5326 for (unsigned i = 0; i < NumDefs; ++i) {
5327 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5328 }
5329
5330 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5331 // Operands listed in NonVecOpIndices will be used as is without splitting;
5332 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5333 // scalar condition (op 1), immediate in sext_inreg (op 2).
5334 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5335 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5336 ++UseIdx, ++UseNo) {
5337 if (is_contained(NonVecOpIndices, UseIdx)) {
5338 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5339 MI.getOperand(UseIdx));
5340 } else {
5341 SmallVector<Register, 8> SplitPieces;
5342 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5343 MRI);
5344 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5345 }
5346 }
5347
5348 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5349
5350 // Take i-th piece of each input operand split and build sub-vector/scalar
5351 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5352 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5354 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5355 Defs.push_back(OutputOpsPieces[DstNo][i]);
5356
5358 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5359 Uses.push_back(InputOpsPieces[InputNo][i]);
5360
5361 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5362 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5363 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5364 }
5365
5366 // Merge small outputs into MI's output for each def operand.
5367 if (NumLeftovers) {
5368 for (unsigned i = 0; i < NumDefs; ++i)
5369 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5370 } else {
5371 for (unsigned i = 0; i < NumDefs; ++i)
5372 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5373 }
5374
5375 MI.eraseFromParent();
5376 return Legalized;
5377}
5378
5381 unsigned NumElts) {
5382 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5383
5384 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5385 unsigned NumDefs = MI.getNumDefs();
5386
5387 SmallVector<DstOp, 8> OutputOpsPieces;
5388 SmallVector<Register, 8> OutputRegs;
5389 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5390
5391 // Instructions that perform register split will be inserted in basic block
5392 // where register is defined (basic block is in the next operand).
5393 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5394 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5395 UseIdx += 2, ++UseNo) {
5396 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5397 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5398 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5399 MIRBuilder, MRI);
5400 }
5401
5402 // Build PHIs with fewer elements.
5403 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5404 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5405 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5406 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5407 Phi.addDef(
5408 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5409 OutputRegs.push_back(Phi.getReg(0));
5410
5411 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5412 Phi.addUse(InputOpsPieces[j][i]);
5413 Phi.add(MI.getOperand(1 + j * 2 + 1));
5414 }
5415 }
5416
5417 // Set the insert point after the existing PHIs
5418 MachineBasicBlock &MBB = *MI.getParent();
5419 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5420
5421 // Merge small outputs into MI's def.
5422 if (NumLeftovers) {
5423 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5424 } else {
5425 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5426 }
5427
5428 MI.eraseFromParent();
5429 return Legalized;
5430}
5431
5434 unsigned TypeIdx,
5435 LLT NarrowTy) {
5436 const int NumDst = MI.getNumOperands() - 1;
5437 const Register SrcReg = MI.getOperand(NumDst).getReg();
5438 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5439 LLT SrcTy = MRI.getType(SrcReg);
5440
5441 if (TypeIdx != 1 || NarrowTy == DstTy)
5442 return UnableToLegalize;
5443
5444 // Requires compatible types. Otherwise SrcReg should have been defined by
5445 // merge-like instruction that would get artifact combined. Most likely
5446 // instruction that defines SrcReg has to perform more/fewer elements
5447 // legalization compatible with NarrowTy.
5448 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5449 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5450
5451 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5452 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5453 return UnableToLegalize;
5454
5455 // This is most likely DstTy (smaller then register size) packed in SrcTy
5456 // (larger then register size) and since unmerge was not combined it will be
5457 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5458 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5459
5460 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5461 //
5462 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5463 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5464 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5465 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5466 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5467 const int PartsPerUnmerge = NumDst / NumUnmerge;
5468
5469 for (int I = 0; I != NumUnmerge; ++I) {
5470 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5471
5472 for (int J = 0; J != PartsPerUnmerge; ++J)
5473 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5474 MIB.addUse(Unmerge.getReg(I));
5475 }
5476
5477 MI.eraseFromParent();
5478 return Legalized;
5479}
5480
5483 LLT NarrowTy) {
5484 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5485 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5486 // that should have been artifact combined. Most likely instruction that uses
5487 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5488 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5489 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5490 if (NarrowTy == SrcTy)
5491 return UnableToLegalize;
5492
5493 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5494 // is for old mir tests. Since the changes to more/fewer elements it should no
5495 // longer be possible to generate MIR like this when starting from llvm-ir
5496 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5497 if (TypeIdx == 1) {
5498 assert(SrcTy.isVector() && "Expected vector types");
5499 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5500 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5501 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5502 return UnableToLegalize;
5503 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5504 //
5505 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5506 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5507 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5508 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5509 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5510 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5511
5513 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5514 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5515 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5516 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5517 Elts.push_back(Unmerge.getReg(j));
5518 }
5519
5520 SmallVector<Register, 8> NarrowTyElts;
5521 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5522 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5523 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5524 ++i, Offset += NumNarrowTyElts) {
5525 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5526 NarrowTyElts.push_back(
5527 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5528 }
5529
5530 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5531 MI.eraseFromParent();
5532 return Legalized;
5533 }
5534
5535 assert(TypeIdx == 0 && "Bad type index");
5536 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5537 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5538 return UnableToLegalize;
5539
5540 // This is most likely SrcTy (smaller then register size) packed in DstTy
5541 // (larger then register size) and since merge was not combined it will be
5542 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5543 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5544
5545 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5546 //
5547 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5548 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5549 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5550 SmallVector<Register, 8> NarrowTyElts;
5551 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5552 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5553 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5554 for (unsigned i = 0; i < NumParts; ++i) {
5556 for (unsigned j = 0; j < NumElts; ++j)
5557 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5558 NarrowTyElts.push_back(
5559 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5560 }
5561
5562 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5563 MI.eraseFromParent();
5564 return Legalized;
5565}
5566
5569 unsigned TypeIdx,
5570 LLT NarrowVecTy) {
5571 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5572 Register InsertVal;
5573 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5574
5575 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5576 if (IsInsert)
5577 InsertVal = MI.getOperand(2).getReg();
5578
5579 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5580 LLT VecTy = MRI.getType(SrcVec);
5581
5582 // If the index is a constant, we can really break this down as you would
5583 // expect, and index into the target size pieces.
5584 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5585 if (MaybeCst) {
5586 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5587 // Avoid out of bounds indexing the pieces.
5588 if (IdxVal >= VecTy.getNumElements()) {
5589 MIRBuilder.buildUndef(DstReg);
5590 MI.eraseFromParent();
5591 return Legalized;
5592 }
5593
5594 if (!NarrowVecTy.isVector()) {
5595 SmallVector<Register, 8> SplitPieces;
5596 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5597 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5598 if (IsInsert) {
5599 SplitPieces[IdxVal] = InsertVal;
5600 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5601 } else {
5602 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5603 }
5604 } else {
5605 SmallVector<Register, 8> VecParts;
5606 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5607
5608 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5609 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5610 TargetOpcode::G_ANYEXT);
5611
5612 unsigned NewNumElts = NarrowVecTy.getNumElements();
5613
5614 LLT IdxTy = MRI.getType(Idx);
5615 int64_t PartIdx = IdxVal / NewNumElts;
5616 auto NewIdx =
5617 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5618
5619 if (IsInsert) {
5620 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5621
5622 // Use the adjusted index to insert into one of the subvectors.
5623 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5624 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5625 VecParts[PartIdx] = InsertPart.getReg(0);
5626
5627 // Recombine the inserted subvector with the others to reform the result
5628 // vector.
5629 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5630 } else {
5631 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5632 }
5633 }
5634
5635 MI.eraseFromParent();
5636 return Legalized;
5637 }
5638
5639 // With a variable index, we can't perform the operation in a smaller type, so
5640 // we're forced to expand this.
5641 //
5642 // TODO: We could emit a chain of compare/select to figure out which piece to
5643 // index.
5645}
5646
5649 LLT NarrowTy) {
5650 // FIXME: Don't know how to handle secondary types yet.
5651 if (TypeIdx != 0)
5652 return UnableToLegalize;
5653
5654 if (!NarrowTy.isByteSized()) {
5655 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5656 return UnableToLegalize;
5657 }
5658
5659 // This implementation doesn't work for atomics. Give up instead of doing
5660 // something invalid.
5661 if (LdStMI.isAtomic())
5662 return UnableToLegalize;
5663
5664 bool IsLoad = isa<GLoad>(LdStMI);
5665 Register ValReg = LdStMI.getReg(0);
5666 Register AddrReg = LdStMI.getPointerReg();
5667 LLT ValTy = MRI.getType(ValReg);
5668
5669 // FIXME: Do we need a distinct NarrowMemory legalize action?
5670 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5671 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5672 return UnableToLegalize;
5673 }
5674
5675 int NumParts = -1;
5676 int NumLeftover = -1;
5677 LLT LeftoverTy;
5678 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5679 if (IsLoad) {
5680 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5681 } else {
5682 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5683 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5684 NumParts = NarrowRegs.size();
5685 NumLeftover = NarrowLeftoverRegs.size();
5686 }
5687 }
5688
5689 if (NumParts == -1)
5690 return UnableToLegalize;
5691
5692 LLT PtrTy = MRI.getType(AddrReg);
5693 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5694
5695 unsigned TotalSize = ValTy.getSizeInBits();
5696
5697 // Split the load/store into PartTy sized pieces starting at Offset. If this
5698 // is a load, return the new registers in ValRegs. For a store, each elements
5699 // of ValRegs should be PartTy. Returns the next offset that needs to be
5700 // handled.
5701 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5702 auto MMO = LdStMI.getMMO();
5703 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5704 unsigned NumParts, unsigned Offset) -> unsigned {
5705 MachineFunction &MF = MIRBuilder.getMF();
5706 unsigned PartSize = PartTy.getSizeInBits();
5707 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5708 ++Idx) {
5709 unsigned ByteOffset = Offset / 8;
5710 Register NewAddrReg;
5711
5712 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5713 ByteOffset);
5714
5715 MachineMemOperand *NewMMO =
5716 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5717
5718 if (IsLoad) {
5719 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5720 ValRegs.push_back(Dst);
5721 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5722 } else {
5723 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5724 }
5725 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5726 }
5727
5728 return Offset;
5729 };
5730
5731 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5732 unsigned HandledOffset =
5733 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5734
5735 // Handle the rest of the register if this isn't an even type breakdown.
5736 if (LeftoverTy.isValid())
5737 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5738
5739 if (IsLoad) {
5740 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5741 LeftoverTy, NarrowLeftoverRegs);
5742 }
5743
5744 LdStMI.eraseFromParent();
5745 return Legalized;
5746}
5747
5750 LLT NarrowTy) {
5751 using namespace TargetOpcode;
5753 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5754
5755 switch (MI.getOpcode()) {
5756 case G_IMPLICIT_DEF:
5757 case G_TRUNC:
5758 case G_AND:
5759 case G_OR:
5760 case G_XOR:
5761 case G_ADD:
5762 case G_SUB:
5763 case G_MUL:
5764 case G_PTR_ADD:
5765 case G_SMULH:
5766 case G_UMULH:
5767 case G_FADD:
5768 case G_FMUL:
5769 case G_FSUB:
5770 case G_FNEG:
5771 case G_FABS:
5772 case G_FCANONICALIZE:
5773 case G_FDIV:
5774 case G_FREM:
5775 case G_FMA:
5776 case G_FMAD:
5777 case G_FPOW:
5778 case G_FEXP:
5779 case G_FEXP2:
5780 case G_FEXP10:
5781 case G_FLOG:
5782 case G_FLOG2:
5783 case G_FLOG10:
5784 case G_FLDEXP:
5785 case G_FNEARBYINT:
5786 case G_FCEIL:
5787 case G_FFLOOR:
5788 case G_FRINT:
5789 case G_INTRINSIC_LRINT:
5790 case G_INTRINSIC_LLRINT:
5791 case G_INTRINSIC_ROUND:
5792 case G_INTRINSIC_ROUNDEVEN:
5793 case G_LROUND:
5794 case G_LLROUND:
5795 case G_INTRINSIC_TRUNC:
5796 case G_FMODF:
5797 case G_FCOS:
5798 case G_FSIN:
5799 case G_FTAN:
5800 case G_FACOS:
5801 case G_FASIN:
5802 case G_FATAN:
5803 case G_FATAN2:
5804 case G_FCOSH:
5805 case G_FSINH:
5806 case G_FTANH:
5807 case G_FSQRT:
5808 case G_BSWAP:
5809 case G_BITREVERSE:
5810 case G_SDIV:
5811 case G_UDIV:
5812 case G_SREM:
5813 case G_UREM:
5814 case G_SDIVREM:
5815 case G_UDIVREM:
5816 case G_SMIN:
5817 case G_SMAX:
5818 case G_UMIN:
5819 case G_UMAX:
5820 case G_ABS:
5821 case G_FMINNUM:
5822 case G_FMAXNUM:
5823 case G_FMINNUM_IEEE:
5824 case G_FMAXNUM_IEEE:
5825 case G_FMINIMUM:
5826 case G_FMAXIMUM:
5827 case G_FMINIMUMNUM:
5828 case G_FMAXIMUMNUM:
5829 case G_FSHL:
5830 case G_FSHR:
5831 case G_ROTL:
5832 case G_ROTR:
5833 case G_FREEZE:
5834 case G_SADDSAT:
5835 case G_SSUBSAT:
5836 case G_UADDSAT:
5837 case G_USUBSAT:
5838 case G_UMULO:
5839 case G_SMULO:
5840 case G_SHL:
5841 case G_LSHR:
5842 case G_ASHR:
5843 case G_SSHLSAT:
5844 case G_USHLSAT:
5845 case G_CTLZ:
5846 case G_CTLZ_ZERO_POISON:
5847 case G_CTTZ:
5848 case G_CTTZ_ZERO_POISON:
5849 case G_CTPOP:
5850 case G_CTLS:
5851 case G_FCOPYSIGN:
5852 case G_ZEXT:
5853 case G_SEXT:
5854 case G_ANYEXT:
5855 case G_FPEXT:
5856 case G_FPTRUNC:
5857 case G_SITOFP:
5858 case G_UITOFP:
5859 case G_FPTOSI:
5860 case G_FPTOUI:
5861 case G_FPTOSI_SAT:
5862 case G_FPTOUI_SAT:
5863 case G_INTTOPTR:
5864 case G_PTRTOINT:
5865 case G_ADDRSPACE_CAST:
5866 case G_UADDO:
5867 case G_USUBO:
5868 case G_UADDE:
5869 case G_USUBE:
5870 case G_SADDO:
5871 case G_SSUBO:
5872 case G_SADDE:
5873 case G_SSUBE:
5874 case G_STRICT_FADD:
5875 case G_STRICT_FSUB:
5876 case G_STRICT_FMUL:
5877 case G_STRICT_FMA:
5878 case G_STRICT_FLDEXP:
5879 case G_FFREXP:
5880 case G_TRUNC_SSAT_S:
5881 case G_TRUNC_SSAT_U:
5882 case G_TRUNC_USAT_U:
5883 return fewerElementsVectorMultiEltType(GMI, NumElts);
5884 case G_ICMP:
5885 case G_FCMP:
5886 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5887 case G_IS_FPCLASS:
5888 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5889 case G_SELECT:
5890 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5891 return fewerElementsVectorMultiEltType(GMI, NumElts);
5892 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5893 case G_PHI:
5894 return fewerElementsVectorPhi(GMI, NumElts);
5895 case G_UNMERGE_VALUES:
5896 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5897 case G_BUILD_VECTOR:
5898 assert(TypeIdx == 0 && "not a vector type index");
5899 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5900 case G_CONCAT_VECTORS:
5901 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5902 return UnableToLegalize;
5903 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5904 case G_EXTRACT_SUBVECTOR: {
5905 Register DstReg = MI.getOperand(0).getReg();
5906 LLT DstTy = MRI.getType(DstReg);
5907 Register SrcReg = MI.getOperand(1).getReg();
5908 uint64_t InsertionPointImm = MI.getOperand(2).getImm();
5909
5910 // If Dst > NarrowTy bits, then cannot legalize
5911 if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
5912 return UnableToLegalize;
5913
5914 // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
5915 if (!DstTy.getElementCount().isKnownMultipleOf(NarrowTy.getElementCount()))
5916 return UnableToLegalize;
5917
5918 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5919 uint64_t RequiredSubvectorIndex =
5920 InsertionPointImm / NarrowTy.getNumElements();
5921 // If Dst and Narrow are both same size, convert to a copy
5922 if (DstTy.getNumElements() == NarrowTy.getNumElements())
5923 MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
5924 else
5925 MIRBuilder.buildExtractSubvector(
5926 DstReg, Unmerge.getReg(RequiredSubvectorIndex),
5927 InsertionPointImm % NarrowTy.getNumElements());
5928
5929 MI.eraseFromParent();
5930 return Legalized;
5931 }
5932 case G_EXTRACT_VECTOR_ELT:
5933 case G_INSERT_VECTOR_ELT:
5934 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5935 case G_LOAD:
5936 case G_STORE:
5937 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5938 case G_SEXT_INREG:
5939 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5941 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5942 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5943 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5944 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5945 case G_SHUFFLE_VECTOR:
5946 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5947 case G_FPOWI:
5948 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5949 case G_BITCAST:
5950 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5951 case G_INTRINSIC_FPTRUNC_ROUND:
5952 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5953 default:
5954 return UnableToLegalize;
5955 }
5956}
5957
5960 LLT NarrowTy) {
5961 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5962 "Not a bitcast operation");
5963
5964 if (TypeIdx != 0)
5965 return UnableToLegalize;
5966
5967 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5968
5969 unsigned NewElemCount =
5970 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5971 SmallVector<Register> SrcVRegs, BitcastVRegs;
5972 if (NewElemCount == 1) {
5973 LLT SrcNarrowTy = SrcTy.getElementType();
5974
5975 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
5976 getUnmergeResults(SrcVRegs, *Unmerge);
5977 } else {
5978 LLT SrcNarrowTy =
5980
5981 // Split the Src and Dst Reg into smaller registers
5982 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5983 return UnableToLegalize;
5984 }
5985
5986 // Build new smaller bitcast instructions
5987 // Not supporting Leftover types for now but will have to
5988 for (Register Reg : SrcVRegs)
5989 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
5990
5991 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5992 MI.eraseFromParent();
5993 return Legalized;
5994}
5995
5997 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5998 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5999 if (TypeIdx != 0)
6000 return UnableToLegalize;
6001
6002 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
6003 MI.getFirst3RegLLTs();
6004 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6005 // The shuffle should be canonicalized by now.
6006 if (DstTy != Src1Ty)
6007 return UnableToLegalize;
6008 if (DstTy != Src2Ty)
6009 return UnableToLegalize;
6010
6011 if (!isPowerOf2_32(DstTy.getNumElements()))
6012 return UnableToLegalize;
6013
6014 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
6015 // Further legalization attempts will be needed to do split further.
6016 NarrowTy =
6017 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
6018 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
6019
6020 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
6021 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
6022 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
6023 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
6024 SplitSrc2Regs[1]};
6025
6026 Register Hi, Lo;
6027
6028 // If Lo or Hi uses elements from at most two of the four input vectors, then
6029 // express it as a vector shuffle of those two inputs. Otherwise extract the
6030 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
6032 for (unsigned High = 0; High < 2; ++High) {
6033 Register &Output = High ? Hi : Lo;
6034
6035 // Build a shuffle mask for the output, discovering on the fly which
6036 // input vectors to use as shuffle operands (recorded in InputUsed).
6037 // If building a suitable shuffle vector proves too hard, then bail
6038 // out with useBuildVector set.
6039 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
6040 unsigned FirstMaskIdx = High * NewElts;
6041 bool UseBuildVector = false;
6042 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6043 // The mask element. This indexes into the input.
6044 int Idx = Mask[FirstMaskIdx + MaskOffset];
6045
6046 // The input vector this mask element indexes into.
6047 unsigned Input = (unsigned)Idx / NewElts;
6048
6049 if (Input >= std::size(Inputs)) {
6050 // The mask element does not index into any input vector.
6051 Ops.push_back(-1);
6052 continue;
6053 }
6054
6055 // Turn the index into an offset from the start of the input vector.
6056 Idx -= Input * NewElts;
6057
6058 // Find or create a shuffle vector operand to hold this input.
6059 unsigned OpNo;
6060 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
6061 if (InputUsed[OpNo] == Input) {
6062 // This input vector is already an operand.
6063 break;
6064 } else if (InputUsed[OpNo] == -1U) {
6065 // Create a new operand for this input vector.
6066 InputUsed[OpNo] = Input;
6067 break;
6068 }
6069 }
6070
6071 if (OpNo >= std::size(InputUsed)) {
6072 // More than two input vectors used! Give up on trying to create a
6073 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
6074 UseBuildVector = true;
6075 break;
6076 }
6077
6078 // Add the mask index for the new shuffle vector.
6079 Ops.push_back(Idx + OpNo * NewElts);
6080 }
6081
6082 if (UseBuildVector) {
6083 LLT EltTy = NarrowTy.getElementType();
6085
6086 // Extract the input elements by hand.
6087 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6088 // The mask element. This indexes into the input.
6089 int Idx = Mask[FirstMaskIdx + MaskOffset];
6090
6091 // The input vector this mask element indexes into.
6092 unsigned Input = (unsigned)Idx / NewElts;
6093
6094 if (Input >= std::size(Inputs)) {
6095 // The mask element is "undef" or indexes off the end of the input.
6096 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6097 continue;
6098 }
6099
6100 // Turn the index into an offset from the start of the input vector.
6101 Idx -= Input * NewElts;
6102
6103 // Extract the vector element by hand.
6104 SVOps.push_back(MIRBuilder
6105 .buildExtractVectorElement(
6106 EltTy, Inputs[Input],
6107 MIRBuilder.buildConstant(LLT::integer(32), Idx))
6108 .getReg(0));
6109 }
6110
6111 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6112 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6113 } else if (InputUsed[0] == -1U) {
6114 // No input vectors were used! The result is undefined.
6115 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6116 } else if (NewElts == 1) {
6117 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6118 } else {
6119 Register Op0 = Inputs[InputUsed[0]];
6120 // If only one input was used, use an undefined vector for the other.
6121 Register Op1 = InputUsed[1] == -1U
6122 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6123 : Inputs[InputUsed[1]];
6124 // At least one input vector was used. Create a new shuffle vector.
6125 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6126 }
6127
6128 Ops.clear();
6129 }
6130
6131 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6132 MI.eraseFromParent();
6133 return Legalized;
6134}
6135
6137 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6138 auto &RdxMI = cast<GVecReduce>(MI);
6139
6140 if (TypeIdx != 1)
6141 return UnableToLegalize;
6142
6143 // The semantics of the normal non-sequential reductions allow us to freely
6144 // re-associate the operation.
6145 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6146
6147 if (NarrowTy.isVector() &&
6148 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6149 return UnableToLegalize;
6150
6151 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6152 SmallVector<Register> SplitSrcs;
6153 // If NarrowTy is a scalar then we're being asked to scalarize.
6154 const unsigned NumParts =
6155 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6156 : SrcTy.getNumElements();
6157
6158 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6159 if (NarrowTy.isScalar()) {
6160 if (DstTy != NarrowTy)
6161 return UnableToLegalize; // FIXME: handle implicit extensions.
6162
6163 if (isPowerOf2_32(NumParts)) {
6164 // Generate a tree of scalar operations to reduce the critical path.
6165 SmallVector<Register> PartialResults;
6166 unsigned NumPartsLeft = NumParts;
6167 while (NumPartsLeft > 1) {
6168 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6169 PartialResults.emplace_back(
6171 .buildInstr(ScalarOpc, {NarrowTy},
6172 {SplitSrcs[Idx], SplitSrcs[Idx + 1]},
6173 MI.getFlags())
6174 .getReg(0));
6175 }
6176 SplitSrcs = PartialResults;
6177 PartialResults.clear();
6178 NumPartsLeft = SplitSrcs.size();
6179 }
6180 assert(SplitSrcs.size() == 1);
6181 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6182 MI.eraseFromParent();
6183 return Legalized;
6184 }
6185 // If we can't generate a tree, then just do sequential operations.
6186 Register Acc = SplitSrcs[0];
6187 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6188 Acc = MIRBuilder
6189 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]},
6190 MI.getFlags())
6191 .getReg(0);
6192 MIRBuilder.buildCopy(DstReg, Acc);
6193 MI.eraseFromParent();
6194 return Legalized;
6195 }
6196 SmallVector<Register> PartialReductions;
6197 for (unsigned Part = 0; Part < NumParts; ++Part) {
6198 PartialReductions.push_back(MIRBuilder
6199 .buildInstr(RdxMI.getOpcode(), {DstTy},
6200 {SplitSrcs[Part]},
6201 MI.getFlags())
6202 .getReg(0));
6203 }
6204
6205 // If the types involved are powers of 2, we can generate intermediate vector
6206 // ops, before generating a final reduction operation.
6207 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6208 isPowerOf2_32(NarrowTy.getNumElements())) {
6209 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6210 }
6211
6212 Register Acc = PartialReductions[0];
6213 for (unsigned Part = 1; Part < NumParts; ++Part) {
6214 if (Part == NumParts - 1) {
6215 MIRBuilder.buildInstr(ScalarOpc, {DstReg}, {Acc, PartialReductions[Part]},
6216 MI.getFlags());
6217 } else {
6218 Acc = MIRBuilder
6219 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]},
6220 MI.getFlags())
6221 .getReg(0);
6222 }
6223 }
6224 MI.eraseFromParent();
6225 return Legalized;
6226}
6227
6230 unsigned int TypeIdx,
6231 LLT NarrowTy) {
6232 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6233 MI.getFirst3RegLLTs();
6234 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6235 DstTy != NarrowTy)
6236 return UnableToLegalize;
6237
6238 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6239 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6240 "Unexpected vecreduce opcode");
6241 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6242 ? TargetOpcode::G_FADD
6243 : TargetOpcode::G_FMUL;
6244
6245 SmallVector<Register> SplitSrcs;
6246 unsigned NumParts = SrcTy.getNumElements();
6247 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6248 Register Acc = ScalarReg;
6249 for (unsigned i = 0; i < NumParts; i++)
6250 Acc = MIRBuilder
6251 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]},
6252 MI.getFlags())
6253 .getReg(0);
6254
6255 MIRBuilder.buildCopy(DstReg, Acc);
6256 MI.eraseFromParent();
6257 return Legalized;
6258}
6259
6261LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6262 LLT SrcTy, LLT NarrowTy,
6263 unsigned ScalarOpc) {
6264 SmallVector<Register> SplitSrcs;
6265 // Split the sources into NarrowTy size pieces.
6266 extractParts(SrcReg, NarrowTy,
6267 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6268 MIRBuilder, MRI);
6269 // We're going to do a tree reduction using vector operations until we have
6270 // one NarrowTy size value left.
6271 while (SplitSrcs.size() > 1) {
6272 SmallVector<Register> PartialRdxs;
6273 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6274 Register LHS = SplitSrcs[Idx];
6275 Register RHS = SplitSrcs[Idx + 1];
6276 // Create the intermediate vector op.
6277 Register Res =
6279 .buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}, MI.getFlags())
6280 .getReg(0);
6281 PartialRdxs.push_back(Res);
6282 }
6283 SplitSrcs = std::move(PartialRdxs);
6284 }
6285 // Finally generate the requested NarrowTy based reduction.
6286 Observer.changingInstr(MI);
6287 MI.getOperand(1).setReg(SplitSrcs[0]);
6288 Observer.changedInstr(MI);
6289 return Legalized;
6290}
6291
6294 const LLT HalfTy, const LLT AmtTy) {
6295
6296 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6297 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6298 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6299
6300 if (Amt.isZero()) {
6301 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6302 MI.eraseFromParent();
6303 return Legalized;
6304 }
6305
6306 LLT NVT = HalfTy;
6307 unsigned NVTBits = HalfTy.getSizeInBits();
6308 unsigned VTBits = 2 * NVTBits;
6309
6310 SrcOp Lo(Register(0)), Hi(Register(0));
6311 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6312 if (Amt.ugt(VTBits)) {
6313 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6314 } else if (Amt.ugt(NVTBits)) {
6315 Lo = MIRBuilder.buildConstant(NVT, 0);
6316 Hi = MIRBuilder.buildShl(NVT, InL,
6317 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6318 } else if (Amt == NVTBits) {
6319 Lo = MIRBuilder.buildConstant(NVT, 0);
6320 Hi = InL;
6321 } else {
6322 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6323 auto OrLHS =
6324 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6325 auto OrRHS = MIRBuilder.buildLShr(
6326 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6327 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6328 }
6329 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6330 if (Amt.ugt(VTBits)) {
6331 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6332 } else if (Amt.ugt(NVTBits)) {
6333 Lo = MIRBuilder.buildLShr(NVT, InH,
6334 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6335 Hi = MIRBuilder.buildConstant(NVT, 0);
6336 } else if (Amt == NVTBits) {
6337 Lo = InH;
6338 Hi = MIRBuilder.buildConstant(NVT, 0);
6339 } else {
6340 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6341
6342 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6343 auto OrRHS = MIRBuilder.buildShl(
6344 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6345
6346 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6347 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6348 }
6349 } else {
6350 if (Amt.ugt(VTBits)) {
6351 Hi = Lo = MIRBuilder.buildAShr(
6352 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6353 } else if (Amt.ugt(NVTBits)) {
6354 Lo = MIRBuilder.buildAShr(NVT, InH,
6355 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6356 Hi = MIRBuilder.buildAShr(NVT, InH,
6357 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6358 } else if (Amt == NVTBits) {
6359 Lo = InH;
6360 Hi = MIRBuilder.buildAShr(NVT, InH,
6361 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6362 } else {
6363 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6364
6365 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6366 auto OrRHS = MIRBuilder.buildShl(
6367 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6368
6369 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6370 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6371 }
6372 }
6373
6374 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6375 MI.eraseFromParent();
6376
6377 return Legalized;
6378}
6379
6382 LLT RequestedTy) {
6383 if (TypeIdx == 1) {
6384 Observer.changingInstr(MI);
6385 narrowScalarSrc(MI, RequestedTy, 2);
6386 Observer.changedInstr(MI);
6387 return Legalized;
6388 }
6389
6390 Register DstReg = MI.getOperand(0).getReg();
6391 LLT DstTy = MRI.getType(DstReg);
6392 if (DstTy.isVector())
6393 return UnableToLegalize;
6394
6395 Register Amt = MI.getOperand(2).getReg();
6396 LLT ShiftAmtTy = MRI.getType(Amt);
6397 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6398 if (DstEltSize % 2 != 0)
6399 return UnableToLegalize;
6400
6401 // Check if we should use multi-way splitting instead of recursive binary
6402 // splitting.
6403 //
6404 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6405 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6406 // and dependency chains created by usual binary splitting approach
6407 // (128->64->32).
6408 //
6409 // The >= 8 parts threshold ensures we only use this optimization when binary
6410 // splitting would require multiple recursive passes, avoiding overhead for
6411 // simple 2-way splits where binary approach is sufficient.
6412 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6413 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6414 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6415 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6416 // steps).
6417 if (NumParts >= 8)
6418 return narrowScalarShiftMultiway(MI, RequestedTy);
6419 }
6420
6421 // Fall back to binary splitting:
6422 // Ignore the input type. We can only go to exactly half the size of the
6423 // input. If that isn't small enough, the resulting pieces will be further
6424 // legalized.
6425 const unsigned NewBitSize = DstEltSize / 2;
6426 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6427 const LLT CondTy = LLT::integer(1);
6428
6429 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6430 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6431 ShiftAmtTy);
6432 }
6433
6434 // TODO: Expand with known bits.
6435
6436 // Handle the fully general expansion by an unknown amount.
6437 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6438
6439 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6440 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6441 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6442
6443 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6444 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6445
6446 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6447 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6448 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6449
6450 Register ResultRegs[2];
6451 switch (MI.getOpcode()) {
6452 case TargetOpcode::G_SHL: {
6453 // Short: ShAmt < NewBitSize
6454 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6455
6456 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6457 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6458 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6459
6460 // Long: ShAmt >= NewBitSize
6461 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6462 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6463
6464 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6465 auto Hi = MIRBuilder.buildSelect(
6466 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6467
6468 ResultRegs[0] = Lo.getReg(0);
6469 ResultRegs[1] = Hi.getReg(0);
6470 break;
6471 }
6472 case TargetOpcode::G_LSHR:
6473 case TargetOpcode::G_ASHR: {
6474 // Short: ShAmt < NewBitSize
6475 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6476
6477 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6478 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6479 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6480
6481 // Long: ShAmt >= NewBitSize
6483 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6484 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6485 } else {
6486 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6487 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6488 }
6489 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6490 {InH, AmtExcess}); // Lo from Hi part.
6491
6492 auto Lo = MIRBuilder.buildSelect(
6493 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6494
6495 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6496
6497 ResultRegs[0] = Lo.getReg(0);
6498 ResultRegs[1] = Hi.getReg(0);
6499 break;
6500 }
6501 default:
6502 llvm_unreachable("not a shift");
6503 }
6504
6505 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6506 MI.eraseFromParent();
6507 return Legalized;
6508}
6509
6511 unsigned PartIdx,
6512 unsigned NumParts,
6513 ArrayRef<Register> SrcParts,
6514 const ShiftParams &Params,
6515 LLT TargetTy, LLT ShiftAmtTy) {
6516 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6517 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6518 assert(WordShiftConst && BitShiftConst && "Expected constants");
6519
6520 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6521 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6522 const bool NeedsInterWordShift = ShiftBits != 0;
6523
6524 switch (Opcode) {
6525 case TargetOpcode::G_SHL: {
6526 // Data moves from lower indices to higher indices
6527 // If this part would come from a source beyond our range, it's zero
6528 if (PartIdx < ShiftWords)
6529 return Params.Zero;
6530
6531 unsigned SrcIdx = PartIdx - ShiftWords;
6532 if (!NeedsInterWordShift)
6533 return SrcParts[SrcIdx];
6534
6535 // Combine shifted main part with carry from previous part
6536 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6537 if (SrcIdx > 0) {
6538 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6539 Params.InvBitShift);
6540 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6541 }
6542 return Hi.getReg(0);
6543 }
6544
6545 case TargetOpcode::G_LSHR: {
6546 unsigned SrcIdx = PartIdx + ShiftWords;
6547 if (SrcIdx >= NumParts)
6548 return Params.Zero;
6549 if (!NeedsInterWordShift)
6550 return SrcParts[SrcIdx];
6551
6552 // Combine shifted main part with carry from next part
6553 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6554 if (SrcIdx + 1 < NumParts) {
6555 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6556 Params.InvBitShift);
6557 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6558 }
6559 return Lo.getReg(0);
6560 }
6561
6562 case TargetOpcode::G_ASHR: {
6563 // Like LSHR but preserves sign bit
6564 unsigned SrcIdx = PartIdx + ShiftWords;
6565 if (SrcIdx >= NumParts)
6566 return Params.SignBit;
6567 if (!NeedsInterWordShift)
6568 return SrcParts[SrcIdx];
6569
6570 // Only the original MSB part uses arithmetic shift to preserve sign. All
6571 // other parts use logical shift since they're just moving data bits.
6572 auto Lo =
6573 (SrcIdx == NumParts - 1)
6574 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6575 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6576 Register HiSrc =
6577 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6578 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6579 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6580 }
6581
6582 default:
6583 llvm_unreachable("not a shift");
6584 }
6585}
6586
6588 Register MainOperand,
6589 Register ShiftAmt,
6590 LLT TargetTy,
6591 Register CarryOperand) {
6592 // This helper generates a single output part for variable shifts by combining
6593 // the main operand (shifted by BitShift) with carry bits from an adjacent
6594 // part.
6595
6596 // For G_ASHR, individual parts don't have their own sign bit, only the
6597 // complete value does. So we use LSHR for the main operand shift in ASHR
6598 // context.
6599 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6600 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6601 : Opcode;
6602
6603 // Perform the primary shift on the main operand
6604 Register MainShifted =
6605 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6606 .getReg(0);
6607
6608 // No carry operand available
6609 if (!CarryOperand.isValid())
6610 return MainShifted;
6611
6612 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6613 // so carry bits aren't needed.
6614 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6615 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6616 LLT BoolTy = LLT::integer(1);
6617 auto IsZeroBitShift =
6618 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6619
6620 // Extract bits from the adjacent part that will "carry over" into this part.
6621 // The carry direction is opposite to the main shift direction, so we can
6622 // align the two shifted values before combining them with OR.
6623
6624 // Determine the carry shift opcode (opposite direction)
6625 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6626 : TargetOpcode::G_SHL;
6627
6628 // Calculate inverse shift amount: BitWidth - ShiftAmt
6629 auto TargetBitsConst =
6630 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6631 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6632
6633 // Shift the carry operand
6634 Register CarryBits =
6636 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6637 .getReg(0);
6638
6639 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6640 // TargetBits which would be poison for the individual carry shift operation).
6641 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6642 Register SafeCarryBits =
6643 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6644 .getReg(0);
6645
6646 // Combine the main shifted part with the carry bits
6647 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6648}
6649
6652 const APInt &Amt,
6653 LLT TargetTy,
6654 LLT ShiftAmtTy) {
6655 // Any wide shift can be decomposed into WordShift + BitShift components.
6656 // When shift amount is known constant, directly compute the decomposition
6657 // values and generate constant registers.
6658 Register DstReg = MI.getOperand(0).getReg();
6659 Register SrcReg = MI.getOperand(1).getReg();
6660 LLT DstTy = MRI.getType(DstReg);
6661
6662 const unsigned DstBits = DstTy.getScalarSizeInBits();
6663 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6664 const unsigned NumParts = DstBits / TargetBits;
6665
6666 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6667
6668 // When the shift amount is known at compile time, we just calculate which
6669 // source parts contribute to each output part.
6670
6671 SmallVector<Register, 8> SrcParts;
6672 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6673
6674 if (Amt.isZero()) {
6675 // No shift needed, just copy
6676 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6677 MI.eraseFromParent();
6678 return Legalized;
6679 }
6680
6681 ShiftParams Params;
6682 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6683 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6684
6685 // Generate constants and values needed by all shift types
6686 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6687 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6688 Params.InvBitShift =
6689 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6690 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6691
6692 // For ASHR, we need the sign-extended value to fill shifted-out positions
6693 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6694 Params.SignBit =
6696 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6697 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6698 .getReg(0);
6699
6700 SmallVector<Register, 8> DstParts(NumParts);
6701 for (unsigned I = 0; I < NumParts; ++I)
6702 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6703 Params, TargetTy, ShiftAmtTy);
6704
6705 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6706 MI.eraseFromParent();
6707 return Legalized;
6708}
6709
6712 Register DstReg = MI.getOperand(0).getReg();
6713 Register SrcReg = MI.getOperand(1).getReg();
6714 Register AmtReg = MI.getOperand(2).getReg();
6715 LLT DstTy = MRI.getType(DstReg);
6716 LLT ShiftAmtTy = MRI.getType(AmtReg);
6717
6718 const unsigned DstBits = DstTy.getScalarSizeInBits();
6719 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6720 const unsigned NumParts = DstBits / TargetBits;
6721
6722 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6723 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6724
6725 // If the shift amount is known at compile time, we can use direct indexing
6726 // instead of generating select chains in the general case.
6727 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6728 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6729 ShiftAmtTy);
6730
6731 // For runtime-variable shift amounts, we must generate a more complex
6732 // sequence that handles all possible shift values using select chains.
6733
6734 // Split the input into target-sized pieces
6735 SmallVector<Register, 8> SrcParts;
6736 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6737
6738 // Shifting by zero should be a no-op.
6739 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6740 LLT BoolTy = LLT::integer(1);
6741 auto IsZeroShift =
6742 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6743
6744 // Any wide shift can be decomposed into two components:
6745 // 1. WordShift: number of complete target-sized words to shift
6746 // 2. BitShift: number of bits to shift within each word
6747 //
6748 // Example: 128-bit >> 50 with 32-bit target:
6749 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6750 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6751 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6752 auto TargetBitsLog2Const =
6753 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6754 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6755
6756 Register WordShift =
6757 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6758 Register BitShift =
6759 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6760
6761 // Fill values:
6762 // - SHL/LSHR: fill with zeros
6763 // - ASHR: fill with sign-extended MSB
6764 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6765
6766 Register FillValue;
6767 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6768 auto TargetBitsMinusOneConst =
6769 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6770 FillValue = MIRBuilder
6771 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6772 TargetBitsMinusOneConst)
6773 .getReg(0);
6774 } else {
6775 FillValue = ZeroReg;
6776 }
6777
6778 SmallVector<Register, 8> DstParts(NumParts);
6779
6780 // For each output part, generate a select chain that chooses the correct
6781 // result based on the runtime WordShift value. This handles all possible
6782 // word shift amounts by pre-calculating what each would produce.
6783 for (unsigned I = 0; I < NumParts; ++I) {
6784 // Initialize with appropriate default value for this shift type
6785 Register InBoundsResult = FillValue;
6786
6787 // clang-format off
6788 // Build a branchless select chain by pre-computing results for all possible
6789 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6790 //
6791 // K=0: select(WordShift==0, result0, FillValue)
6792 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6793 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6794 // clang-format on
6795 for (unsigned K = 0; K < NumParts; ++K) {
6796 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6797 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6798 WordShift, WordShiftKConst);
6799
6800 // Calculate source indices for this word shift
6801 //
6802 // For 4-part 128-bit value with K=1 word shift:
6803 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6804 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6805 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6806 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6807 int MainSrcIdx;
6808 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6809
6810 switch (MI.getOpcode()) {
6811 case TargetOpcode::G_SHL:
6812 MainSrcIdx = (int)I - (int)K;
6813 CarrySrcIdx = MainSrcIdx - 1;
6814 break;
6815 case TargetOpcode::G_LSHR:
6816 case TargetOpcode::G_ASHR:
6817 MainSrcIdx = (int)I + (int)K;
6818 CarrySrcIdx = MainSrcIdx + 1;
6819 break;
6820 default:
6821 llvm_unreachable("Not a shift");
6822 }
6823
6824 // Check bounds and build the result for this word shift
6825 Register ResultForK;
6826 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6827 Register MainOp = SrcParts[MainSrcIdx];
6828 Register CarryOp;
6829
6830 // Determine carry operand with bounds checking
6831 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6832 CarryOp = SrcParts[CarrySrcIdx];
6833 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6834 CarrySrcIdx >= (int)NumParts)
6835 CarryOp = FillValue; // Use sign extension
6836
6837 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6838 TargetTy, CarryOp);
6839 } else {
6840 // Out of bounds - use fill value for this k
6841 ResultForK = FillValue;
6842 }
6843
6844 // Select this result if WordShift equals k
6845 InBoundsResult =
6847 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6848 .getReg(0);
6849 }
6850
6851 // Handle zero-shift special case: if shift is 0, use original input
6852 DstParts[I] =
6854 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6855 .getReg(0);
6856 }
6857
6858 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6859 MI.eraseFromParent();
6860 return Legalized;
6861}
6862
6865 LLT MoreTy) {
6866 assert(TypeIdx == 0 && "Expecting only Idx 0");
6867
6868 Observer.changingInstr(MI);
6869 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6870 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6871 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6872 moreElementsVectorSrc(MI, MoreTy, I);
6873 }
6874
6875 MachineBasicBlock &MBB = *MI.getParent();
6876 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6877 moreElementsVectorDst(MI, MoreTy, 0);
6878 Observer.changedInstr(MI);
6879 return Legalized;
6880}
6881
6882MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6883 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6884 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6885
6886 switch (Opcode) {
6887 default:
6889 "getNeutralElementForVecReduce called with invalid opcode!");
6890 case TargetOpcode::G_VECREDUCE_ADD:
6891 case TargetOpcode::G_VECREDUCE_OR:
6892 case TargetOpcode::G_VECREDUCE_XOR:
6893 case TargetOpcode::G_VECREDUCE_UMAX:
6894 return MIRBuilder.buildConstant(Ty, 0);
6895 case TargetOpcode::G_VECREDUCE_MUL:
6896 return MIRBuilder.buildConstant(Ty, 1);
6897 case TargetOpcode::G_VECREDUCE_AND:
6898 case TargetOpcode::G_VECREDUCE_UMIN:
6900 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6901 case TargetOpcode::G_VECREDUCE_SMAX:
6903 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6904 case TargetOpcode::G_VECREDUCE_SMIN:
6906 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6907 case TargetOpcode::G_VECREDUCE_FADD:
6908 return MIRBuilder.buildFConstant(Ty, -0.0);
6909 case TargetOpcode::G_VECREDUCE_FMUL:
6910 return MIRBuilder.buildFConstant(Ty, 1.0);
6911 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6912 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6913 assert(false && "getNeutralElementForVecReduce unimplemented for "
6914 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6915 }
6916 llvm_unreachable("switch expected to return!");
6917}
6918
6921 LLT MoreTy) {
6922 unsigned Opc = MI.getOpcode();
6923 switch (Opc) {
6924 case TargetOpcode::G_IMPLICIT_DEF:
6925 case TargetOpcode::G_LOAD: {
6926 if (TypeIdx != 0)
6927 return UnableToLegalize;
6928 Observer.changingInstr(MI);
6929 moreElementsVectorDst(MI, MoreTy, 0);
6930 Observer.changedInstr(MI);
6931 return Legalized;
6932 }
6933 case TargetOpcode::G_STORE:
6934 if (TypeIdx != 0)
6935 return UnableToLegalize;
6936 Observer.changingInstr(MI);
6937 moreElementsVectorSrc(MI, MoreTy, 0);
6938 Observer.changedInstr(MI);
6939 return Legalized;
6940 case TargetOpcode::G_AND:
6941 case TargetOpcode::G_OR:
6942 case TargetOpcode::G_XOR:
6943 case TargetOpcode::G_ADD:
6944 case TargetOpcode::G_SUB:
6945 case TargetOpcode::G_MUL:
6946 case TargetOpcode::G_FADD:
6947 case TargetOpcode::G_FSUB:
6948 case TargetOpcode::G_FMUL:
6949 case TargetOpcode::G_FDIV:
6950 case TargetOpcode::G_FCOPYSIGN:
6951 case TargetOpcode::G_UADDSAT:
6952 case TargetOpcode::G_USUBSAT:
6953 case TargetOpcode::G_SADDSAT:
6954 case TargetOpcode::G_SSUBSAT:
6955 case TargetOpcode::G_SMIN:
6956 case TargetOpcode::G_SMAX:
6957 case TargetOpcode::G_UMIN:
6958 case TargetOpcode::G_UMAX:
6959 case TargetOpcode::G_FMINNUM:
6960 case TargetOpcode::G_FMAXNUM:
6961 case TargetOpcode::G_FMINNUM_IEEE:
6962 case TargetOpcode::G_FMAXNUM_IEEE:
6963 case TargetOpcode::G_FMINIMUM:
6964 case TargetOpcode::G_FMAXIMUM:
6965 case TargetOpcode::G_FMINIMUMNUM:
6966 case TargetOpcode::G_FMAXIMUMNUM:
6967 case TargetOpcode::G_STRICT_FADD:
6968 case TargetOpcode::G_STRICT_FSUB:
6969 case TargetOpcode::G_STRICT_FMUL: {
6970 Observer.changingInstr(MI);
6971 moreElementsVectorSrc(MI, MoreTy, 1);
6972 moreElementsVectorSrc(MI, MoreTy, 2);
6973 moreElementsVectorDst(MI, MoreTy, 0);
6974 Observer.changedInstr(MI);
6975 return Legalized;
6976 }
6977 case TargetOpcode::G_SHL:
6978 case TargetOpcode::G_ASHR:
6979 case TargetOpcode::G_LSHR: {
6980 Observer.changingInstr(MI);
6981 moreElementsVectorSrc(MI, MoreTy, 1);
6982 // The shift operand may have a different scalar type from the source and
6983 // destination operands.
6984 LLT ShiftMoreTy = MoreTy.changeElementType(
6985 MRI.getType(MI.getOperand(2).getReg()).getElementType());
6986 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
6987 moreElementsVectorDst(MI, MoreTy, 0);
6988 Observer.changedInstr(MI);
6989 return Legalized;
6990 }
6991 case TargetOpcode::G_FMA:
6992 case TargetOpcode::G_STRICT_FMA:
6993 case TargetOpcode::G_FSHR:
6994 case TargetOpcode::G_FSHL: {
6995 Observer.changingInstr(MI);
6996 moreElementsVectorSrc(MI, MoreTy, 1);
6997 moreElementsVectorSrc(MI, MoreTy, 2);
6998 moreElementsVectorSrc(MI, MoreTy, 3);
6999 moreElementsVectorDst(MI, MoreTy, 0);
7000 Observer.changedInstr(MI);
7001 return Legalized;
7002 }
7003 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
7004 case TargetOpcode::G_EXTRACT:
7005 if (TypeIdx != 1)
7006 return UnableToLegalize;
7007 Observer.changingInstr(MI);
7008 moreElementsVectorSrc(MI, MoreTy, 1);
7009 Observer.changedInstr(MI);
7010 return Legalized;
7011 case TargetOpcode::G_INSERT:
7012 case TargetOpcode::G_INSERT_VECTOR_ELT:
7013 case TargetOpcode::G_FREEZE:
7014 case TargetOpcode::G_FNEG:
7015 case TargetOpcode::G_FABS:
7016 case TargetOpcode::G_FSQRT:
7017 case TargetOpcode::G_FCEIL:
7018 case TargetOpcode::G_FFLOOR:
7019 case TargetOpcode::G_FNEARBYINT:
7020 case TargetOpcode::G_FRINT:
7021 case TargetOpcode::G_INTRINSIC_ROUND:
7022 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
7023 case TargetOpcode::G_INTRINSIC_TRUNC:
7024 case TargetOpcode::G_BITREVERSE:
7025 case TargetOpcode::G_BSWAP:
7026 case TargetOpcode::G_FCANONICALIZE:
7027 case TargetOpcode::G_SEXT_INREG:
7028 case TargetOpcode::G_ABS:
7029 case TargetOpcode::G_CTLZ:
7030 case TargetOpcode::G_CTPOP:
7031 if (TypeIdx != 0)
7032 return UnableToLegalize;
7033 Observer.changingInstr(MI);
7034 moreElementsVectorSrc(MI, MoreTy, 1);
7035 moreElementsVectorDst(MI, MoreTy, 0);
7036 Observer.changedInstr(MI);
7037 return Legalized;
7038 case TargetOpcode::G_SELECT: {
7039 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
7040 if (TypeIdx == 1) {
7041 if (!CondTy.isScalar() ||
7042 DstTy.getElementCount() != MoreTy.getElementCount())
7043 return UnableToLegalize;
7044
7045 // This is turning a scalar select of vectors into a vector
7046 // select. Broadcast the select condition.
7047 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
7048 Observer.changingInstr(MI);
7049 MI.getOperand(1).setReg(ShufSplat.getReg(0));
7050 Observer.changedInstr(MI);
7051 return Legalized;
7052 }
7053
7054 if (CondTy.isVector())
7055 return UnableToLegalize;
7056
7057 Observer.changingInstr(MI);
7058 moreElementsVectorSrc(MI, MoreTy, 2);
7059 moreElementsVectorSrc(MI, MoreTy, 3);
7060 moreElementsVectorDst(MI, MoreTy, 0);
7061 Observer.changedInstr(MI);
7062 return Legalized;
7063 }
7064 case TargetOpcode::G_UNMERGE_VALUES:
7065 return UnableToLegalize;
7066 case TargetOpcode::G_PHI:
7067 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
7068 case TargetOpcode::G_SHUFFLE_VECTOR:
7069 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
7070 case TargetOpcode::G_BUILD_VECTOR: {
7072 for (auto Op : MI.uses()) {
7073 Elts.push_back(Op.getReg());
7074 }
7075
7076 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
7077 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
7078 }
7079
7080 MIRBuilder.buildDeleteTrailingVectorElements(
7081 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
7082 MI.eraseFromParent();
7083 return Legalized;
7084 }
7085 case TargetOpcode::G_SEXT:
7086 case TargetOpcode::G_ZEXT:
7087 case TargetOpcode::G_ANYEXT:
7088 case TargetOpcode::G_TRUNC:
7089 case TargetOpcode::G_FPTRUNC:
7090 case TargetOpcode::G_FPEXT:
7091 case TargetOpcode::G_FPTOSI:
7092 case TargetOpcode::G_FPTOUI:
7093 case TargetOpcode::G_FPTOSI_SAT:
7094 case TargetOpcode::G_FPTOUI_SAT:
7095 case TargetOpcode::G_SITOFP:
7096 case TargetOpcode::G_UITOFP:
7097 case TargetOpcode::G_TRUNC_SSAT_S:
7098 case TargetOpcode::G_TRUNC_SSAT_U:
7099 case TargetOpcode::G_TRUNC_USAT_U: {
7100 Observer.changingInstr(MI);
7101 LLT SrcExtTy;
7102 LLT DstExtTy;
7103 if (TypeIdx == 0) {
7104 DstExtTy = MoreTy;
7105 SrcExtTy = MoreTy.changeElementType(
7106 MRI.getType(MI.getOperand(1).getReg()).getElementType());
7107 } else {
7108 DstExtTy = MoreTy.changeElementType(
7109 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7110 SrcExtTy = MoreTy;
7111 }
7112 moreElementsVectorSrc(MI, SrcExtTy, 1);
7113 moreElementsVectorDst(MI, DstExtTy, 0);
7114 Observer.changedInstr(MI);
7115 return Legalized;
7116 }
7117 case TargetOpcode::G_ICMP:
7118 case TargetOpcode::G_FCMP: {
7119 if (TypeIdx != 1)
7120 return UnableToLegalize;
7121
7122 Observer.changingInstr(MI);
7123 moreElementsVectorSrc(MI, MoreTy, 2);
7124 moreElementsVectorSrc(MI, MoreTy, 3);
7125 LLT CondTy = MoreTy.changeVectorElementType(
7126 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7127 moreElementsVectorDst(MI, CondTy, 0);
7128 Observer.changedInstr(MI);
7129 return Legalized;
7130 }
7131 case TargetOpcode::G_BITCAST: {
7132 if (TypeIdx != 0)
7133 return UnableToLegalize;
7134
7135 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7136 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7137
7138 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7139 if (coefficient % DstTy.getNumElements() != 0)
7140 return UnableToLegalize;
7141
7142 coefficient = coefficient / DstTy.getNumElements();
7143
7144 LLT NewTy = SrcTy.changeElementCount(
7145 ElementCount::get(coefficient, MoreTy.isScalable()));
7146 Observer.changingInstr(MI);
7147 moreElementsVectorSrc(MI, NewTy, 1);
7148 moreElementsVectorDst(MI, MoreTy, 0);
7149 Observer.changedInstr(MI);
7150 return Legalized;
7151 }
7152 case TargetOpcode::G_VECREDUCE_FADD:
7153 case TargetOpcode::G_VECREDUCE_FMUL:
7154 case TargetOpcode::G_VECREDUCE_ADD:
7155 case TargetOpcode::G_VECREDUCE_MUL:
7156 case TargetOpcode::G_VECREDUCE_AND:
7157 case TargetOpcode::G_VECREDUCE_OR:
7158 case TargetOpcode::G_VECREDUCE_XOR:
7159 case TargetOpcode::G_VECREDUCE_SMAX:
7160 case TargetOpcode::G_VECREDUCE_SMIN:
7161 case TargetOpcode::G_VECREDUCE_UMAX:
7162 case TargetOpcode::G_VECREDUCE_UMIN: {
7163 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7164 MachineOperand &MO = MI.getOperand(1);
7165 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7166 auto NeutralElement = getNeutralElementForVecReduce(
7167 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7168
7169 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7170 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7171 i != e; i++) {
7172 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7173 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7174 NeutralElement, Idx);
7175 }
7176
7177 Observer.changingInstr(MI);
7178 MO.setReg(NewVec.getReg(0));
7179 Observer.changedInstr(MI);
7180 return Legalized;
7181 }
7182
7183 default:
7184 return UnableToLegalize;
7185 }
7186}
7187
7190 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7191 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7192 unsigned MaskNumElts = Mask.size();
7193 unsigned SrcNumElts = SrcTy.getNumElements();
7194 LLT DestEltTy = DstTy.getElementType();
7195
7196 if (MaskNumElts == SrcNumElts)
7197 return Legalized;
7198
7199 if (MaskNumElts < SrcNumElts) {
7200 // Extend mask to match new destination vector size with
7201 // undef values.
7202 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7203 llvm::copy(Mask, NewMask.begin());
7204
7205 moreElementsVectorDst(MI, SrcTy, 0);
7206 MIRBuilder.setInstrAndDebugLoc(MI);
7207 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7208 MI.getOperand(1).getReg(),
7209 MI.getOperand(2).getReg(), NewMask);
7210 MI.eraseFromParent();
7211
7212 return Legalized;
7213 }
7214
7215 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7216 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7217 LLT PaddedTy =
7218 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7219
7220 // Create new source vectors by concatenating the initial
7221 // source vectors with undefined vectors of the same size.
7222 auto Undef = MIRBuilder.buildUndef(SrcTy);
7223 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7224 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7225 MOps1[0] = MI.getOperand(1).getReg();
7226 MOps2[0] = MI.getOperand(2).getReg();
7227
7228 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7229 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7230
7231 // Readjust mask for new input vector length.
7232 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7233 for (unsigned I = 0; I != MaskNumElts; ++I) {
7234 int Idx = Mask[I];
7235 if (Idx >= static_cast<int>(SrcNumElts))
7236 Idx += PaddedMaskNumElts - SrcNumElts;
7237 MappedOps[I] = Idx;
7238 }
7239
7240 // If we got more elements than required, extract subvector.
7241 if (MaskNumElts != PaddedMaskNumElts) {
7242 auto Shuffle =
7243 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7244
7245 SmallVector<Register, 16> Elts(MaskNumElts);
7246 for (unsigned I = 0; I < MaskNumElts; ++I) {
7247 Elts[I] =
7248 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7249 .getReg(0);
7250 }
7251 MIRBuilder.buildBuildVector(DstReg, Elts);
7252 } else {
7253 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7254 }
7255
7256 MI.eraseFromParent();
7258}
7259
7262 unsigned int TypeIdx, LLT MoreTy) {
7263 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7264 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7265 unsigned NumElts = DstTy.getNumElements();
7266 unsigned WidenNumElts = MoreTy.getNumElements();
7267
7268 if (DstTy.isVector() && Src1Ty.isVector() &&
7269 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7271 }
7272
7273 if (TypeIdx != 0)
7274 return UnableToLegalize;
7275
7276 // Expect a canonicalized shuffle.
7277 if (DstTy != Src1Ty || DstTy != Src2Ty)
7278 return UnableToLegalize;
7279
7280 moreElementsVectorSrc(MI, MoreTy, 1);
7281 moreElementsVectorSrc(MI, MoreTy, 2);
7282
7283 // Adjust mask based on new input vector length.
7284 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7285 for (unsigned I = 0; I != NumElts; ++I) {
7286 int Idx = Mask[I];
7287 if (Idx < static_cast<int>(NumElts))
7288 NewMask[I] = Idx;
7289 else
7290 NewMask[I] = Idx - NumElts + WidenNumElts;
7291 }
7292 moreElementsVectorDst(MI, MoreTy, 0);
7293 MIRBuilder.setInstrAndDebugLoc(MI);
7294 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7295 MI.getOperand(1).getReg(),
7296 MI.getOperand(2).getReg(), NewMask);
7297 MI.eraseFromParent();
7298 return Legalized;
7299}
7300
7301void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7302 ArrayRef<Register> Src1Regs,
7303 ArrayRef<Register> Src2Regs,
7304 LLT NarrowTy) {
7306 unsigned SrcParts = Src1Regs.size();
7307 unsigned DstParts = DstRegs.size();
7308
7309 unsigned DstIdx = 0; // Low bits of the result.
7310 Register FactorSum =
7311 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7312 DstRegs[DstIdx] = FactorSum;
7313
7314 Register CarrySumPrevDstIdx;
7316
7317 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7318 // Collect high parts of muls from previous DstIdx.
7319 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7320 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7321 MachineInstrBuilder Umulh =
7322 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7323 Factors.push_back(Umulh.getReg(0));
7324 }
7325 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7326 // the low Src1 part, so multiply-add selectors can use it as the first
7327 // accumulated cross product.
7328 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7329 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7330 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7331 unsigned i = RevI - 1;
7333 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7334 Factors.push_back(Mul.getReg(0));
7335 }
7336 // Add CarrySum from additions calculated for previous DstIdx.
7337 if (DstIdx != 1) {
7338 Factors.push_back(CarrySumPrevDstIdx);
7339 }
7340
7341 Register CarrySum;
7342 // Add all factors and accumulate all carries into CarrySum.
7343 if (DstIdx != DstParts - 1) {
7344 MachineInstrBuilder Uaddo =
7345 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7346 FactorSum = Uaddo.getReg(0);
7347 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7348 for (unsigned i = 2; i < Factors.size(); ++i) {
7349 MachineInstrBuilder Uaddo =
7350 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7351 FactorSum = Uaddo.getReg(0);
7352 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7353 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7354 }
7355 } else {
7356 // Since value for the next index is not calculated, neither is CarrySum.
7357 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7358 for (unsigned i = 2; i < Factors.size(); ++i)
7359 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7360 }
7361
7362 CarrySumPrevDstIdx = CarrySum;
7363 DstRegs[DstIdx] = FactorSum;
7364 Factors.clear();
7365 }
7366}
7367
7370 LLT NarrowTy) {
7371 if (TypeIdx != 0)
7372 return UnableToLegalize;
7373
7374 Register DstReg = MI.getOperand(0).getReg();
7375 LLT DstType = MRI.getType(DstReg);
7376 // FIXME: add support for vector types
7377 if (DstType.isVector())
7378 return UnableToLegalize;
7379
7380 unsigned Opcode = MI.getOpcode();
7381 unsigned OpO, OpE, OpF;
7382 switch (Opcode) {
7383 case TargetOpcode::G_SADDO:
7384 case TargetOpcode::G_SADDE:
7385 case TargetOpcode::G_UADDO:
7386 case TargetOpcode::G_UADDE:
7387 case TargetOpcode::G_ADD:
7388 OpO = TargetOpcode::G_UADDO;
7389 OpE = TargetOpcode::G_UADDE;
7390 OpF = TargetOpcode::G_UADDE;
7391 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7392 OpF = TargetOpcode::G_SADDE;
7393 break;
7394 case TargetOpcode::G_SSUBO:
7395 case TargetOpcode::G_SSUBE:
7396 case TargetOpcode::G_USUBO:
7397 case TargetOpcode::G_USUBE:
7398 case TargetOpcode::G_SUB:
7399 OpO = TargetOpcode::G_USUBO;
7400 OpE = TargetOpcode::G_USUBE;
7401 OpF = TargetOpcode::G_USUBE;
7402 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7403 OpF = TargetOpcode::G_SSUBE;
7404 break;
7405 default:
7406 llvm_unreachable("Unexpected add/sub opcode!");
7407 }
7408
7409 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7410 unsigned NumDefs = MI.getNumExplicitDefs();
7411 Register Src1 = MI.getOperand(NumDefs).getReg();
7412 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7413 Register CarryDst, CarryIn;
7414 if (NumDefs == 2)
7415 CarryDst = MI.getOperand(1).getReg();
7416 if (MI.getNumOperands() == NumDefs + 3)
7417 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7418
7419 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7420 LLT LeftoverTy, DummyTy;
7421 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7422 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7423 MIRBuilder, MRI);
7424 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7425 MRI);
7426
7427 int NarrowParts = Src1Regs.size();
7428 Src1Regs.append(Src1Left);
7429 Src2Regs.append(Src2Left);
7430 DstRegs.reserve(Src1Regs.size());
7431
7432 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7433 Register DstReg =
7434 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7435 Register CarryOut;
7436 // Forward the final carry-out to the destination register
7437 if (i == e - 1 && CarryDst)
7438 CarryOut = CarryDst;
7439 else
7440 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7441
7442 if (!CarryIn) {
7443 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7444 {Src1Regs[i], Src2Regs[i]});
7445 } else if (i == e - 1) {
7446 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7447 {Src1Regs[i], Src2Regs[i], CarryIn});
7448 } else {
7449 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7450 {Src1Regs[i], Src2Regs[i], CarryIn});
7451 }
7452
7453 DstRegs.push_back(DstReg);
7454 CarryIn = CarryOut;
7455 }
7456 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7457 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7458 ArrayRef(DstRegs).drop_front(NarrowParts));
7459
7460 MI.eraseFromParent();
7461 return Legalized;
7462}
7463
7466 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7467
7468 LLT Ty = MRI.getType(DstReg);
7469 if (Ty.isVector())
7470 return UnableToLegalize;
7471
7472 unsigned Size = Ty.getSizeInBits();
7473 unsigned NarrowSize = NarrowTy.getSizeInBits();
7474 if (Size % NarrowSize != 0)
7475 return UnableToLegalize;
7476
7477 unsigned NumParts = Size / NarrowSize;
7478 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
7479 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7480
7481 SmallVector<Register, 2> Src1Parts, Src2Parts;
7482 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7483 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7484 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7485 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7486
7487 // Take only high half of registers if this is high mul.
7488 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7489 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7490 MI.eraseFromParent();
7491 return Legalized;
7492}
7493
7496 LLT NarrowTy) {
7497 if (TypeIdx != 0)
7498 return UnableToLegalize;
7499
7500 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7501
7502 Register Src = MI.getOperand(1).getReg();
7503 LLT SrcTy = MRI.getType(Src);
7504
7505 // If all finite floats fit into the narrowed integer type, we can just swap
7506 // out the result type. Only IEEE half qualifies: bfloat is also 16 bits wide
7507 // but has float's exponent range. LLT::float16() is equivalent to
7508 // LLT::scalar(16) on targets without extended LLTs.
7509 if (SrcTy.getScalarType() != LLT::float16() ||
7510 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7511 return UnableToLegalize;
7512
7513 Observer.changingInstr(MI);
7514 narrowScalarDst(MI, NarrowTy, 0,
7515 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7516 Observer.changedInstr(MI);
7517 return Legalized;
7518}
7519
7522 LLT NarrowTy) {
7523 if (TypeIdx != 1)
7524 return UnableToLegalize;
7525
7526 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7527
7528 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7529 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7530 // NarrowSize.
7531 if (SizeOp1 % NarrowSize != 0)
7532 return UnableToLegalize;
7533 int NumParts = SizeOp1 / NarrowSize;
7534
7535 SmallVector<Register, 2> SrcRegs, DstRegs;
7536 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7537 MIRBuilder, MRI);
7538
7539 Register OpReg = MI.getOperand(0).getReg();
7540 uint64_t OpStart = MI.getOperand(2).getImm();
7541 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7542 for (int i = 0; i < NumParts; ++i) {
7543 unsigned SrcStart = i * NarrowSize;
7544
7545 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7546 // No part of the extract uses this subregister, ignore it.
7547 continue;
7548 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7549 // The entire subregister is extracted, forward the value.
7550 DstRegs.push_back(SrcRegs[i]);
7551 continue;
7552 }
7553
7554 // OpSegStart is where this destination segment would start in OpReg if it
7555 // extended infinitely in both directions.
7556 int64_t ExtractOffset;
7557 uint64_t SegSize;
7558 if (OpStart < SrcStart) {
7559 ExtractOffset = 0;
7560 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7561 } else {
7562 ExtractOffset = OpStart - SrcStart;
7563 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7564 }
7565
7566 Register SegReg = SrcRegs[i];
7567 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7568 // A genuine extract is needed.
7569 SegReg = MRI.createGenericVirtualRegister(LLT::integer(SegSize));
7570 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7571 }
7572
7573 DstRegs.push_back(SegReg);
7574 }
7575
7576 Register DstReg = MI.getOperand(0).getReg();
7577 if (MRI.getType(DstReg).isVector())
7578 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7579 else if (DstRegs.size() > 1)
7580 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7581 else
7582 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7583 MI.eraseFromParent();
7584 return Legalized;
7585}
7586
7589 LLT NarrowTy) {
7590 // FIXME: Don't know how to handle secondary types yet.
7591 if (TypeIdx != 0)
7592 return UnableToLegalize;
7593
7594 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7595 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7596 LLT LeftoverTy;
7597 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7598 LeftoverRegs, MIRBuilder, MRI);
7599
7600 SrcRegs.append(LeftoverRegs);
7601
7602 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7603 Register OpReg = MI.getOperand(2).getReg();
7604 uint64_t OpStart = MI.getOperand(3).getImm();
7605 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7606 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7607 unsigned DstStart = I * NarrowSize;
7608
7609 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7610 // The entire subregister is defined by this insert, forward the new
7611 // value.
7612 DstRegs.push_back(OpReg);
7613 continue;
7614 }
7615
7616 Register SrcReg = SrcRegs[I];
7617 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7618 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7619 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7620 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7621 }
7622
7623 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7624 // No part of the insert affects this subregister, forward the original.
7625 DstRegs.push_back(SrcReg);
7626 continue;
7627 }
7628
7629 // OpSegStart is where this destination segment would start in OpReg if it
7630 // extended infinitely in both directions.
7631 int64_t ExtractOffset, InsertOffset;
7632 uint64_t SegSize;
7633 if (OpStart < DstStart) {
7634 InsertOffset = 0;
7635 ExtractOffset = DstStart - OpStart;
7636 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7637 } else {
7638 InsertOffset = OpStart - DstStart;
7639 ExtractOffset = 0;
7640 SegSize =
7641 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
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:348
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
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
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:1972
LLVM_ABI MachineInstr * getOpcodeDef(unsigned Opcode, Register Reg, const MachineRegisterInfo &MRI)
See if Reg is defined by an single def instruction that is Opcode.
Definition Utils.cpp:656
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h: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 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
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, std::function< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
Definition Utils.cpp:1572
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h: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:2139
To bit_cast(const From &from) noexcept
Definition bit.h:90
@ Mul
Product of integers.
@ FSub
Subtraction of floats.
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
IntPtrTy
Definition InstrProf.h:82
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h: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.