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