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.
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
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,
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 // Check if tail calls have been disabled in this function.
553 if (F.getFnAttribute("disable-tail-calls").getValueAsBool())
554 return false;
555
556 // Only tail call if the following instruction is a standard return or if we
557 // have a `thisreturn` callee, and a sequence like:
558 //
559 // G_MEMCPY %0, %1, %2
560 // $x0 = COPY %0
561 // RET_ReallyLR implicit $x0
562 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
563 if (Next != MBB.instr_end() && Next->isCopy()) {
564 if (MI.getOpcode() == TargetOpcode::G_BZERO)
565 return false;
566
567 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
568 // mempy/etc routines return the same parameter. For other it will be the
569 // returned value.
570 Register VReg = MI.getOperand(0).getReg();
571 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
572 return false;
573
574 Register PReg = Next->getOperand(0).getReg();
575 if (!PReg.isPhysical())
576 return false;
577
578 auto Ret = next_nodbg(Next, MBB.instr_end());
579 if (Ret == MBB.instr_end() || !Ret->isReturn())
580 return false;
581
582 if (Ret->getNumImplicitOperands() != 1)
583 return false;
584
585 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
586 return false;
587
588 // Skip over the COPY that we just validated.
589 Next = Ret;
590 }
591
592 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
593 return false;
594
595 return true;
596}
597
599 const char *Name, const CallLowering::ArgInfo &Result,
601 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
602 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
603
605 Info.CallConv = CC;
606 Info.Callee = MachineOperand::CreateES(Name);
607 Info.OrigRet = Result;
608 if (MI)
609 Info.IsTailCall =
610 (Result.Ty->isVoidTy() ||
611 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
612 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
613 *MIRBuilder.getMRI()) &&
614 // Lowering doesn't support tail calling inside a function with
615 // a swifterror argument yet.
617
618 llvm::append_range(Info.OrigArgs, Args);
619 if (!CLI.lowerCall(MIRBuilder, Info))
621
622 if (MI && Info.LoweredTailCall) {
623 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
624
625 // Check debug locations before removing the return.
626 LocObserver.checkpoint(true);
627
628 // We must have a return following the call (or debug insts) to get past
629 // isLibCallInTailPosition.
630 do {
631 MachineInstr *Next = MI->getNextNode();
632 assert(Next &&
633 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
634 "Expected instr following MI to be return or debug inst?");
635 // We lowered a tail call, so the call is now the return from the block.
636 // Delete the old return.
637 Next->eraseFromParent();
638 } while (MI->getNextNode());
639
640 // We expect to lose the debug location from the return.
641 LocObserver.checkpoint(false);
642 }
644}
645
647 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
649 MachineInstr *MI) const {
650 if (!Libcalls)
652
653 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
654 if (LibcallImpl == RTLIB::Unsupported)
656
658 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
659 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
660}
661
662// Useful for libcalls where all operands have the same type.
665 unsigned Size, Type *OpType,
666 LostDebugLocObserver &LocObserver) const {
667 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
668
669 // FIXME: What does the original arg index mean here?
671 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
672 Args.push_back({MO.getReg(), OpType, 0});
673 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
674 LocObserver, &MI);
675}
676
677LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
678 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
679 LostDebugLocObserver &LocObserver) {
680 MachineFunction &MF = *MI.getMF();
682
683 Register DstSin = MI.getOperand(0).getReg();
684 Register DstCos = MI.getOperand(1).getReg();
685 Register Src = MI.getOperand(2).getReg();
686 LLT DstTy = MRI.getType(DstSin);
687
688 int MemSize = DstTy.getSizeInBytes();
689 Align Alignment = getStackTemporaryAlignment(DstTy);
691 unsigned AddrSpace = DL.getAllocaAddrSpace();
692 MachinePointerInfo PtrInfo;
693
694 Register StackPtrSin =
695 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
696 .getReg(0);
697 Register StackPtrCos =
698 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
699 .getReg(0);
700
701 auto &Ctx = MF.getFunction().getContext();
702 auto LibcallResult = createLibcall(
703 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
704 {{Src, OpType, 0},
705 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
706 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
707 LocObserver, &MI);
708
709 if (LibcallResult != LegalizeResult::Legalized)
711
713 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
715 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
716
717 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
718 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
719 MI.eraseFromParent();
720
722}
723
725LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
726 unsigned Size, Type *OpType,
727 LostDebugLocObserver &LocObserver) {
728 MachineFunction &MF = MIRBuilder.getMF();
729 MachineRegisterInfo &MRI = MF.getRegInfo();
730
731 Register DstFrac = MI.getOperand(0).getReg();
732 Register DstInt = MI.getOperand(1).getReg();
733 Register Src = MI.getOperand(2).getReg();
734 LLT DstTy = MRI.getType(DstFrac);
735
736 int MemSize = DstTy.getSizeInBytes();
738 const DataLayout &DL = MIRBuilder.getDataLayout();
739 unsigned AddrSpace = DL.getAllocaAddrSpace();
740 MachinePointerInfo PtrInfo;
741
742 Register StackPtrInt =
743 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
744 .getReg(0);
745
746 auto &Ctx = MF.getFunction().getContext();
747 auto LibcallResult = createLibcall(
748 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
749 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
750 LocObserver, &MI);
751
752 if (LibcallResult != LegalizeResult::Legalized)
754
756 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
757
758 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
759 MI.eraseFromParent();
760
762}
763
764static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
765 Type *FromType) {
766 auto ToMVT = MVT::getVT(ToType);
767 auto FromMVT = MVT::getVT(FromType);
768
769 switch (Opcode) {
770 case TargetOpcode::G_FPEXT:
771 return RTLIB::getFPEXT(FromMVT, ToMVT);
772 case TargetOpcode::G_FPTRUNC:
773 return RTLIB::getFPROUND(FromMVT, ToMVT);
774 case TargetOpcode::G_FPTOSI:
775 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
776 case TargetOpcode::G_FPTOUI:
777 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
778 case TargetOpcode::G_SITOFP:
779 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
780 case TargetOpcode::G_UITOFP:
781 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
782 }
783 llvm_unreachable("Unsupported libcall function");
784}
785
787 MachineInstr &MI, Type *ToType, Type *FromType,
788 LostDebugLocObserver &LocObserver, bool IsSigned) const {
789 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
790 if (FromType->isIntegerTy()) {
791 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
792 Arg.Flags[0].setSExt();
793 else
794 Arg.Flags[0].setZExt();
795 }
796
797 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
798 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
799 LocObserver, &MI);
800}
801
804 LostDebugLocObserver &LocObserver) const {
805 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
806
808 // Add all the args, except for the last which is an imm denoting 'tail'.
809 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
810 Register Reg = MI.getOperand(i).getReg();
811
812 // Need derive an IR type for call lowering.
813 LLT OpLLT = MRI.getType(Reg);
814 Type *OpTy = nullptr;
815 if (OpLLT.isPointer())
816 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
817 else
818 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
819 Args.push_back({Reg, OpTy, 0});
820 }
821
822 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
823 RTLIB::Libcall RTLibcall;
824 unsigned Opc = MI.getOpcode();
825 switch (Opc) {
826 case TargetOpcode::G_BZERO:
827 RTLibcall = RTLIB::BZERO;
828 break;
829 case TargetOpcode::G_MEMCPY:
830 RTLibcall = RTLIB::MEMCPY;
831 Args[0].Flags[0].setReturned();
832 break;
833 case TargetOpcode::G_MEMMOVE:
834 RTLibcall = RTLIB::MEMMOVE;
835 Args[0].Flags[0].setReturned();
836 break;
837 case TargetOpcode::G_MEMSET:
838 RTLibcall = RTLIB::MEMSET;
839 Args[0].Flags[0].setReturned();
840 break;
841 default:
842 llvm_unreachable("unsupported opcode");
843 }
844
845 if (!Libcalls) // FIXME: Should be mandatory
847
848 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
849
850 // Unsupported libcall on the target.
851 if (RTLibcallImpl == RTLIB::Unsupported) {
852 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
853 << MIRBuilder.getTII().getName(Opc) << "\n");
855 }
856
858 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
859
860 StringRef LibcallName =
862 Info.Callee = MachineOperand::CreateES(LibcallName.data());
863 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
864 Info.IsTailCall =
865 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
866 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI) &&
867 // Lowering doesn't support tail calling inside a function with
868 // a swifterror argument yet.
870
871 llvm::append_range(Info.OrigArgs, Args);
872 if (!CLI.lowerCall(MIRBuilder, Info))
874
875 if (Info.LoweredTailCall) {
876 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
877
878 // Check debug locations before removing the return.
879 LocObserver.checkpoint(true);
880
881 // We must have a return following the call (or debug insts) to get past
882 // isLibCallInTailPosition.
883 do {
884 MachineInstr *Next = MI.getNextNode();
885 assert(Next &&
886 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
887 "Expected instr following MI to be return or debug inst?");
888 // We lowered a tail call, so the call is now the return from the block.
889 // Delete the old return.
890 Next->eraseFromParent();
891 } while (MI.getNextNode());
892
893 // We expect to lose the debug location from the return.
894 LocObserver.checkpoint(false);
895 }
896
898}
899
900static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
901 unsigned Opc = MI.getOpcode();
902 auto &AtomicMI = cast<GMemOperation>(MI);
903 auto &MMO = AtomicMI.getMMO();
904 auto Ordering = MMO.getMergedOrdering();
905 LLT MemType = MMO.getMemoryType();
906 uint64_t MemSize = MemType.getSizeInBytes();
907 if (MemType.isVector())
908 return RTLIB::UNKNOWN_LIBCALL;
909
910#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
911#define LCALL5(A) \
912 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
913 switch (Opc) {
914 case TargetOpcode::G_ATOMIC_CMPXCHG:
915 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
916 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
917 return getOutlineAtomicHelper(LC, Ordering, MemSize);
918 }
919 case TargetOpcode::G_ATOMICRMW_XCHG: {
920 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
921 return getOutlineAtomicHelper(LC, Ordering, MemSize);
922 }
923 case TargetOpcode::G_ATOMICRMW_ADD:
924 case TargetOpcode::G_ATOMICRMW_SUB: {
925 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
926 return getOutlineAtomicHelper(LC, Ordering, MemSize);
927 }
928 case TargetOpcode::G_ATOMICRMW_AND: {
929 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
930 return getOutlineAtomicHelper(LC, Ordering, MemSize);
931 }
932 case TargetOpcode::G_ATOMICRMW_OR: {
933 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
934 return getOutlineAtomicHelper(LC, Ordering, MemSize);
935 }
936 case TargetOpcode::G_ATOMICRMW_XOR: {
937 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
938 return getOutlineAtomicHelper(LC, Ordering, MemSize);
939 }
940 default:
941 return RTLIB::UNKNOWN_LIBCALL;
942 }
943#undef LCALLS
944#undef LCALL5
945}
946
949 auto &Ctx = MIRBuilder.getContext();
950
951 Type *RetTy;
952 SmallVector<Register> RetRegs;
954 unsigned Opc = MI.getOpcode();
955 switch (Opc) {
956 case TargetOpcode::G_ATOMIC_CMPXCHG:
957 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
959 LLT SuccessLLT;
960 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
961 MI.getFirst4RegLLTs();
962 RetRegs.push_back(Ret);
963 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
964 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
965 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
966 NewLLT) = MI.getFirst5RegLLTs();
967 RetRegs.push_back(Success);
968 RetTy = StructType::get(
969 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
970 }
971 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
972 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
973 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
974 break;
975 }
976 case TargetOpcode::G_ATOMICRMW_XCHG:
977 case TargetOpcode::G_ATOMICRMW_ADD:
978 case TargetOpcode::G_ATOMICRMW_SUB:
979 case TargetOpcode::G_ATOMICRMW_AND:
980 case TargetOpcode::G_ATOMICRMW_OR:
981 case TargetOpcode::G_ATOMICRMW_XOR: {
982 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
983 RetRegs.push_back(Ret);
984 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
985 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
986 Val =
987 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
988 .getReg(0);
989 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
990 Val =
991 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
992 .getReg(0);
993 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
994 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
995 break;
996 }
997 default:
998 llvm_unreachable("unsupported opcode");
999 }
1000
1001 if (!Libcalls) // FIXME: Should be mandatory
1003
1004 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
1005 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
1006 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
1007
1008 // Unsupported libcall on the target.
1009 if (RTLibcallImpl == RTLIB::Unsupported) {
1010 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
1011 << MIRBuilder.getTII().getName(Opc) << "\n");
1013 }
1014
1016 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1017
1018 StringRef LibcallName =
1020 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1021 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1022
1023 llvm::append_range(Info.OrigArgs, Args);
1024 if (!CLI.lowerCall(MIRBuilder, Info))
1026
1028}
1029
1030static RTLIB::Libcall
1032 RTLIB::Libcall RTLibcall;
1033 switch (MI.getOpcode()) {
1034 case TargetOpcode::G_GET_FPENV:
1035 RTLibcall = RTLIB::FEGETENV;
1036 break;
1037 case TargetOpcode::G_SET_FPENV:
1038 case TargetOpcode::G_RESET_FPENV:
1039 RTLibcall = RTLIB::FESETENV;
1040 break;
1041 case TargetOpcode::G_GET_FPMODE:
1042 RTLibcall = RTLIB::FEGETMODE;
1043 break;
1044 case TargetOpcode::G_SET_FPMODE:
1045 case TargetOpcode::G_RESET_FPMODE:
1046 RTLibcall = RTLIB::FESETMODE;
1047 break;
1048 default:
1049 llvm_unreachable("Unexpected opcode");
1050 }
1051 return RTLibcall;
1052}
1053
1054// Some library functions that read FP state (fegetmode, fegetenv) write the
1055// state into a region in memory. IR intrinsics that do the same operations
1056// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1057// intrinsics via the library functions, we need to use temporary variable,
1058// for example:
1059//
1060// %0:_(s32) = G_GET_FPMODE
1061//
1062// is transformed to:
1063//
1064// %1:_(p0) = G_FRAME_INDEX %stack.0
1065// BL &fegetmode
1066// %0:_(s32) = G_LOAD % 1
1067//
1069LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1070 LostDebugLocObserver &LocObserver) {
1071 const DataLayout &DL = MIRBuilder.getDataLayout();
1072 auto &MF = MIRBuilder.getMF();
1073 auto &MRI = *MIRBuilder.getMRI();
1074 auto &Ctx = MF.getFunction().getContext();
1075
1076 // Create temporary, where library function will put the read state.
1077 Register Dst = MI.getOperand(0).getReg();
1078 LLT StateTy = MRI.getType(Dst);
1079 TypeSize StateSize = StateTy.getSizeInBytes();
1080 Align TempAlign = getStackTemporaryAlignment(StateTy);
1081 MachinePointerInfo TempPtrInfo;
1082 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1083
1084 // Create a call to library function, with the temporary as an argument.
1085 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1086 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1087 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1088 auto Res = createLibcall(
1089 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1090 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1091 nullptr);
1092 if (Res != LegalizerHelper::Legalized)
1093 return Res;
1094
1095 // Create a load from the temporary.
1096 MachineMemOperand *MMO = MF.getMachineMemOperand(
1097 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1098 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1099
1101}
1102
1103// Similar to `createGetStateLibcall` the function calls a library function
1104// using transient space in stack. In this case the library function reads
1105// content of memory region.
1107LegalizerHelper::createSetStateLibcall(MachineInstr &MI,
1108 LostDebugLocObserver &LocObserver) {
1109 const DataLayout &DL = MIRBuilder.getDataLayout();
1110 auto &MF = MIRBuilder.getMF();
1111 auto &MRI = *MIRBuilder.getMRI();
1112 auto &Ctx = MF.getFunction().getContext();
1113
1114 // Create temporary, where library function will get the new state.
1115 Register Src = MI.getOperand(0).getReg();
1116 LLT StateTy = MRI.getType(Src);
1117 TypeSize StateSize = StateTy.getSizeInBytes();
1118 Align TempAlign = getStackTemporaryAlignment(StateTy);
1119 MachinePointerInfo TempPtrInfo;
1120 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1121
1122 // Put the new state into the temporary.
1123 MachineMemOperand *MMO = MF.getMachineMemOperand(
1124 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1125 MIRBuilder.buildStore(Src, Temp, *MMO);
1126
1127 // Create a call to library function, with the temporary as an argument.
1128 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1129 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1130 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1131 return createLibcall(RTLibcall,
1132 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1133 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1134 LocObserver, nullptr);
1135}
1136
1137/// Returns the corresponding libcall for the given Pred and
1138/// the ICMP predicate that should be generated to compare with #0
1139/// after the libcall.
1140static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1142#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1143 do { \
1144 switch (Size) { \
1145 case 32: \
1146 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1147 case 64: \
1148 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1149 case 128: \
1150 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1151 default: \
1152 llvm_unreachable("unexpected size"); \
1153 } \
1154 } while (0)
1155
1156 // These use the three-way (-1/0/1) compare libcalls, whose result is tested
1157 // against 0 with a signed integer predicate. Unordered (UO) is a boolean.
1158 switch (Pred) {
1159 case CmpInst::FCMP_OEQ:
1160 RTLIBCASE_CMP(FCMP3_PRED_OEQ_F, CmpInst::ICMP_EQ);
1161 case CmpInst::FCMP_UNE:
1162 RTLIBCASE_CMP(FCMP3_PRED_UNE_F, CmpInst::ICMP_NE);
1163 case CmpInst::FCMP_OGE:
1164 RTLIBCASE_CMP(FCMP3_PRED_OGE_F, CmpInst::ICMP_SGE);
1165 case CmpInst::FCMP_OLT:
1166 RTLIBCASE_CMP(FCMP3_PRED_OLT_F, CmpInst::ICMP_SLT);
1167 case CmpInst::FCMP_OLE:
1168 RTLIBCASE_CMP(FCMP3_PRED_OLE_F, CmpInst::ICMP_SLE);
1169 case CmpInst::FCMP_OGT:
1170 RTLIBCASE_CMP(FCMP3_PRED_OGT_F, CmpInst::ICMP_SGT);
1171 case CmpInst::FCMP_UNO:
1173 default:
1174 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1175 }
1176}
1177
1179LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1180 LostDebugLocObserver &LocObserver) {
1181 auto &MF = MIRBuilder.getMF();
1182 auto &Ctx = MF.getFunction().getContext();
1183 const GFCmp *Cmp = cast<GFCmp>(&MI);
1184
1185 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1186 unsigned Size = OpLLT.getSizeInBits();
1187 if ((Size != 32 && Size != 64 && Size != 128) ||
1188 OpLLT != MRI.getType(Cmp->getRHSReg()))
1189 return UnableToLegalize;
1190
1191 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1192
1193 // DstReg type is s32
1194 const Register DstReg = Cmp->getReg(0);
1195 LLT DstTy = MRI.getType(DstReg);
1196 const auto Cond = Cmp->getCond();
1197 Type *RetTy = TLI.getCmpLibcallReturnType(Ctx);
1198
1199 // Reference:
1200 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1201 // Generates a libcall followed by ICMP.
1202 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1203 const CmpInst::Predicate ICmpPred,
1204 const DstOp &Res) -> Register {
1205 // FCMP libcall returns an integer, and needs an ICMP with #0.
1206 LLT TempLLT = LLT::integer(RetTy->getIntegerBitWidth());
1207 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1208 // Generate libcall, holding result in Temp
1209 const auto Status = createLibcall(
1210 Libcall, {Temp, RetTy, 0},
1211 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1212 LocObserver, &MI);
1213 if (Status != Legalized)
1214 return {};
1215
1216 // Compare temp with #0 to get the final result.
1217 return MIRBuilder
1218 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1219 .getReg(0);
1220 };
1221
1222 // Simple case if we have a direct mapping from predicate to libcall
1223 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1224 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1225 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1226 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1227 return Legalized;
1228 }
1229 return UnableToLegalize;
1230 }
1231
1232 // No direct mapping found, should be generated as combination of libcalls.
1233
1234 switch (Cond) {
1235 case CmpInst::FCMP_UEQ: {
1236 // FCMP_UEQ: unordered or equal
1237 // Convert into (FCMP_OEQ || FCMP_UNO).
1238
1239 const auto [OeqLibcall, OeqPred] =
1241 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1242
1243 const auto [UnoLibcall, UnoPred] =
1245 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1246 if (Oeq && Uno)
1247 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1248 else
1249 return UnableToLegalize;
1250
1251 break;
1252 }
1253 case CmpInst::FCMP_ONE: {
1254 // FCMP_ONE: ordered and operands are unequal
1255 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1256
1257 // We inverse the predicate instead of generating a NOT
1258 // to save one instruction.
1259 // On AArch64 isel can even select two cmp into a single ccmp.
1260 const auto [OeqLibcall, OeqPred] =
1262 const auto NotOeq =
1263 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1264
1265 const auto [UnoLibcall, UnoPred] =
1267 const auto NotUno =
1268 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1269
1270 if (NotOeq && NotUno)
1271 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1272 else
1273 return UnableToLegalize;
1274
1275 break;
1276 }
1277 case CmpInst::FCMP_ULT:
1278 case CmpInst::FCMP_UGE:
1279 case CmpInst::FCMP_UGT:
1280 case CmpInst::FCMP_ULE:
1281 case CmpInst::FCMP_ORD: {
1282 // Convert into: !(inverse(Pred))
1283 // E.g. FCMP_ULT becomes !FCMP_OGE
1284 // This is equivalent to the following, but saves some instructions.
1285 // MIRBuilder.buildNot(
1286 // PredTy,
1287 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1288 // Op1, Op2));
1289 const auto [InversedLibcall, InversedPred] =
1291 if (!BuildLibcall(InversedLibcall,
1292 CmpInst::getInversePredicate(InversedPred), DstReg))
1293 return UnableToLegalize;
1294 break;
1295 }
1296 default:
1297 return UnableToLegalize;
1298 }
1299
1300 return Legalized;
1301}
1302
1303// The function is used to legalize operations that set default environment
1304// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1305// On most targets supported in glibc FE_DFL_MODE is defined as
1306// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1307// it is not true, the target must provide custom lowering.
1309LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1310 LostDebugLocObserver &LocObserver) {
1311 const DataLayout &DL = MIRBuilder.getDataLayout();
1312 auto &MF = MIRBuilder.getMF();
1313 auto &Ctx = MF.getFunction().getContext();
1314
1315 // Create an argument for the library function.
1316 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1317 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1318 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1319 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1320 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1321 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1322 MIRBuilder.buildIntToPtr(Dest, DefValue);
1323
1324 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1325 return createLibcall(
1326 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1327 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1328}
1329
1332 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1333
1334 switch (MI.getOpcode()) {
1335 default:
1336 return UnableToLegalize;
1337 case TargetOpcode::G_MUL:
1338 case TargetOpcode::G_SDIV:
1339 case TargetOpcode::G_UDIV:
1340 case TargetOpcode::G_SREM:
1341 case TargetOpcode::G_UREM:
1342 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1343 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1344 unsigned Size = LLTy.getSizeInBits();
1345 Type *HLTy = IntegerType::get(Ctx, Size);
1346 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1347 if (Status != Legalized)
1348 return Status;
1349 break;
1350 }
1351 case TargetOpcode::G_FADD:
1352 case TargetOpcode::G_FSUB:
1353 case TargetOpcode::G_FMUL:
1354 case TargetOpcode::G_FDIV:
1355 case TargetOpcode::G_FMA:
1356 case TargetOpcode::G_FPOW:
1357 case TargetOpcode::G_FREM:
1358 case TargetOpcode::G_FCOS:
1359 case TargetOpcode::G_FSIN:
1360 case TargetOpcode::G_FTAN:
1361 case TargetOpcode::G_FACOS:
1362 case TargetOpcode::G_FASIN:
1363 case TargetOpcode::G_FATAN:
1364 case TargetOpcode::G_FATAN2:
1365 case TargetOpcode::G_FCOSH:
1366 case TargetOpcode::G_FSINH:
1367 case TargetOpcode::G_FTANH:
1368 case TargetOpcode::G_FLOG10:
1369 case TargetOpcode::G_FLOG:
1370 case TargetOpcode::G_FLOG2:
1371 case TargetOpcode::G_FEXP:
1372 case TargetOpcode::G_FEXP2:
1373 case TargetOpcode::G_FEXP10:
1374 case TargetOpcode::G_FCEIL:
1375 case TargetOpcode::G_FFLOOR:
1376 case TargetOpcode::G_FMINNUM:
1377 case TargetOpcode::G_FMAXNUM:
1378 case TargetOpcode::G_FMINIMUMNUM:
1379 case TargetOpcode::G_FMAXIMUMNUM:
1380 case TargetOpcode::G_FSQRT:
1381 case TargetOpcode::G_FRINT:
1382 case TargetOpcode::G_FNEARBYINT:
1383 case TargetOpcode::G_INTRINSIC_TRUNC:
1384 case TargetOpcode::G_INTRINSIC_ROUND:
1385 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1386 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1387 unsigned Size = LLTy.getSizeInBits();
1388 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1389 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1390 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1391 return UnableToLegalize;
1392 }
1393 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1394 if (Status != Legalized)
1395 return Status;
1396 break;
1397 }
1398 case TargetOpcode::G_FSINCOS: {
1399 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1400 unsigned Size = LLTy.getSizeInBits();
1401 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1402 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1403 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1404 return UnableToLegalize;
1405 }
1406 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1407 }
1408 case TargetOpcode::G_FMODF: {
1409 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1410 unsigned Size = LLTy.getSizeInBits();
1411 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1412 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1413 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1414 return UnableToLegalize;
1415 }
1416 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1417 }
1418 case TargetOpcode::G_LROUND:
1419 case TargetOpcode::G_LLROUND:
1420 case TargetOpcode::G_INTRINSIC_LRINT:
1421 case TargetOpcode::G_INTRINSIC_LLRINT: {
1422 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1423 unsigned Size = LLTy.getSizeInBits();
1424 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1425 Type *ITy = IntegerType::get(
1426 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1427 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1428 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1429 return UnableToLegalize;
1430 }
1431 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1433 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1434 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1435 if (Status != Legalized)
1436 return Status;
1437 MI.eraseFromParent();
1438 return Legalized;
1439 }
1440 case TargetOpcode::G_FPOWI:
1441 case TargetOpcode::G_FLDEXP: {
1442 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1443 unsigned Size = LLTy.getSizeInBits();
1444 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1445 Type *ITy = IntegerType::get(
1446 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1447 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1448 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1449 return UnableToLegalize;
1450 }
1451 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1453 {MI.getOperand(1).getReg(), HLTy, 0},
1454 {MI.getOperand(2).getReg(), ITy, 1}};
1455 Args[1].Flags[0].setSExt();
1457 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1458 if (Status != Legalized)
1459 return Status;
1460 break;
1461 }
1462 case TargetOpcode::G_FPEXT:
1463 case TargetOpcode::G_FPTRUNC: {
1464 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1465 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1466 if (!FromTy || !ToTy)
1467 return UnableToLegalize;
1468 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1469 if (Status != Legalized)
1470 return Status;
1471 break;
1472 }
1473 case TargetOpcode::G_FCMP: {
1474 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1475 if (Status != Legalized)
1476 return Status;
1477 MI.eraseFromParent();
1478 return Status;
1479 }
1480 case TargetOpcode::G_FPTOSI:
1481 case TargetOpcode::G_FPTOUI: {
1482 // FIXME: Support other types
1483 Type *FromTy =
1484 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1485 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1486 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1487 return UnableToLegalize;
1489 FromTy, LocObserver);
1490 if (Status != Legalized)
1491 return Status;
1492 break;
1493 }
1494 case TargetOpcode::G_SITOFP:
1495 case TargetOpcode::G_UITOFP: {
1496 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1497 Type *ToTy =
1498 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1499 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1500 return UnableToLegalize;
1501 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1503 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1504 if (Status != Legalized)
1505 return Status;
1506 break;
1507 }
1508 case TargetOpcode::G_ATOMICRMW_XCHG:
1509 case TargetOpcode::G_ATOMICRMW_ADD:
1510 case TargetOpcode::G_ATOMICRMW_SUB:
1511 case TargetOpcode::G_ATOMICRMW_AND:
1512 case TargetOpcode::G_ATOMICRMW_OR:
1513 case TargetOpcode::G_ATOMICRMW_XOR:
1514 case TargetOpcode::G_ATOMIC_CMPXCHG:
1515 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1517 if (Status != Legalized)
1518 return Status;
1519 break;
1520 }
1521 case TargetOpcode::G_BZERO:
1522 case TargetOpcode::G_MEMCPY:
1523 case TargetOpcode::G_MEMMOVE:
1524 case TargetOpcode::G_MEMSET: {
1525 LegalizeResult Result =
1526 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1527 if (Result != Legalized)
1528 return Result;
1529 MI.eraseFromParent();
1530 return Result;
1531 }
1532 case TargetOpcode::G_GET_FPENV:
1533 case TargetOpcode::G_GET_FPMODE: {
1534 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1535 if (Result != Legalized)
1536 return Result;
1537 break;
1538 }
1539 case TargetOpcode::G_SET_FPENV:
1540 case TargetOpcode::G_SET_FPMODE: {
1541 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1542 if (Result != Legalized)
1543 return Result;
1544 break;
1545 }
1546 case TargetOpcode::G_RESET_FPENV:
1547 case TargetOpcode::G_RESET_FPMODE: {
1548 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1549 if (Result != Legalized)
1550 return Result;
1551 break;
1552 }
1553 }
1554
1555 MI.eraseFromParent();
1556 return Legalized;
1557}
1558
1560 unsigned TypeIdx,
1561 LLT NarrowTy) {
1562 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1563 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1564
1565 switch (MI.getOpcode()) {
1566 default:
1567 return UnableToLegalize;
1568 case TargetOpcode::G_IMPLICIT_DEF: {
1569 Register DstReg = MI.getOperand(0).getReg();
1570 LLT DstTy = MRI.getType(DstReg);
1571
1572 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1573 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1574 // FIXME: Although this would also be legal for the general case, it causes
1575 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1576 // combines not being hit). This seems to be a problem related to the
1577 // artifact combiner.
1578 if (SizeOp0 % NarrowSize != 0) {
1579 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1580 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1581 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1582
1583 MI.eraseFromParent();
1584 return Legalized;
1585 }
1586
1587 int NumParts = SizeOp0 / NarrowSize;
1588
1590 for (int i = 0; i < NumParts; ++i)
1591 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1592
1593 if (DstTy.isVector())
1594 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1595 else
1596 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1597 MI.eraseFromParent();
1598 return Legalized;
1599 }
1600 case TargetOpcode::G_CONSTANT: {
1601 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1602 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1603 unsigned TotalSize = Ty.getSizeInBits();
1604 unsigned NarrowSize = NarrowTy.getSizeInBits();
1605 int NumParts = TotalSize / NarrowSize;
1606
1607 SmallVector<Register, 4> PartRegs;
1608 for (int I = 0; I != NumParts; ++I) {
1609 unsigned Offset = I * NarrowSize;
1610 auto K = MIRBuilder.buildConstant(NarrowTy,
1611 Val.lshr(Offset).trunc(NarrowSize));
1612 PartRegs.push_back(K.getReg(0));
1613 }
1614
1615 LLT LeftoverTy;
1616 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1617 SmallVector<Register, 1> LeftoverRegs;
1618 if (LeftoverBits != 0) {
1619 LeftoverTy = LLT::scalar(LeftoverBits);
1620 auto K = MIRBuilder.buildConstant(
1621 LeftoverTy,
1622 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1623 LeftoverRegs.push_back(K.getReg(0));
1624 }
1625
1626 insertParts(MI.getOperand(0).getReg(),
1627 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1628
1629 MI.eraseFromParent();
1630 return Legalized;
1631 }
1632 case TargetOpcode::G_SEXT:
1633 case TargetOpcode::G_ZEXT:
1634 case TargetOpcode::G_ANYEXT:
1635 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1636 case TargetOpcode::G_TRUNC: {
1637 if (TypeIdx != 1)
1638 return UnableToLegalize;
1639
1640 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1641 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1642 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1643 return UnableToLegalize;
1644 }
1645
1646 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1647 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1648 MI.eraseFromParent();
1649 return Legalized;
1650 }
1651 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1652 case TargetOpcode::G_FREEZE: {
1653 if (TypeIdx != 0)
1654 return UnableToLegalize;
1655
1656 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1657 // Should widen scalar first
1658 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1659 return UnableToLegalize;
1660
1661 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1663 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1664 Parts.push_back(
1665 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1666 .getReg(0));
1667 }
1668
1669 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1670 MI.eraseFromParent();
1671 return Legalized;
1672 }
1673 case TargetOpcode::G_ADD:
1674 case TargetOpcode::G_SUB:
1675 case TargetOpcode::G_SADDO:
1676 case TargetOpcode::G_SSUBO:
1677 case TargetOpcode::G_SADDE:
1678 case TargetOpcode::G_SSUBE:
1679 case TargetOpcode::G_UADDO:
1680 case TargetOpcode::G_USUBO:
1681 case TargetOpcode::G_UADDE:
1682 case TargetOpcode::G_USUBE:
1683 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1684 case TargetOpcode::G_MUL:
1685 case TargetOpcode::G_UMULH:
1686 case TargetOpcode::G_SMULH:
1687 return narrowScalarMul(MI, NarrowTy);
1688 case TargetOpcode::G_EXTRACT:
1689 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1690 case TargetOpcode::G_INSERT:
1691 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1692 case TargetOpcode::G_LOAD: {
1693 auto &LoadMI = cast<GLoad>(MI);
1694 Register DstReg = LoadMI.getDstReg();
1695 LLT DstTy = MRI.getType(DstReg);
1696 if (DstTy.isVector())
1697 return UnableToLegalize;
1698
1699 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1700 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1701 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1702 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1703 LoadMI.eraseFromParent();
1704 return Legalized;
1705 }
1706
1707 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1708 }
1709 case TargetOpcode::G_ZEXTLOAD:
1710 case TargetOpcode::G_SEXTLOAD:
1711 case TargetOpcode::G_FPEXTLOAD: {
1712 auto &LoadMI = cast<GExtLoad>(MI);
1713 Register DstReg = LoadMI.getDstReg();
1714 Register PtrReg = LoadMI.getPointerReg();
1715
1716 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1717 auto &MMO = LoadMI.getMMO();
1718 unsigned MemSize = MMO.getSizeInBits().getValue();
1719
1720 if (MemSize == NarrowSize) {
1721 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1722 } else if (MemSize < NarrowSize) {
1723 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1724 } else if (MemSize > NarrowSize) {
1725 // FIXME: Need to split the load.
1726 return UnableToLegalize;
1727 }
1728
1729 if (isa<GZExtLoad>(LoadMI))
1730 MIRBuilder.buildZExt(DstReg, TmpReg);
1731 else if (isa<GSExtLoad>(LoadMI))
1732 MIRBuilder.buildSExt(DstReg, TmpReg);
1733 else
1734 MIRBuilder.buildFPExt(DstReg, TmpReg);
1735
1736 LoadMI.eraseFromParent();
1737 return Legalized;
1738 }
1739 case TargetOpcode::G_STORE: {
1740 auto &StoreMI = cast<GStore>(MI);
1741
1742 Register SrcReg = StoreMI.getValueReg();
1743 LLT SrcTy = MRI.getType(SrcReg);
1744 if (SrcTy.isVector())
1745 return UnableToLegalize;
1746
1747 int NumParts = SizeOp0 / NarrowSize;
1748 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1749 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1750 if (SrcTy.isVector() && LeftoverBits != 0)
1751 return UnableToLegalize;
1752
1753 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1754 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1755 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1756 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1757 StoreMI.eraseFromParent();
1758 return Legalized;
1759 }
1760
1761 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1762 }
1763 case TargetOpcode::G_FPTRUNCSTORE: {
1764 auto &StoreMI = cast<GFPTruncStore>(MI);
1765 Register SrcReg = StoreMI.getValueReg();
1766 Register PtrReg = StoreMI.getPointerReg();
1767
1768 auto &MMO = StoreMI.getMMO();
1769 unsigned MemSize = MMO.getSizeInBits().getValue();
1770 if (MemSize > NarrowSize) {
1771 return UnableToLegalize;
1772 }
1773
1774 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1775 if (MemSize == NarrowSize) {
1776 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1777 } else if (MemSize < NarrowSize) {
1778 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1779 MMO);
1780 }
1781
1782 StoreMI.eraseFromParent();
1783 return Legalized;
1784 }
1785 case TargetOpcode::G_SELECT:
1786 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1787 case TargetOpcode::G_AND:
1788 case TargetOpcode::G_OR:
1789 case TargetOpcode::G_XOR: {
1790 // Legalize bitwise operation:
1791 // A = BinOp<Ty> B, C
1792 // into:
1793 // B1, ..., BN = G_UNMERGE_VALUES B
1794 // C1, ..., CN = G_UNMERGE_VALUES C
1795 // A1 = BinOp<Ty/N> B1, C2
1796 // ...
1797 // AN = BinOp<Ty/N> BN, CN
1798 // A = G_MERGE_VALUES A1, ..., AN
1799 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1800 }
1801 case TargetOpcode::G_SHL:
1802 case TargetOpcode::G_LSHR:
1803 case TargetOpcode::G_ASHR:
1804 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1805 case TargetOpcode::G_CTLZ:
1806 case TargetOpcode::G_CTLZ_ZERO_POISON:
1807 case TargetOpcode::G_CTTZ:
1808 case TargetOpcode::G_CTTZ_ZERO_POISON:
1809 case TargetOpcode::G_CTLS:
1810 case TargetOpcode::G_CTPOP:
1811 if (TypeIdx == 1)
1812 switch (MI.getOpcode()) {
1813 case TargetOpcode::G_CTLZ:
1814 case TargetOpcode::G_CTLZ_ZERO_POISON:
1815 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1816 case TargetOpcode::G_CTTZ:
1817 case TargetOpcode::G_CTTZ_ZERO_POISON:
1818 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1819 case TargetOpcode::G_CTPOP:
1820 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1821 case TargetOpcode::G_CTLS:
1822 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1823 default:
1824 return UnableToLegalize;
1825 }
1826
1827 Observer.changingInstr(MI);
1828 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1829 Observer.changedInstr(MI);
1830 return Legalized;
1831 case TargetOpcode::G_INTTOPTR:
1832 if (TypeIdx != 1)
1833 return UnableToLegalize;
1834
1835 Observer.changingInstr(MI);
1836 narrowScalarSrc(MI, NarrowTy, 1);
1837 Observer.changedInstr(MI);
1838 return Legalized;
1839 case TargetOpcode::G_PTRTOINT:
1840 if (TypeIdx != 0)
1841 return UnableToLegalize;
1842
1843 Observer.changingInstr(MI);
1844 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1845 Observer.changedInstr(MI);
1846 return Legalized;
1847 case TargetOpcode::G_PHI: {
1848 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1849 // NarrowSize.
1850 if (SizeOp0 % NarrowSize != 0)
1851 return UnableToLegalize;
1852
1853 unsigned NumParts = SizeOp0 / NarrowSize;
1855 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1856 Observer.changingInstr(MI);
1857 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1858 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1859 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1860 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1861 SrcRegs[i / 2], MIRBuilder, MRI);
1862 }
1863 MachineBasicBlock &MBB = *MI.getParent();
1864 MIRBuilder.setInsertPt(MBB, MI);
1865 for (unsigned i = 0; i < NumParts; ++i) {
1866 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1868 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1869 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1870 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1871 }
1872 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1873 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1874 Observer.changedInstr(MI);
1875 MI.eraseFromParent();
1876 return Legalized;
1877 }
1878 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1879 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1880 if (TypeIdx != 2)
1881 return UnableToLegalize;
1882
1883 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1884 Observer.changingInstr(MI);
1885 narrowScalarSrc(MI, NarrowTy, OpIdx);
1886 Observer.changedInstr(MI);
1887 return Legalized;
1888 }
1889 case TargetOpcode::G_ICMP: {
1890 Register LHS = MI.getOperand(2).getReg();
1891 LLT SrcTy = MRI.getType(LHS);
1892 CmpInst::Predicate Pred =
1893 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1894
1895 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1896 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1897 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1898 LHSLeftoverRegs, MIRBuilder, MRI))
1899 return UnableToLegalize;
1900
1901 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1902 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1903 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1904 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1905 return UnableToLegalize;
1906
1907 // We now have the LHS and RHS of the compare split into narrow-type
1908 // registers, plus potentially some leftover type.
1909 Register Dst = MI.getOperand(0).getReg();
1910 LLT ResTy = MRI.getType(Dst);
1911 if (ICmpInst::isEquality(Pred)) {
1912 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1913 // them together. For each equal part, the result should be all 0s. For
1914 // each non-equal part, we'll get at least one 1.
1915 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1917 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1918 auto LHS = std::get<0>(LHSAndRHS);
1919 auto RHS = std::get<1>(LHSAndRHS);
1920 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1921 Xors.push_back(Xor);
1922 }
1923
1924 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1925 // to the desired narrow type so that we can OR them together later.
1926 SmallVector<Register, 4> WidenedXors;
1927 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1928 auto LHS = std::get<0>(LHSAndRHS);
1929 auto RHS = std::get<1>(LHSAndRHS);
1930 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1931 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1932 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1933 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1934 llvm::append_range(Xors, WidenedXors);
1935 }
1936
1937 // Now, for each part we broke up, we know if they are equal/not equal
1938 // based off the G_XOR. We can OR these all together and compare against
1939 // 0 to get the result.
1940 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1941 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1942 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1943 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1944 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1945 } else {
1946 Register CmpIn;
1947 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1948 Register CmpOut;
1949 CmpInst::Predicate PartPred;
1950
1951 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1952 PartPred = Pred;
1953 CmpOut = Dst;
1954 } else {
1955 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1956 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1957 }
1958
1959 if (!CmpIn) {
1960 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1961 RHSPartRegs[I]);
1962 } else {
1963 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1964 RHSPartRegs[I]);
1965 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1966 LHSPartRegs[I], RHSPartRegs[I]);
1967 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1968 }
1969
1970 CmpIn = CmpOut;
1971 }
1972
1973 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1974 Register CmpOut;
1975 CmpInst::Predicate PartPred;
1976
1977 if (I == E - 1) {
1978 PartPred = Pred;
1979 CmpOut = Dst;
1980 } else {
1981 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1982 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1983 }
1984
1985 if (!CmpIn) {
1986 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1987 RHSLeftoverRegs[I]);
1988 } else {
1989 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1990 RHSLeftoverRegs[I]);
1991 auto CmpEq =
1992 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1993 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1994 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1995 }
1996
1997 CmpIn = CmpOut;
1998 }
1999 }
2000 MI.eraseFromParent();
2001 return Legalized;
2002 }
2003 case TargetOpcode::G_FCMP:
2004 if (TypeIdx != 0)
2005 return UnableToLegalize;
2006
2007 Observer.changingInstr(MI);
2008 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
2009 Observer.changedInstr(MI);
2010 return Legalized;
2011
2012 case TargetOpcode::G_SEXT_INREG: {
2013 if (TypeIdx != 0)
2014 return UnableToLegalize;
2015
2016 int64_t SizeInBits = MI.getOperand(2).getImm();
2017
2018 // So long as the new type has more bits than the bits we're extending we
2019 // don't need to break it apart.
2020 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2021 Observer.changingInstr(MI);
2022 // We don't lose any non-extension bits by truncating the src and
2023 // sign-extending the dst.
2024 MachineOperand &MO1 = MI.getOperand(1);
2025 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2026 MO1.setReg(TruncMIB.getReg(0));
2027
2028 MachineOperand &MO2 = MI.getOperand(0);
2029 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2030 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2031 MIRBuilder.buildSExt(MO2, DstExt);
2032 MO2.setReg(DstExt);
2033 Observer.changedInstr(MI);
2034 return Legalized;
2035 }
2036
2037 // Break it apart. Components below the extension point are unmodified. The
2038 // component containing the extension point becomes a narrower SEXT_INREG.
2039 // Components above it are ashr'd from the component containing the
2040 // extension point.
2041 if (SizeOp0 % NarrowSize != 0)
2042 return UnableToLegalize;
2043 int NumParts = SizeOp0 / NarrowSize;
2044
2045 // List the registers where the destination will be scattered.
2047 // List the registers where the source will be split.
2049
2050 // Create all the temporary registers.
2051 for (int i = 0; i < NumParts; ++i) {
2052 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2053
2054 SrcRegs.push_back(SrcReg);
2055 }
2056
2057 // Explode the big arguments into smaller chunks.
2058 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2059
2060 Register AshrCstReg =
2061 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2062 .getReg(0);
2063 Register FullExtensionReg;
2064 Register PartialExtensionReg;
2065
2066 // Do the operation on each small part.
2067 for (int i = 0; i < NumParts; ++i) {
2068 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2069 DstRegs.push_back(SrcRegs[i]);
2070 PartialExtensionReg = DstRegs.back();
2071 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2072 assert(PartialExtensionReg &&
2073 "Expected to visit partial extension before full");
2074 if (FullExtensionReg) {
2075 DstRegs.push_back(FullExtensionReg);
2076 continue;
2077 }
2078 DstRegs.push_back(
2079 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2080 .getReg(0));
2081 FullExtensionReg = DstRegs.back();
2082 } else {
2083 DstRegs.push_back(
2085 .buildInstr(
2086 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2087 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2088 .getReg(0));
2089 PartialExtensionReg = DstRegs.back();
2090 }
2091 }
2092
2093 // Gather the destination registers into the final destination.
2094 Register DstReg = MI.getOperand(0).getReg();
2095 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2096 MI.eraseFromParent();
2097 return Legalized;
2098 }
2099 case TargetOpcode::G_BSWAP:
2100 case TargetOpcode::G_BITREVERSE: {
2101 if (SizeOp0 % NarrowSize != 0)
2102 return UnableToLegalize;
2103
2104 Observer.changingInstr(MI);
2105 SmallVector<Register, 2> SrcRegs, DstRegs;
2106 unsigned NumParts = SizeOp0 / NarrowSize;
2107 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2108 MIRBuilder, MRI);
2109
2110 for (unsigned i = 0; i < NumParts; ++i) {
2111 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2112 {SrcRegs[NumParts - 1 - i]});
2113 DstRegs.push_back(DstPart.getReg(0));
2114 }
2115
2116 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2117
2118 Observer.changedInstr(MI);
2119 MI.eraseFromParent();
2120 return Legalized;
2121 }
2122 case TargetOpcode::G_PTR_ADD:
2123 case TargetOpcode::G_PTRMASK: {
2124 if (TypeIdx != 1)
2125 return UnableToLegalize;
2126 Observer.changingInstr(MI);
2127 narrowScalarSrc(MI, NarrowTy, 2);
2128 Observer.changedInstr(MI);
2129 return Legalized;
2130 }
2131 case TargetOpcode::G_FPTOUI:
2132 case TargetOpcode::G_FPTOSI:
2133 case TargetOpcode::G_FPTOUI_SAT:
2134 case TargetOpcode::G_FPTOSI_SAT:
2135 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2136 case TargetOpcode::G_FPEXT:
2137 if (TypeIdx != 0)
2138 return UnableToLegalize;
2139 Observer.changingInstr(MI);
2140 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2141 Observer.changedInstr(MI);
2142 return Legalized;
2143 case TargetOpcode::G_FLDEXP:
2144 case TargetOpcode::G_STRICT_FLDEXP:
2145 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2146 case TargetOpcode::G_VSCALE: {
2147 Register Dst = MI.getOperand(0).getReg();
2148 LLT Ty = MRI.getType(Dst);
2149
2150 // Assume VSCALE(1) fits into a legal integer
2151 const APInt One(NarrowTy.getSizeInBits(), 1);
2152 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2153 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2154 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2155 MIRBuilder.buildMul(Dst, ZExt, C);
2156
2157 MI.eraseFromParent();
2158 return Legalized;
2159 }
2160 }
2161}
2162
2164 LLT Ty = MRI.getType(Val);
2165 if (Ty.isScalar() && !Ty.isFloat())
2166 return Val;
2167
2168 const DataLayout &DL = MIRBuilder.getDataLayout();
2169 LLT NewTy = LLT::integer(Ty.getSizeInBits());
2170
2171 if (Ty.isFloat())
2172 return MIRBuilder.buildBitcast(NewTy, Val).getReg(0);
2173
2174 if (Ty.isPointer()) {
2175 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2176 return Register();
2177 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2178 }
2179
2180 Register NewVal = Val;
2181
2182 assert(Ty.isVector());
2183 if (Ty.isPointerVector())
2184 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2185 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2186}
2187
2189 unsigned OpIdx, unsigned ExtOpcode) {
2190 MachineOperand &MO = MI.getOperand(OpIdx);
2191 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2192 MO.setReg(ExtB.getReg(0));
2193}
2194
2196 unsigned OpIdx) {
2197 MachineOperand &MO = MI.getOperand(OpIdx);
2198 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2199 MI.getFlags());
2200 MO.setReg(ExtB.getReg(0));
2201}
2202
2204 unsigned OpIdx) {
2205 MachineOperand &MO = MI.getOperand(OpIdx);
2206 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2207 MO.setReg(ExtB.getReg(0));
2208}
2209
2211 unsigned OpIdx, unsigned TruncOpcode) {
2212 MachineOperand &MO = MI.getOperand(OpIdx);
2213 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2214 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2215 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2216 MO.setReg(DstExt);
2217}
2218
2220 unsigned OpIdx) {
2221 MachineOperand &MO = MI.getOperand(OpIdx);
2222 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2223 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2224 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2225 MO.setReg(DstExt);
2226}
2227
2229 unsigned OpIdx, unsigned ExtOpcode) {
2230 MachineOperand &MO = MI.getOperand(OpIdx);
2231 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2232 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2233 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2234 MO.setReg(DstTrunc);
2235}
2236
2238 unsigned OpIdx) {
2239 MachineOperand &MO = MI.getOperand(OpIdx);
2240 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2241 Register Dst = MO.getReg();
2242 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2243 MO.setReg(DstExt);
2244 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2245}
2246
2248 unsigned OpIdx) {
2249 MachineOperand &MO = MI.getOperand(OpIdx);
2250 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2251}
2252
2253void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2254 MachineOperand &Op = MI.getOperand(OpIdx);
2255 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2256}
2257
2258void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2259 MachineOperand &MO = MI.getOperand(OpIdx);
2260 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2261 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2262 MIRBuilder.buildBitcast(MO, CastDst);
2263 MO.setReg(CastDst);
2264}
2265
2267LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2268 LLT WideTy) {
2269 if (TypeIdx != 1)
2270 return UnableToLegalize;
2271
2272 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2273 if (DstTy.isVector())
2274 return UnableToLegalize;
2275
2276 LLT SrcTy = MRI.getType(Src1Reg);
2277 const int DstSize = DstTy.getSizeInBits();
2278 const int SrcSize = SrcTy.getSizeInBits();
2279 const int WideSize = WideTy.getSizeInBits();
2280 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2281
2282 unsigned NumOps = MI.getNumOperands();
2283 unsigned NumSrc = MI.getNumOperands() - 1;
2284 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2285
2286 if (WideSize >= DstSize) {
2287 // Directly pack the bits in the target type.
2288 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2289
2290 for (unsigned I = 2; I != NumOps; ++I) {
2291 const unsigned Offset = (I - 1) * PartSize;
2292
2293 Register SrcReg = MI.getOperand(I).getReg();
2294 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2295
2296 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2297
2298 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2299 MRI.createGenericVirtualRegister(WideTy);
2300
2301 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2302 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2303 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2304 ResultReg = NextResult;
2305 }
2306
2307 if (WideSize > DstSize)
2308 MIRBuilder.buildTrunc(DstReg, ResultReg);
2309 else if (DstTy.isPointer())
2310 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2311 else if (DstTy != WideTy)
2312 MIRBuilder.buildBitcast(DstReg, ResultReg);
2313
2314 MI.eraseFromParent();
2315 return Legalized;
2316 }
2317
2318 // Unmerge the original values to the GCD type, and recombine to the next
2319 // multiple greater than the original type.
2320 //
2321 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2322 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2323 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2324 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2325 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2326 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2327 // %12:_(s12) = G_MERGE_VALUES %10, %11
2328 //
2329 // Padding with undef if necessary:
2330 //
2331 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2332 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2333 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2334 // %7:_(s2) = G_IMPLICIT_DEF
2335 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2336 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2337 // %10:_(s12) = G_MERGE_VALUES %8, %9
2338
2339 const int GCD = std::gcd(SrcSize, WideSize);
2340 LLT GCDTy = WideTy.changeElementSize(GCD);
2341
2342 SmallVector<Register, 8> NewMergeRegs;
2343 SmallVector<Register, 8> Unmerges;
2344 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2345
2346 // Decompose the original operands if they don't evenly divide.
2347 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2348 Register SrcReg = MO.getReg();
2349 if (GCD == SrcSize) {
2350 Unmerges.push_back(SrcReg);
2351 } else {
2352 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2353 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2354 Unmerges.push_back(Unmerge.getReg(J));
2355 }
2356 }
2357
2358 // Pad with undef to the next size that is a multiple of the requested size.
2359 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2360 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2361 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2362 Unmerges.push_back(UndefReg);
2363 }
2364
2365 const int PartsPerGCD = WideSize / GCD;
2366
2367 // Build merges of each piece.
2368 ArrayRef<Register> Slicer(Unmerges);
2369 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2370 auto Merge =
2371 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2372 NewMergeRegs.push_back(Merge.getReg(0));
2373 }
2374
2375 // A truncate may be necessary if the requested type doesn't evenly divide the
2376 // original result type.
2377 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2378 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2379 } else {
2380 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2381 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2382 }
2383
2384 MI.eraseFromParent();
2385 return Legalized;
2386}
2387
2389LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2390 LLT WideTy) {
2391 if (TypeIdx != 0)
2392 return UnableToLegalize;
2393
2394 int NumDst = MI.getNumOperands() - 1;
2395 Register SrcReg = MI.getOperand(NumDst).getReg();
2396 LLT SrcTy = MRI.getType(SrcReg);
2397 if (SrcTy.isVector())
2398 return UnableToLegalize;
2399
2400 Register Dst0Reg = MI.getOperand(0).getReg();
2401 LLT DstTy = MRI.getType(Dst0Reg);
2402 if (!DstTy.isScalar())
2403 return UnableToLegalize;
2404
2405 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2406 if (SrcTy.isPointer()) {
2407 const DataLayout &DL = MIRBuilder.getDataLayout();
2408 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2409 LLVM_DEBUG(
2410 dbgs() << "Not casting non-integral address space integer\n");
2411 return UnableToLegalize;
2412 }
2413
2414 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2415 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2416 }
2417
2418 // Widen SrcTy to WideTy. This does not affect the result, but since the
2419 // user requested this size, it is probably better handled than SrcTy and
2420 // should reduce the total number of legalization artifacts.
2421 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2422 SrcTy = WideTy;
2423 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2424 }
2425
2426 // Theres no unmerge type to target. Directly extract the bits from the
2427 // source type
2428 unsigned DstSize = DstTy.getSizeInBits();
2429
2430 if (SrcTy.isFloat()) {
2431 SrcReg = coerceToInteger(SrcReg);
2432 SrcTy = MRI.getType(SrcReg);
2433 }
2434
2435 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2436 for (int I = 1; I != NumDst; ++I) {
2437 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2438 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2439 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2440 }
2441
2442 MI.eraseFromParent();
2443 return Legalized;
2444 }
2445
2446 // Extend the source to a wider type.
2447 LLT LCMTy = getLCMType(SrcTy, WideTy);
2448
2449 Register WideSrc = SrcReg;
2450 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2451 // TODO: If this is an integral address space, cast to integer and anyext.
2452 if (SrcTy.isPointer()) {
2453 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2454 return UnableToLegalize;
2455 }
2456
2457 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2458 }
2459
2460 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2461
2462 // Create a sequence of unmerges and merges to the original results. Since we
2463 // may have widened the source, we will need to pad the results with dead defs
2464 // to cover the source register.
2465 // e.g. widen s48 to s64:
2466 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2467 //
2468 // =>
2469 // %4:_(s192) = G_ANYEXT %0:_(s96)
2470 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2471 // ; unpack to GCD type, with extra dead defs
2472 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2473 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2474 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2475 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2476 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2477 const LLT GCDTy = getGCDType(WideTy, DstTy);
2478 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2479 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2480
2481 // Directly unmerge to the destination without going through a GCD type
2482 // if possible
2483 if (PartsPerRemerge == 1) {
2484 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2485
2486 for (int I = 0; I != NumUnmerge; ++I) {
2487 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2488
2489 for (int J = 0; J != PartsPerUnmerge; ++J) {
2490 int Idx = I * PartsPerUnmerge + J;
2491 if (Idx < NumDst)
2492 MIB.addDef(MI.getOperand(Idx).getReg());
2493 else {
2494 // Create dead def for excess components.
2495 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2496 }
2497 }
2498
2499 MIB.addUse(Unmerge.getReg(I));
2500 }
2501 } else {
2502 SmallVector<Register, 16> Parts;
2503 for (int J = 0; J != NumUnmerge; ++J)
2504 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2505
2506 SmallVector<Register, 8> RemergeParts;
2507 for (int I = 0; I != NumDst; ++I) {
2508 for (int J = 0; J < PartsPerRemerge; ++J) {
2509 const int Idx = I * PartsPerRemerge + J;
2510 RemergeParts.emplace_back(Parts[Idx]);
2511 }
2512
2513 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2514 RemergeParts.clear();
2515 }
2516 }
2517
2518 MI.eraseFromParent();
2519 return Legalized;
2520}
2521
2523LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2524 LLT WideTy) {
2525 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2526 unsigned Offset = MI.getOperand(2).getImm();
2527
2528 if (TypeIdx == 0) {
2529 if (SrcTy.isVector() || DstTy.isVector())
2530 return UnableToLegalize;
2531
2532 SrcOp Src(SrcReg);
2533 if (SrcTy.isPointer()) {
2534 // Extracts from pointers can be handled only if they are really just
2535 // simple integers.
2536 const DataLayout &DL = MIRBuilder.getDataLayout();
2537 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2538 return UnableToLegalize;
2539
2540 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2541 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2542 SrcTy = SrcAsIntTy;
2543 }
2544
2545 if (DstTy.isPointer())
2546 return UnableToLegalize;
2547
2548 if (Offset == 0) {
2549 // Avoid a shift in the degenerate case.
2550 MIRBuilder.buildTrunc(DstReg,
2551 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2552 MI.eraseFromParent();
2553 return Legalized;
2554 }
2555
2556 // Do a shift in the source type.
2557 LLT ShiftTy = SrcTy;
2558 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2559 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2560 ShiftTy = WideTy;
2561 }
2562
2563 auto LShr = MIRBuilder.buildLShr(
2564 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2565 MIRBuilder.buildTrunc(DstReg, LShr);
2566 MI.eraseFromParent();
2567 return Legalized;
2568 }
2569
2570 if (SrcTy.isScalar()) {
2571 Observer.changingInstr(MI);
2572 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2573 Observer.changedInstr(MI);
2574 return Legalized;
2575 }
2576
2577 if (!SrcTy.isVector())
2578 return UnableToLegalize;
2579
2580 if (DstTy != SrcTy.getElementType())
2581 return UnableToLegalize;
2582
2583 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2584 return UnableToLegalize;
2585
2586 Observer.changingInstr(MI);
2587 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2588
2589 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2590 Offset);
2591 widenScalarDst(MI, WideTy.getScalarType(), 0);
2592 Observer.changedInstr(MI);
2593 return Legalized;
2594}
2595
2597LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2598 LLT WideTy) {
2599 if (TypeIdx != 0 || WideTy.isVector())
2600 return UnableToLegalize;
2601 Observer.changingInstr(MI);
2602 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2603 widenScalarDst(MI, WideTy);
2604 Observer.changedInstr(MI);
2605 return Legalized;
2606}
2607
2609LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2610 LLT WideTy) {
2611 unsigned Opcode;
2612 unsigned ExtOpcode;
2613 std::optional<Register> CarryIn;
2614 switch (MI.getOpcode()) {
2615 default:
2616 llvm_unreachable("Unexpected opcode!");
2617 case TargetOpcode::G_SADDO:
2618 Opcode = TargetOpcode::G_ADD;
2619 ExtOpcode = TargetOpcode::G_SEXT;
2620 break;
2621 case TargetOpcode::G_SSUBO:
2622 Opcode = TargetOpcode::G_SUB;
2623 ExtOpcode = TargetOpcode::G_SEXT;
2624 break;
2625 case TargetOpcode::G_UADDO:
2626 Opcode = TargetOpcode::G_ADD;
2627 ExtOpcode = TargetOpcode::G_ZEXT;
2628 break;
2629 case TargetOpcode::G_USUBO:
2630 Opcode = TargetOpcode::G_SUB;
2631 ExtOpcode = TargetOpcode::G_ZEXT;
2632 break;
2633 case TargetOpcode::G_SADDE:
2634 Opcode = TargetOpcode::G_UADDE;
2635 ExtOpcode = TargetOpcode::G_SEXT;
2636 CarryIn = MI.getOperand(4).getReg();
2637 break;
2638 case TargetOpcode::G_SSUBE:
2639 Opcode = TargetOpcode::G_USUBE;
2640 ExtOpcode = TargetOpcode::G_SEXT;
2641 CarryIn = MI.getOperand(4).getReg();
2642 break;
2643 case TargetOpcode::G_UADDE:
2644 Opcode = TargetOpcode::G_UADDE;
2645 ExtOpcode = TargetOpcode::G_ZEXT;
2646 CarryIn = MI.getOperand(4).getReg();
2647 break;
2648 case TargetOpcode::G_USUBE:
2649 Opcode = TargetOpcode::G_USUBE;
2650 ExtOpcode = TargetOpcode::G_ZEXT;
2651 CarryIn = MI.getOperand(4).getReg();
2652 break;
2653 }
2654
2655 if (TypeIdx == 1) {
2656 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2657
2658 Observer.changingInstr(MI);
2659 if (CarryIn)
2660 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2661 widenScalarDst(MI, WideTy, 1);
2662
2663 Observer.changedInstr(MI);
2664 return Legalized;
2665 }
2666
2667 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2668 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2669 // Do the arithmetic in the larger type.
2670 Register NewOp;
2671 if (CarryIn) {
2672 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2673 NewOp = MIRBuilder
2674 .buildInstr(Opcode, {WideTy, CarryOutTy},
2675 {LHSExt, RHSExt, *CarryIn})
2676 .getReg(0);
2677 } else {
2678 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2679 }
2680 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2681 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2682 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2683 // There is no overflow if the ExtOp is the same as NewOp.
2684 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2685 // Now trunc the NewOp to the original result.
2686 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2687 MI.eraseFromParent();
2688 return Legalized;
2689}
2690
2692LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2693 LLT WideTy) {
2694 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2695 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2696 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2697 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2698 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2699 // We can convert this to:
2700 // 1. Any extend iN to iM
2701 // 2. SHL by M-N
2702 // 3. [US][ADD|SUB|SHL]SAT
2703 // 4. L/ASHR by M-N
2704 //
2705 // It may be more efficient to lower this to a min and a max operation in
2706 // the higher precision arithmetic if the promoted operation isn't legal,
2707 // but this decision is up to the target's lowering request.
2708 Register DstReg = MI.getOperand(0).getReg();
2709
2710 unsigned NewBits = WideTy.getScalarSizeInBits();
2711 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2712
2713 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2714 // must not left shift the RHS to preserve the shift amount.
2715 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2716 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2717 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2718 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2719 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2720 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2721
2722 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2723 {ShiftL, ShiftR}, MI.getFlags());
2724
2725 // Use a shift that will preserve the number of sign bits when the trunc is
2726 // folded away.
2727 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2728 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2729
2730 MIRBuilder.buildTrunc(DstReg, Result);
2731 MI.eraseFromParent();
2732 return Legalized;
2733}
2734
2736LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2737 LLT WideTy) {
2738 if (TypeIdx == 1) {
2739 Observer.changingInstr(MI);
2740 widenScalarDst(MI, WideTy, 1);
2741 Observer.changedInstr(MI);
2742 return Legalized;
2743 }
2744
2745 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2746 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2747 LLT SrcTy = MRI.getType(LHS);
2748 LLT OverflowTy = MRI.getType(OriginalOverflow);
2749 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2750
2751 // To determine if the result overflowed in the larger type, we extend the
2752 // input to the larger type, do the multiply (checking if it overflows),
2753 // then also check the high bits of the result to see if overflow happened
2754 // there.
2755 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2756 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2757 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2758
2759 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2760 // so we don't need to check the overflow result of larger type Mulo.
2761 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2762
2763 unsigned MulOpc =
2764 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2765
2766 MachineInstrBuilder Mulo;
2767 if (WideMulCanOverflow)
2768 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2769 {LeftOperand, RightOperand});
2770 else
2771 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2772
2773 auto Mul = Mulo->getOperand(0);
2774 MIRBuilder.buildTrunc(Result, Mul);
2775
2776 MachineInstrBuilder ExtResult;
2777 // Overflow occurred if it occurred in the larger type, or if the high part
2778 // of the result does not zero/sign-extend the low part. Check this second
2779 // possibility first.
2780 if (IsSigned) {
2781 // For signed, overflow occurred when the high part does not sign-extend
2782 // the low part.
2783 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2784 } else {
2785 // Unsigned overflow occurred when the high part does not zero-extend the
2786 // low part.
2787 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2788 }
2789
2790 if (WideMulCanOverflow) {
2791 auto Overflow =
2792 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2793 // Finally check if the multiplication in the larger type itself overflowed.
2794 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2795 } else {
2796 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2797 }
2798 MI.eraseFromParent();
2799 return Legalized;
2800}
2801
2804 unsigned Opcode = MI.getOpcode();
2805 switch (Opcode) {
2806 default:
2807 return UnableToLegalize;
2808 case TargetOpcode::G_ATOMICRMW_XCHG:
2809 case TargetOpcode::G_ATOMICRMW_ADD:
2810 case TargetOpcode::G_ATOMICRMW_SUB:
2811 case TargetOpcode::G_ATOMICRMW_AND:
2812 case TargetOpcode::G_ATOMICRMW_OR:
2813 case TargetOpcode::G_ATOMICRMW_XOR:
2814 case TargetOpcode::G_ATOMICRMW_MIN:
2815 case TargetOpcode::G_ATOMICRMW_MAX:
2816 case TargetOpcode::G_ATOMICRMW_UMIN:
2817 case TargetOpcode::G_ATOMICRMW_UMAX:
2818 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2819 Observer.changingInstr(MI);
2820 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2821 widenScalarDst(MI, WideTy, 0);
2822 Observer.changedInstr(MI);
2823 return Legalized;
2824 case TargetOpcode::G_ATOMIC_CMPXCHG:
2825 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2826 Observer.changingInstr(MI);
2827 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2828 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2829 widenScalarDst(MI, WideTy, 0);
2830 Observer.changedInstr(MI);
2831 return Legalized;
2832 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2833 if (TypeIdx == 0) {
2834 Observer.changingInstr(MI);
2835 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2836 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2837 widenScalarDst(MI, WideTy, 0);
2838 Observer.changedInstr(MI);
2839 return Legalized;
2840 }
2841 assert(TypeIdx == 1 &&
2842 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2843 Observer.changingInstr(MI);
2844 widenScalarDst(MI, WideTy, 1);
2845 Observer.changedInstr(MI);
2846 return Legalized;
2847 case TargetOpcode::G_EXTRACT:
2848 return widenScalarExtract(MI, TypeIdx, WideTy);
2849 case TargetOpcode::G_INSERT:
2850 return widenScalarInsert(MI, TypeIdx, WideTy);
2851 case TargetOpcode::G_MERGE_VALUES:
2852 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2853 case TargetOpcode::G_UNMERGE_VALUES:
2854 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2855 case TargetOpcode::G_SADDO:
2856 case TargetOpcode::G_SSUBO:
2857 case TargetOpcode::G_UADDO:
2858 case TargetOpcode::G_USUBO:
2859 case TargetOpcode::G_SADDE:
2860 case TargetOpcode::G_SSUBE:
2861 case TargetOpcode::G_UADDE:
2862 case TargetOpcode::G_USUBE:
2863 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2864 case TargetOpcode::G_UMULO:
2865 case TargetOpcode::G_SMULO:
2866 return widenScalarMulo(MI, TypeIdx, WideTy);
2867 case TargetOpcode::G_SADDSAT:
2868 case TargetOpcode::G_SSUBSAT:
2869 case TargetOpcode::G_SSHLSAT:
2870 case TargetOpcode::G_UADDSAT:
2871 case TargetOpcode::G_USUBSAT:
2872 case TargetOpcode::G_USHLSAT:
2873 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2874 case TargetOpcode::G_CTTZ:
2875 case TargetOpcode::G_CTTZ_ZERO_POISON:
2876 case TargetOpcode::G_CTLZ:
2877 case TargetOpcode::G_CTLZ_ZERO_POISON:
2878 case TargetOpcode::G_CTLS:
2879 case TargetOpcode::G_CTPOP: {
2880 if (TypeIdx == 0) {
2881 Observer.changingInstr(MI);
2882 widenScalarDst(MI, WideTy, 0);
2883 Observer.changedInstr(MI);
2884 return Legalized;
2885 }
2886
2887 Register SrcReg = MI.getOperand(1).getReg();
2888
2889 // First extend the input.
2890 unsigned ExtOpc;
2891 switch (Opcode) {
2892 case TargetOpcode::G_CTTZ:
2893 case TargetOpcode::G_CTTZ_ZERO_POISON:
2894 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2895 ExtOpc = TargetOpcode::G_ANYEXT;
2896 break;
2897 case TargetOpcode::G_CTLS:
2898 ExtOpc = TargetOpcode::G_SEXT;
2899 break;
2900 default:
2901 ExtOpc = TargetOpcode::G_ZEXT;
2902 }
2903
2904 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2905 LLT CurTy = MRI.getType(SrcReg);
2906 unsigned NewOpc = Opcode;
2907 if (NewOpc == TargetOpcode::G_CTTZ) {
2908 // The count is the same in the larger type except if the original
2909 // value was zero. This can be handled by setting the bit just off
2910 // the top of the original type.
2911 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2912 CurTy.getScalarSizeInBits());
2913 MIBSrc = MIRBuilder.buildOr(
2914 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2915 // Now we know the operand is non-zero, use the more relaxed opcode.
2916 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2917 }
2918
2919 unsigned SizeDiff =
2920 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2921
2922 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2923 // An optimization where the result is the CTLZ after the left shift by
2924 // (Difference in widety and current ty), that is,
2925 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2926 // Result = ctlz MIBSrc
2927 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2928 MIRBuilder.buildConstant(WideTy, SizeDiff));
2929 }
2930
2931 // Perform the operation at the larger size.
2932 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2933 // This is already the correct result for CTPOP and CTTZs
2934 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2935 // The correct result is NewOp - (Difference in widety and current ty).
2936 // At this stage SUB is guaranteed to be positive no-wrap,
2937 // that to be used in further KnownBits optimizations for CTLZ.
2938 MIBNewOp = MIRBuilder.buildSub(
2939 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2940 Opcode == TargetOpcode::G_CTLZ
2941 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2942 : std::nullopt);
2943 }
2944
2945 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2946 MI.eraseFromParent();
2947 return Legalized;
2948 }
2949 case TargetOpcode::G_BSWAP: {
2950 Observer.changingInstr(MI);
2951 Register DstReg = MI.getOperand(0).getReg();
2952
2953 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2954 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2955 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2956 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2957
2958 MI.getOperand(0).setReg(DstExt);
2959
2960 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2961
2962 LLT Ty = MRI.getType(DstReg);
2963 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2964 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2965 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2966
2967 MIRBuilder.buildTrunc(DstReg, ShrReg);
2968 Observer.changedInstr(MI);
2969 return Legalized;
2970 }
2971 case TargetOpcode::G_BITREVERSE: {
2972 Observer.changingInstr(MI);
2973
2974 Register DstReg = MI.getOperand(0).getReg();
2975 LLT Ty = MRI.getType(DstReg);
2976 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2977
2978 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2979 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2980 MI.getOperand(0).setReg(DstExt);
2981 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2982
2983 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2984 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2985 MIRBuilder.buildTrunc(DstReg, Shift);
2986 Observer.changedInstr(MI);
2987 return Legalized;
2988 }
2989 case TargetOpcode::G_FREEZE:
2990 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2991 Observer.changingInstr(MI);
2992 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2993 widenScalarDst(MI, WideTy);
2994 Observer.changedInstr(MI);
2995 return Legalized;
2996
2997 case TargetOpcode::G_ABS:
2998 Observer.changingInstr(MI);
2999 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3000 widenScalarDst(MI, WideTy);
3001 Observer.changedInstr(MI);
3002 return Legalized;
3003
3004 case TargetOpcode::G_ADD:
3005 case TargetOpcode::G_AND:
3006 case TargetOpcode::G_MUL:
3007 case TargetOpcode::G_OR:
3008 case TargetOpcode::G_XOR:
3009 case TargetOpcode::G_SUB:
3010 case TargetOpcode::G_SHUFFLE_VECTOR:
3011 // Perform operation at larger width (any extension is fines here, high bits
3012 // don't affect the result) and then truncate the result back to the
3013 // original type.
3014 Observer.changingInstr(MI);
3015 // The G_ANYEXTs below leave the new high bits unconstrained, so no-wrap and
3016 // disjoint claims proved at the narrow width no longer hold. Paths that
3017 // widen with value-preserving G_ZEXT/G_SEXT keep their flags.
3020 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3021 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3022 widenScalarDst(MI, WideTy);
3023 Observer.changedInstr(MI);
3024 return Legalized;
3025
3026 case TargetOpcode::G_SBFX:
3027 case TargetOpcode::G_UBFX:
3028 Observer.changingInstr(MI);
3029
3030 if (TypeIdx == 0) {
3031 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3032 widenScalarDst(MI, WideTy);
3033 } else {
3034 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3035 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3036 }
3037
3038 Observer.changedInstr(MI);
3039 return Legalized;
3040
3041 case TargetOpcode::G_SHL:
3042 Observer.changingInstr(MI);
3043
3044 if (TypeIdx == 0) {
3045 // Widening the result with G_ANYEXT invalidates the no-wrap flags, as in
3046 // the G_ADD/G_SUB/G_MUL case above. TypeIdx 1 widens only the shift
3047 // amount, which is value-preserving, so it keeps them.
3049 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3050 widenScalarDst(MI, WideTy);
3051 } else {
3052 assert(TypeIdx == 1);
3053 // The "number of bits to shift" operand must preserve its value as an
3054 // unsigned integer:
3055 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3056 }
3057
3058 Observer.changedInstr(MI);
3059 return Legalized;
3060
3061 case TargetOpcode::G_ROTR:
3062 case TargetOpcode::G_ROTL:
3063 if (TypeIdx != 1)
3064 return UnableToLegalize;
3065
3066 Observer.changingInstr(MI);
3067 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3068 Observer.changedInstr(MI);
3069 return Legalized;
3070
3071 case TargetOpcode::G_SDIV:
3072 case TargetOpcode::G_SREM:
3073 case TargetOpcode::G_SMIN:
3074 case TargetOpcode::G_SMAX:
3075 case TargetOpcode::G_ABDS:
3076 Observer.changingInstr(MI);
3077 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3078 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3079 widenScalarDst(MI, WideTy);
3080 Observer.changedInstr(MI);
3081 return Legalized;
3082
3083 case TargetOpcode::G_SDIVREM:
3084 Observer.changingInstr(MI);
3085 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3086 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3087 widenScalarDst(MI, WideTy);
3088 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3089 widenScalarDst(MI, WideTy, 1);
3090 Observer.changedInstr(MI);
3091 return Legalized;
3092
3093 case TargetOpcode::G_ASHR:
3094 case TargetOpcode::G_LSHR:
3095 Observer.changingInstr(MI);
3096
3097 if (TypeIdx == 0) {
3098 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3099 : TargetOpcode::G_ZEXT;
3100
3101 widenScalarSrc(MI, WideTy, 1, CvtOp);
3102 widenScalarDst(MI, WideTy);
3103 } else {
3104 assert(TypeIdx == 1);
3105 // The "number of bits to shift" operand must preserve its value as an
3106 // unsigned integer:
3107 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3108 }
3109
3110 Observer.changedInstr(MI);
3111 return Legalized;
3112 case TargetOpcode::G_UDIV:
3113 case TargetOpcode::G_UREM:
3114 case TargetOpcode::G_ABDU:
3115 Observer.changingInstr(MI);
3116 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3117 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3118 widenScalarDst(MI, WideTy);
3119 Observer.changedInstr(MI);
3120 return Legalized;
3121 case TargetOpcode::G_UDIVREM:
3122 Observer.changingInstr(MI);
3123 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3124 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3125 widenScalarDst(MI, WideTy);
3126 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3127 widenScalarDst(MI, WideTy, 1);
3128 Observer.changedInstr(MI);
3129 return Legalized;
3130 case TargetOpcode::G_UMIN:
3131 case TargetOpcode::G_UMAX: {
3132 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3133
3134 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3135 unsigned ExtOpc =
3136 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3137 getApproximateEVTForLLT(WideTy, Ctx))
3138 ? TargetOpcode::G_SEXT
3139 : TargetOpcode::G_ZEXT;
3140
3141 Observer.changingInstr(MI);
3142 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3143 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3144 widenScalarDst(MI, WideTy);
3145 Observer.changedInstr(MI);
3146 return Legalized;
3147 }
3148
3149 case TargetOpcode::G_SELECT:
3150 Observer.changingInstr(MI);
3151 if (TypeIdx == 0) {
3152 // Perform operation at larger width (any extension is fine here, high
3153 // bits don't affect the result) and then truncate the result back to the
3154 // original type.
3155 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3156 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3157 widenScalarDst(MI, WideTy);
3158 } else {
3159 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3160 // Explicit extension is required here since high bits affect the result.
3161 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3162 }
3163 Observer.changedInstr(MI);
3164 return Legalized;
3165
3166 case TargetOpcode::G_FPEXT:
3167 if (TypeIdx != 1)
3168 return UnableToLegalize;
3169
3170 Observer.changingInstr(MI);
3171 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3172 Observer.changedInstr(MI);
3173 return Legalized;
3174 case TargetOpcode::G_FPTOSI:
3175 case TargetOpcode::G_FPTOUI:
3176 case TargetOpcode::G_INTRINSIC_LRINT:
3177 case TargetOpcode::G_INTRINSIC_LLRINT:
3178 case TargetOpcode::G_IS_FPCLASS:
3179 Observer.changingInstr(MI);
3180
3181 if (TypeIdx == 0)
3182 widenScalarDst(MI, WideTy);
3183 else
3184 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3185
3186 Observer.changedInstr(MI);
3187 return Legalized;
3188 case TargetOpcode::G_SITOFP:
3189 Observer.changingInstr(MI);
3190
3191 if (TypeIdx == 0)
3192 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3193 else
3194 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3195
3196 Observer.changedInstr(MI);
3197 return Legalized;
3198 case TargetOpcode::G_UITOFP:
3199 Observer.changingInstr(MI);
3200
3201 if (TypeIdx == 0)
3202 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3203 else
3204 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3205
3206 Observer.changedInstr(MI);
3207 return Legalized;
3208 case TargetOpcode::G_FPTOSI_SAT:
3209 case TargetOpcode::G_FPTOUI_SAT:
3210 Observer.changingInstr(MI);
3211
3212 if (TypeIdx == 0) {
3213 Register OldDst = MI.getOperand(0).getReg();
3214 LLT Ty = MRI.getType(OldDst);
3215 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3216 Register NewDst;
3217 MI.getOperand(0).setReg(ExtReg);
3218 uint64_t ShortBits = Ty.getScalarSizeInBits();
3219 uint64_t WideBits = WideTy.getScalarSizeInBits();
3220 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3221 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3222 // z = i16 fptosi_sat(a)
3223 // ->
3224 // x = i32 fptosi_sat(a)
3225 // y = smin(x, 32767)
3226 // z = smax(y, -32768)
3227 auto MaxVal = MIRBuilder.buildConstant(
3228 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3229 auto MinVal = MIRBuilder.buildConstant(
3230 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3231 Register MidReg =
3232 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3233 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3234 } else {
3235 // z = i16 fptoui_sat(a)
3236 // ->
3237 // x = i32 fptoui_sat(a)
3238 // y = smin(x, 65535)
3239 auto MaxVal = MIRBuilder.buildConstant(
3240 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3241 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3242 }
3243 MIRBuilder.buildTrunc(OldDst, NewDst);
3244 } else
3245 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3246
3247 Observer.changedInstr(MI);
3248 return Legalized;
3249 case TargetOpcode::G_LOAD:
3250 case TargetOpcode::G_SEXTLOAD:
3251 case TargetOpcode::G_ZEXTLOAD:
3252 case TargetOpcode::G_FPEXTLOAD:
3253 Observer.changingInstr(MI);
3254 widenScalarDst(MI, WideTy);
3255 Observer.changedInstr(MI);
3256 return Legalized;
3257
3258 case TargetOpcode::G_STORE: {
3259 if (TypeIdx != 0)
3260 return UnableToLegalize;
3261
3262 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3263 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3264 if (!Ty.isScalar()) {
3265 // We need to widen the vector element type.
3266 Observer.changingInstr(MI);
3267 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3268 // We also need to adjust the MMO to turn this into a truncating store.
3269 MachineMemOperand &MMO = **MI.memoperands_begin();
3270 MachineFunction &MF = MIRBuilder.getMF();
3271 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3272 MI.setMemRefs(MF, {NewMMO});
3273 Observer.changedInstr(MI);
3274 return Legalized;
3275 }
3276
3277 Observer.changingInstr(MI);
3278
3279 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3280 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3281 widenScalarSrc(MI, WideTy, 0, ExtType);
3282
3283 Observer.changedInstr(MI);
3284 return Legalized;
3285 }
3286 case TargetOpcode::G_FPTRUNCSTORE:
3287 if (TypeIdx != 0)
3288 return UnableToLegalize;
3289 Observer.changingInstr(MI);
3290 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3291 Observer.changedInstr(MI);
3292 return Legalized;
3293 case TargetOpcode::G_CONSTANT: {
3294 MachineOperand &SrcMO = MI.getOperand(1);
3295 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3296 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3297 MRI.getType(MI.getOperand(0).getReg()));
3298 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3299 ExtOpc == TargetOpcode::G_ANYEXT) &&
3300 "Illegal Extend");
3301 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3302 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3303 ? SrcVal.sext(WideTy.getSizeInBits())
3304 : SrcVal.zext(WideTy.getSizeInBits());
3305 Observer.changingInstr(MI);
3306 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3307
3308 widenScalarDst(MI, WideTy);
3309 Observer.changedInstr(MI);
3310 return Legalized;
3311 }
3312 case TargetOpcode::G_FCONSTANT: {
3313 // To avoid changing the bits of the constant due to extension to a larger
3314 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3315 MachineOperand &SrcMO = MI.getOperand(1);
3316 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3317 MIRBuilder.setInstrAndDebugLoc(MI);
3318 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3319 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3320 MI.eraseFromParent();
3321 return Legalized;
3322 }
3323 case TargetOpcode::G_IMPLICIT_DEF: {
3324 Observer.changingInstr(MI);
3325 widenScalarDst(MI, WideTy);
3326 Observer.changedInstr(MI);
3327 return Legalized;
3328 }
3329 case TargetOpcode::G_BRCOND:
3330 Observer.changingInstr(MI);
3331 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3332 Observer.changedInstr(MI);
3333 return Legalized;
3334
3335 case TargetOpcode::G_FCMP:
3336 Observer.changingInstr(MI);
3337 if (TypeIdx == 0)
3338 widenScalarDst(MI, WideTy);
3339 else {
3340 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3341 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3342 }
3343 Observer.changedInstr(MI);
3344 return Legalized;
3345
3346 case TargetOpcode::G_ICMP:
3347 Observer.changingInstr(MI);
3348 if (TypeIdx == 0)
3349 widenScalarDst(MI, WideTy);
3350 else {
3351 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3352 CmpInst::Predicate Pred =
3353 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3354
3355 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3356 unsigned ExtOpcode =
3357 (CmpInst::isSigned(Pred) ||
3358 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3359 getApproximateEVTForLLT(WideTy, Ctx)))
3360 ? TargetOpcode::G_SEXT
3361 : TargetOpcode::G_ZEXT;
3362 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3363 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3364 }
3365 Observer.changedInstr(MI);
3366 return Legalized;
3367
3368 case TargetOpcode::G_PTR_ADD:
3369 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3370 Observer.changingInstr(MI);
3371 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3372 Observer.changedInstr(MI);
3373 return Legalized;
3374
3375 case TargetOpcode::G_PHI: {
3376 assert(TypeIdx == 0 && "Expecting only Idx 0");
3377
3378 Observer.changingInstr(MI);
3379 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3380 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3381 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3382 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3383 }
3384
3385 MachineBasicBlock &MBB = *MI.getParent();
3386 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3387 widenScalarDst(MI, WideTy);
3388 Observer.changedInstr(MI);
3389 return Legalized;
3390 }
3391 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3392 if (TypeIdx == 0) {
3393 Register VecReg = MI.getOperand(1).getReg();
3394 LLT VecTy = MRI.getType(VecReg);
3395 Observer.changingInstr(MI);
3396
3397 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3398 TargetOpcode::G_ANYEXT);
3399
3400 widenScalarDst(MI, WideTy, 0);
3401 Observer.changedInstr(MI);
3402 return Legalized;
3403 }
3404
3405 if (TypeIdx != 2)
3406 return UnableToLegalize;
3407 Observer.changingInstr(MI);
3408 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3409 Observer.changedInstr(MI);
3410 return Legalized;
3411 }
3412 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3413 if (TypeIdx == 0) {
3414 Observer.changingInstr(MI);
3415 const LLT WideEltTy = WideTy.getElementType();
3416
3417 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3418 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3419 widenScalarDst(MI, WideTy, 0);
3420 Observer.changedInstr(MI);
3421 return Legalized;
3422 }
3423
3424 if (TypeIdx == 1) {
3425 Observer.changingInstr(MI);
3426
3427 Register VecReg = MI.getOperand(1).getReg();
3428 LLT VecTy = MRI.getType(VecReg);
3429 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3430
3431 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3432 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3433 widenScalarDst(MI, WideVecTy, 0);
3434 Observer.changedInstr(MI);
3435 return Legalized;
3436 }
3437
3438 if (TypeIdx == 2) {
3439 Observer.changingInstr(MI);
3440 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3441 Observer.changedInstr(MI);
3442 return Legalized;
3443 }
3444
3445 return UnableToLegalize;
3446 }
3447 case TargetOpcode::G_FADD:
3448 case TargetOpcode::G_FMUL:
3449 case TargetOpcode::G_FSUB:
3450 case TargetOpcode::G_FMA:
3451 case TargetOpcode::G_FMAD:
3452 case TargetOpcode::G_FNEG:
3453 case TargetOpcode::G_FABS:
3454 case TargetOpcode::G_FCANONICALIZE:
3455 case TargetOpcode::G_FMINNUM:
3456 case TargetOpcode::G_FMAXNUM:
3457 case TargetOpcode::G_FMINNUM_IEEE:
3458 case TargetOpcode::G_FMAXNUM_IEEE:
3459 case TargetOpcode::G_FMINIMUM:
3460 case TargetOpcode::G_FMAXIMUM:
3461 case TargetOpcode::G_FMINIMUMNUM:
3462 case TargetOpcode::G_FMAXIMUMNUM:
3463 case TargetOpcode::G_FDIV:
3464 case TargetOpcode::G_FREM:
3465 case TargetOpcode::G_FCEIL:
3466 case TargetOpcode::G_FFLOOR:
3467 case TargetOpcode::G_FCOS:
3468 case TargetOpcode::G_FSIN:
3469 case TargetOpcode::G_FTAN:
3470 case TargetOpcode::G_FACOS:
3471 case TargetOpcode::G_FASIN:
3472 case TargetOpcode::G_FATAN:
3473 case TargetOpcode::G_FATAN2:
3474 case TargetOpcode::G_FCOSH:
3475 case TargetOpcode::G_FSINH:
3476 case TargetOpcode::G_FTANH:
3477 case TargetOpcode::G_FLOG10:
3478 case TargetOpcode::G_FLOG:
3479 case TargetOpcode::G_FLOG2:
3480 case TargetOpcode::G_FRINT:
3481 case TargetOpcode::G_FNEARBYINT:
3482 case TargetOpcode::G_FSQRT:
3483 case TargetOpcode::G_FEXP:
3484 case TargetOpcode::G_FEXP2:
3485 case TargetOpcode::G_FEXP10:
3486 case TargetOpcode::G_FPOW:
3487 case TargetOpcode::G_INTRINSIC_TRUNC:
3488 case TargetOpcode::G_INTRINSIC_ROUND:
3489 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3490 assert(TypeIdx == 0);
3491 Observer.changingInstr(MI);
3492
3493 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3494 widenScalarSrcUsingFPExt(MI, WideTy, I);
3495
3496 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3497 Observer.changedInstr(MI);
3498 return Legalized;
3499 case TargetOpcode::G_FMODF: {
3500 Observer.changingInstr(MI);
3501 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3502
3503 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3504 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3505 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3506 Observer.changedInstr(MI);
3507 return Legalized;
3508 }
3509 case TargetOpcode::G_FPOWI:
3510 case TargetOpcode::G_FLDEXP:
3511 case TargetOpcode::G_STRICT_FLDEXP: {
3512 if (TypeIdx == 0) {
3513 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3514 return UnableToLegalize;
3515
3516 Observer.changingInstr(MI);
3517 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3518 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3519 Observer.changedInstr(MI);
3520 return Legalized;
3521 }
3522
3523 if (TypeIdx == 1) {
3524 // For some reason SelectionDAG tries to promote to a libcall without
3525 // actually changing the integer type for promotion.
3526 Observer.changingInstr(MI);
3527 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3528 Observer.changedInstr(MI);
3529 return Legalized;
3530 }
3531
3532 return UnableToLegalize;
3533 }
3534 case TargetOpcode::G_FFREXP: {
3535 Observer.changingInstr(MI);
3536
3537 if (TypeIdx == 0) {
3538 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3539 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3540 } else {
3541 widenScalarDst(MI, WideTy, 1);
3542 }
3543
3544 Observer.changedInstr(MI);
3545 return Legalized;
3546 }
3547 case TargetOpcode::G_LROUND:
3548 case TargetOpcode::G_LLROUND:
3549 Observer.changingInstr(MI);
3550
3551 if (TypeIdx == 0)
3552 widenScalarDst(MI, WideTy);
3553 else
3554 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3555
3556 Observer.changedInstr(MI);
3557 return Legalized;
3558
3559 case TargetOpcode::G_INTTOPTR:
3560 if (TypeIdx != 1)
3561 return UnableToLegalize;
3562
3563 Observer.changingInstr(MI);
3564 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3565 Observer.changedInstr(MI);
3566 return Legalized;
3567 case TargetOpcode::G_PTRTOINT:
3568 if (TypeIdx != 0)
3569 return UnableToLegalize;
3570
3571 Observer.changingInstr(MI);
3572 widenScalarDst(MI, WideTy, 0);
3573 Observer.changedInstr(MI);
3574 return Legalized;
3575 case TargetOpcode::G_BUILD_VECTOR: {
3576 Observer.changingInstr(MI);
3577
3578 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3579 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3580 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3581
3582 // Avoid changing the result vector type if the source element type was
3583 // requested.
3584 if (TypeIdx == 1) {
3585 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3586 } else {
3587 widenScalarDst(MI, WideTy, 0);
3588 }
3589
3590 Observer.changedInstr(MI);
3591 return Legalized;
3592 }
3593 case TargetOpcode::G_SEXT_INREG:
3594 if (TypeIdx != 0)
3595 return UnableToLegalize;
3596
3597 Observer.changingInstr(MI);
3598 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3599 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3600 Observer.changedInstr(MI);
3601 return Legalized;
3602 case TargetOpcode::G_PTRMASK: {
3603 if (TypeIdx != 1)
3604 return UnableToLegalize;
3605 Observer.changingInstr(MI);
3606 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3607 Observer.changedInstr(MI);
3608 return Legalized;
3609 }
3610 case TargetOpcode::G_VECREDUCE_ADD: {
3611 if (TypeIdx != 1)
3612 return UnableToLegalize;
3613 Observer.changingInstr(MI);
3614 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3615 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3616 Observer.changedInstr(MI);
3617 return Legalized;
3618 }
3619 case TargetOpcode::G_VECREDUCE_FADD:
3620 case TargetOpcode::G_VECREDUCE_FMUL:
3621 case TargetOpcode::G_VECREDUCE_FMIN:
3622 case TargetOpcode::G_VECREDUCE_FMAX:
3623 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3624 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3625 if (TypeIdx != 0)
3626 return UnableToLegalize;
3627 Observer.changingInstr(MI);
3628 Register VecReg = MI.getOperand(1).getReg();
3629 LLT VecTy = MRI.getType(VecReg);
3630 LLT WideVecTy = VecTy.changeElementType(WideTy);
3631 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3632 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3633 Observer.changedInstr(MI);
3634 return Legalized;
3635 }
3636 case TargetOpcode::G_VSCALE: {
3637 MachineOperand &SrcMO = MI.getOperand(1);
3638 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3639 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3640 // The CImm is always a signed value
3641 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3642 Observer.changingInstr(MI);
3643 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3644 widenScalarDst(MI, WideTy);
3645 Observer.changedInstr(MI);
3646 return Legalized;
3647 }
3648 case TargetOpcode::G_SPLAT_VECTOR: {
3649 if (TypeIdx != 1)
3650 return UnableToLegalize;
3651
3652 Observer.changingInstr(MI);
3653 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3654 Observer.changedInstr(MI);
3655 return Legalized;
3656 }
3657 case TargetOpcode::G_INSERT_SUBVECTOR: {
3658 if (TypeIdx != 0)
3659 return UnableToLegalize;
3660
3662 Register BigVec = IS.getBigVec();
3663 Register SubVec = IS.getSubVec();
3664
3665 LLT SubVecTy = MRI.getType(SubVec);
3666 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3667
3668 // Widen the G_INSERT_SUBVECTOR
3669 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3670 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3671 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3672 IS.getIndexImm());
3673
3674 // Truncate back down
3675 auto SplatZero = MIRBuilder.buildSplatVector(
3676 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3677 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3678 SplatZero);
3679
3680 MI.eraseFromParent();
3681
3682 return Legalized;
3683 }
3684 case TargetOpcode::G_BITCAST:
3685 if (WideTy.isVector())
3686 return UnableToLegalize;
3687 Observer.changingInstr(MI);
3688 if (TypeIdx == 0)
3689 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3690 else
3691 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3692 Observer.changedInstr(MI);
3693
3694 Register Dst = MI.getOperand(0).getReg();
3695 Register Src = MI.getOperand(1).getReg();
3696 if (MRI.getType(Dst) == MRI.getType(Src)) {
3697 Observer.changingAllUsesOfReg(MRI, Dst);
3698 MRI.replaceRegWith(Dst, Src);
3699 Observer.finishedChangingAllUsesOfReg();
3700 MI.eraseFromParent();
3701 }
3702
3703 return Legalized;
3704 }
3705}
3706
3708 MachineIRBuilder &B, Register Src, LLT Ty) {
3709 auto Unmerge = B.buildUnmerge(Ty, Src);
3710 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3711 Pieces.push_back(Unmerge.getReg(I));
3712}
3713
3714static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3715 MachineIRBuilder &MIRBuilder) {
3716 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3717 MachineFunction &MF = MIRBuilder.getMF();
3718 const DataLayout &DL = MIRBuilder.getDataLayout();
3719 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3720 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3721 LLT DstLLT = MRI.getType(DstReg);
3722
3723 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3724
3725 auto Addr = MIRBuilder.buildConstantPool(
3726 AddrPtrTy,
3727 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3728
3729 MachineMemOperand *MMO =
3731 MachineMemOperand::MOLoad, DstLLT, Alignment);
3732
3733 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3734}
3735
3738 const MachineOperand &ConstOperand = MI.getOperand(1);
3739 const Constant *ConstantVal = ConstOperand.getCImm();
3740
3741 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3742 MI.eraseFromParent();
3743
3744 return Legalized;
3745}
3746
3749 Register Dst = MI.getOperand(0).getReg();
3750 const ConstantFP *ConstantVal = MI.getOperand(1).getFPImm();
3751 const APFloat &Imm = ConstantVal->getValueAPF();
3752
3753 bool ForCodeSize = MIRBuilder.getMF().getFunction().hasOptSize();
3754 if (TLI.getFPImmAction(Imm, MRI.getType(Dst), ForCodeSize) ==
3756 MIRBuilder.buildConstant(Dst, Imm.bitcastToAPInt());
3757 else
3758 emitLoadFromConstantPool(Dst, ConstantVal, MIRBuilder);
3759
3760 MI.eraseFromParent();
3761 return Legalized;
3762}
3763
3766 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3767 if (SrcTy.isVector()) {
3768 LLT SrcEltTy = SrcTy.getElementType();
3770
3771 if (DstTy.isVector()) {
3772 LLT DstEltTy = DstTy.getElementType();
3773 ElementCount DstEC = DstTy.getElementCount();
3774 ElementCount SrcEC = SrcTy.getElementCount();
3775
3776 if (!SrcEC.isKnownMultipleOf(DstEC) && !DstEC.isKnownMultipleOf(SrcEC)) {
3777 // Split non-integer element ratio bitcast
3778 //
3779 // %1:_(<3 x s16>) = G_BITCAST %0:_(<2 x s24>)
3780 //
3781 // =>
3782 //
3783 // %2:_(<6 x s8>) = G_BITCAST %0:_(<2 x s24>)
3784 // %1:_(<3 x s16>) = G_BITCAST %2:_(<6 x s8>)
3785 unsigned SrcEltSize = SrcEltTy.getScalarSizeInBits();
3786 unsigned PieceSize =
3787 std::gcd(SrcEltSize, DstEltTy.getScalarSizeInBits());
3788 LLT PieceTy = LLT::integer(PieceSize);
3789
3790 if (!PieceTy.isByteSized()) {
3791 // Split bitcast whose pieces are not whole bytes through a scalar
3792 //
3793 // %1:_(<3 x s8>) = G_BITCAST %0:_(<2 x s12>)
3794 //
3795 // =>
3796 //
3797 // %2:_(s24) = G_BITCAST %0:_(<2 x s12>)
3798 // %1:_(<3 x s8>) = G_BITCAST %2:_(s24)
3799 LLT ScalarTy = LLT::integer(SrcTy.getSizeInBits());
3800 Register ScalarReg = MIRBuilder.buildBitcast(ScalarTy, Src).getReg(0);
3801 MIRBuilder.buildBitcast(Dst, ScalarReg);
3802 MI.eraseFromParent();
3803 return Legalized;
3804 }
3805
3806 LLT PiecesVecTy =
3807 LLT::vector(SrcEC * (SrcEltSize / PieceSize), PieceTy);
3808 Register PiecesReg =
3809 MIRBuilder.buildBitcast(PiecesVecTy, Src).getReg(0);
3810 MIRBuilder.buildBitcast(Dst, PiecesReg);
3811 MI.eraseFromParent();
3812 return Legalized;
3813 }
3814
3815 unsigned NumDstElt = DstEC.getKnownMinValue();
3816 unsigned NumSrcElt = SrcEC.getKnownMinValue();
3817
3818 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3819 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3820
3821 // If there's an element size mismatch, insert intermediate casts to match
3822 // the result element type.
3823 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3824 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3825 //
3826 // =>
3827 //
3828 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3829 // %3:_(<2 x s8>) = G_BITCAST %2
3830 // %4:_(<2 x s8>) = G_BITCAST %3
3831 // %1:_(<4 x s8>) = G_CONCAT_VECTORS %3, %4
3832 DstCastTy = DstTy.changeVectorElementCount(
3833 ElementCount::getFixed(NumDstElt / NumSrcElt));
3834 SrcPartTy = SrcEltTy;
3835 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3836 //
3837 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3838 //
3839 // =>
3840 //
3841 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3842 // %3:_(s16) = G_BITCAST %2
3843 // %4:_(s16) = G_BITCAST %3
3844 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3845 SrcPartTy = SrcTy.changeVectorElementCount(
3846 ElementCount::getFixed(NumSrcElt / NumDstElt));
3847 DstCastTy = DstEltTy;
3848 }
3849
3850 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3851 for (Register &SrcReg : SrcRegs)
3852 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3853 } else
3854 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3855
3856 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3857 MI.eraseFromParent();
3858 return Legalized;
3859 }
3860
3861 if (DstTy.isVector()) {
3863 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3864 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3865 MI.eraseFromParent();
3866 return Legalized;
3867 }
3868
3869 return UnableToLegalize;
3870}
3871
3872/// Figure out the bit offset into a register when coercing a vector index for
3873/// the wide element type. This is only for the case when promoting vector to
3874/// one with larger elements.
3875//
3876///
3877/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3878/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3880 Register Idx,
3881 unsigned NewEltSize,
3882 unsigned OldEltSize) {
3883 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3884 LLT IdxTy = B.getMRI()->getType(Idx);
3885
3886 // Now figure out the amount we need to shift to get the target bits.
3887 auto OffsetMask = B.buildConstant(
3888 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3889 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3890 return B.buildShl(IdxTy, OffsetIdx,
3891 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3892}
3893
3894/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3895/// is casting to a vector with a smaller element size, perform multiple element
3896/// extracts and merge the results. If this is coercing to a vector with larger
3897/// elements, index the bitcasted vector and extract the target element with bit
3898/// operations. This is intended to force the indexing in the native register
3899/// size for architectures that can dynamically index the register file.
3902 LLT CastTy) {
3903 if (TypeIdx != 1)
3904 return UnableToLegalize;
3905
3906 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3907
3908 LLT SrcEltTy = SrcVecTy.getElementType();
3909 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3910 unsigned OldNumElts = SrcVecTy.getNumElements();
3911
3912 LLT NewEltTy = CastTy.getScalarType();
3913 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3914
3915 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3916 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3917 if (NewNumElts > OldNumElts) {
3918 // Decreasing the vector element size
3919 //
3920 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3921 // =>
3922 // v4i32:castx = bitcast x:v2i64
3923 //
3924 // i64 = bitcast
3925 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3926 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3927 //
3928 if (NewNumElts % OldNumElts != 0)
3929 return UnableToLegalize;
3930
3931 // Type of the intermediate result vector.
3932 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3933 LLT MidTy =
3934 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3935
3936 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3937
3938 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3939 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3940
3941 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3942 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3943 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3944 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3945 NewOps[I] = Elt.getReg(0);
3946 }
3947
3948 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3949 MIRBuilder.buildBitcast(Dst, NewVec);
3950 MI.eraseFromParent();
3951 return Legalized;
3952 }
3953
3954 if (NewNumElts < OldNumElts) {
3955 if (NewEltSize % OldEltSize != 0)
3956 return UnableToLegalize;
3957
3958 // This only depends on powers of 2 because we use bit tricks to figure out
3959 // the bit offset we need to shift to get the target element. A general
3960 // expansion could emit division/multiply.
3961 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3962 return UnableToLegalize;
3963
3964 // Increasing the vector element size.
3965 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3966 //
3967 // =>
3968 //
3969 // %cast = G_BITCAST %vec
3970 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3971 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3972 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3973 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3974 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3975 // %elt = G_TRUNC %elt_bits
3976
3977 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3978 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3979
3980 // Divide to get the index in the wider element type.
3981 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3982
3983 Register WideElt = CastVec;
3984 if (CastTy.isVector()) {
3985 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3986 ScaledIdx).getReg(0);
3987 }
3988
3989 // Compute the bit offset into the register of the target element.
3991 MIRBuilder, Idx, NewEltSize, OldEltSize);
3992
3993 // Shift the wide element to get the target element.
3994 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3995 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3996 MI.eraseFromParent();
3997 return Legalized;
3998 }
3999
4000 return UnableToLegalize;
4001}
4002
4003/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
4004/// TargetReg, while preserving other bits in \p TargetReg.
4005///
4006/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
4008 Register TargetReg, Register InsertReg,
4009 Register OffsetBits) {
4010 LLT TargetTy = B.getMRI()->getType(TargetReg);
4011 LLT InsertTy = B.getMRI()->getType(InsertReg);
4012 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
4013 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
4014
4015 // Produce a bitmask of the value to insert
4016 auto EltMask = B.buildConstant(
4017 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
4018 InsertTy.getSizeInBits()));
4019 // Shift it into position
4020 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
4021 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
4022
4023 // Clear out the bits in the wide element
4024 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
4025
4026 // The value to insert has all zeros already, so stick it into the masked
4027 // wide element.
4028 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
4029}
4030
4031/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
4032/// is increasing the element size, perform the indexing in the target element
4033/// type, and use bit operations to insert at the element position. This is
4034/// intended for architectures that can dynamically index the register file and
4035/// want to force indexing in the native register size.
4038 LLT CastTy) {
4039 if (TypeIdx != 0)
4040 return UnableToLegalize;
4041
4042 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
4043 MI.getFirst4RegLLTs();
4044 LLT VecTy = DstTy;
4045
4046 LLT VecEltTy = VecTy.getElementType();
4047 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
4048 const unsigned NewEltSize = NewEltTy.getSizeInBits();
4049 const unsigned OldEltSize = VecEltTy.getSizeInBits();
4050
4051 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
4052 unsigned OldNumElts = VecTy.getNumElements();
4053
4054 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
4055 if (NewNumElts < OldNumElts) {
4056 if (NewEltSize % OldEltSize != 0)
4057 return UnableToLegalize;
4058
4059 // This only depends on powers of 2 because we use bit tricks to figure out
4060 // the bit offset we need to shift to get the target element. A general
4061 // expansion could emit division/multiply.
4062 if (!isPowerOf2_32(NewEltSize / OldEltSize))
4063 return UnableToLegalize;
4064
4065 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4066 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4067
4068 // Divide to get the index in the wider element type.
4069 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4070
4071 Register ExtractedElt = CastVec;
4072 if (CastTy.isVector()) {
4073 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4074 ScaledIdx).getReg(0);
4075 }
4076
4077 // Compute the bit offset into the register of the target element.
4079 MIRBuilder, Idx, NewEltSize, OldEltSize);
4080
4081 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
4082 Val, OffsetBits);
4083 if (CastTy.isVector()) {
4084 InsertedElt = MIRBuilder.buildInsertVectorElement(
4085 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
4086 }
4087
4088 MIRBuilder.buildBitcast(Dst, InsertedElt);
4089 MI.eraseFromParent();
4090 return Legalized;
4091 }
4092
4093 return UnableToLegalize;
4094}
4095
4096// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4097// those that have smaller than legal operands.
4098//
4099// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4100//
4101// ===>
4102//
4103// s32 = G_BITCAST <4 x s8>
4104// s32 = G_BITCAST <4 x s8>
4105// s32 = G_BITCAST <4 x s8>
4106// s32 = G_BITCAST <4 x s8>
4107// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4108// <16 x s8> = G_BITCAST <4 x s32>
4111 LLT CastTy) {
4112 // Convert it to CONCAT instruction
4113 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4114 if (!ConcatMI) {
4115 return UnableToLegalize;
4116 }
4117
4118 // Check if bitcast is Legal
4119 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4120 LLT SrcScalTy = CastTy.getScalarType();
4121
4122 // Check if the build vector is Legal
4123 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4124 return UnableToLegalize;
4125 }
4126
4127 // Bitcast the sources
4128 SmallVector<Register> BitcastRegs;
4129 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4130 BitcastRegs.push_back(
4131 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4132 .getReg(0));
4133 }
4134
4135 // Build the scalar values into a vector
4136 Register BuildReg =
4137 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4138 MIRBuilder.buildBitcast(DstReg, BuildReg);
4139
4140 MI.eraseFromParent();
4141 return Legalized;
4142}
4143
4144// This bitcasts a shuffle vector to a different type currently of the same
4145// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4146// will be used instead.
4147//
4148// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4149// ===>
4150// <4 x s64> = G_PTRTOINT <4 x p0>
4151// <4 x s64> = G_PTRTOINT <4 x p0>
4152// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4153// <16 x p0> = G_INTTOPTR <16 x s64>
4156 LLT CastTy) {
4157 auto ShuffleMI = cast<GShuffleVector>(&MI);
4158 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4159 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4160
4161 // We currently only handle vectors of the same size.
4162 if (TypeIdx != 0 ||
4163 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4164 CastTy.getElementCount() != DstTy.getElementCount())
4165 return UnableToLegalize;
4166
4167 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4168
4169 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4170 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4171 auto Shuf =
4172 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4173 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4174
4175 MI.eraseFromParent();
4176 return Legalized;
4177}
4178
4179/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4180///
4181/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4182///
4183/// ===>
4184///
4185/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4186/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4187/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4190 LLT CastTy) {
4191 auto ES = cast<GExtractSubvector>(&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 Src = ES->getSrcVec();
4201 uint64_t Idx = ES->getIndexImm();
4202
4203 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4204
4205 LLT DstTy = MRI.getType(Dst);
4206 LLT SrcTy = MRI.getType(Src);
4207 ElementCount DstTyEC = DstTy.getElementCount();
4208 ElementCount SrcTyEC = SrcTy.getElementCount();
4209 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4210 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4211
4212 if (DstTy == CastTy)
4213 return Legalized;
4214
4215 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4216 return UnableToLegalize;
4217
4218 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4219 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4220 if (CastEltSize < DstEltSize)
4221 return UnableToLegalize;
4222
4223 auto AdjustAmt = CastEltSize / DstEltSize;
4224 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4225 SrcTyMinElts % AdjustAmt != 0)
4226 return UnableToLegalize;
4227
4228 Idx /= AdjustAmt;
4229 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4230 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4231 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4232 MIRBuilder.buildBitcast(Dst, PromotedES);
4233
4234 ES->eraseFromParent();
4235 return Legalized;
4236}
4237
4238/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4239///
4240/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4241/// <vscale x 8 x i1>,
4242/// N
4243///
4244/// ===>
4245///
4246/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4247/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4248/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4249/// <vscale x 1 x i8>, N / 8
4250/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4253 LLT CastTy) {
4254 auto ES = cast<GInsertSubvector>(&MI);
4255
4256 if (!CastTy.isVector())
4257 return UnableToLegalize;
4258
4259 if (TypeIdx != 0)
4260 return UnableToLegalize;
4261
4262 Register Dst = ES->getReg(0);
4263 Register BigVec = ES->getBigVec();
4264 Register SubVec = ES->getSubVec();
4265 uint64_t Idx = ES->getIndexImm();
4266
4267 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4268
4269 LLT DstTy = MRI.getType(Dst);
4270 LLT BigVecTy = MRI.getType(BigVec);
4271 LLT SubVecTy = MRI.getType(SubVec);
4272
4273 if (DstTy == CastTy)
4274 return Legalized;
4275
4276 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4277 return UnableToLegalize;
4278
4279 ElementCount DstTyEC = DstTy.getElementCount();
4280 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4281 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4282 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4283 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4284 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4285
4286 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4287 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4288 if (CastEltSize < DstEltSize)
4289 return UnableToLegalize;
4290
4291 auto AdjustAmt = CastEltSize / DstEltSize;
4292 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4293 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4294 return UnableToLegalize;
4295
4296 Idx /= AdjustAmt;
4297 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4298 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4299 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4300 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4301 auto PromotedIS =
4302 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4303 MIRBuilder.buildBitcast(Dst, PromotedIS);
4304
4305 ES->eraseFromParent();
4306 return Legalized;
4307}
4308
4310 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4311 Register DstReg = LoadMI.getDstReg();
4312 Register PtrReg = LoadMI.getPointerReg();
4313 LLT DstTy = MRI.getType(DstReg);
4314 MachineMemOperand &MMO = LoadMI.getMMO();
4315 LLT MemTy = MMO.getMemoryType();
4316 MachineFunction &MF = MIRBuilder.getMF();
4317
4318 LLT EltTy = MemTy.getScalarType();
4319
4320 unsigned MemSizeInBits = MemTy.getSizeInBits();
4321 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4322
4323 if (MemSizeInBits != MemStoreSizeInBits) {
4324 if (MemTy.isVector())
4325 return UnableToLegalize;
4326
4327 // Promote to a byte-sized load if not loading an integral number of
4328 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4329 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4330 MachineMemOperand *NewMMO =
4331 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4332
4333 Register LoadReg = DstReg;
4334 LLT LoadTy = DstTy;
4335
4336 // If this wasn't already an extending load, we need to widen the result
4337 // register to avoid creating a load with a narrower result than the source.
4338 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4339 LoadTy = WideMemTy;
4340 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4341 }
4342
4343 if (isa<GSExtLoad>(LoadMI)) {
4344 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4345 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4346 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4347 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4348 // The extra bits are guaranteed to be zero, since we stored them that
4349 // way. A zext load from Wide thus automatically gives zext from MemVT.
4350 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4351 } else {
4352 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4353 }
4354
4355 if (DstTy != LoadTy)
4356 MIRBuilder.buildTrunc(DstReg, LoadReg);
4357
4358 LoadMI.eraseFromParent();
4359 return Legalized;
4360 }
4361
4362 // Big endian lowering not implemented.
4363 if (MIRBuilder.getDataLayout().isBigEndian())
4364 return UnableToLegalize;
4365
4366 // This load needs splitting into power of 2 sized loads.
4367 //
4368 // Our strategy here is to generate anyextending loads for the smaller
4369 // types up to next power-2 result type, and then combine the two larger
4370 // result values together, before truncating back down to the non-pow-2
4371 // type.
4372 // E.g. v1 = i24 load =>
4373 // v2 = i32 zextload (2 byte)
4374 // v3 = i32 load (1 byte)
4375 // v4 = i32 shl v3, 16
4376 // v5 = i32 or v4, v2
4377 // v1 = i24 trunc v5
4378 // By doing this we generate the correct truncate which should get
4379 // combined away as an artifact with a matching extend.
4380
4381 uint64_t LargeSplitSize, SmallSplitSize;
4382
4383 if (!isPowerOf2_32(MemSizeInBits)) {
4384 // This load needs splitting into power of 2 sized loads.
4385 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4386 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4387 } else {
4388 // This is already a power of 2, but we still need to split this in half.
4389 //
4390 // Assume we're being asked to decompose an unaligned load.
4391 // TODO: If this requires multiple splits, handle them all at once.
4392 auto &Ctx = MF.getFunction().getContext();
4393 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4394 return UnableToLegalize;
4395
4396 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4397 }
4398
4399 if (MemTy.isVector()) {
4400 // TODO: Handle vector extloads
4401 if (MemTy != DstTy)
4402 return UnableToLegalize;
4403
4404 Align Alignment = LoadMI.getAlign();
4405 // Given an alignment larger than the size of the memory, we can increase
4406 // the size of the load without needing to scalarize it.
4407 if (Alignment.value() * 8 > MemSizeInBits &&
4409 LLT MoreTy = DstTy.changeVectorElementCount(
4411 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4412 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4413 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4414 NewLoad.getReg(0));
4415 LoadMI.eraseFromParent();
4416 return Legalized;
4417 }
4418
4419 // TODO: We can do better than scalarizing the vector and at least split it
4420 // in half.
4421 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4422 }
4423
4424 MachineMemOperand *LargeMMO =
4425 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4426 MachineMemOperand *SmallMMO =
4427 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4428
4429 LLT PtrTy = MRI.getType(PtrReg);
4430 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4431
4432 LLT AnyExtTy = LLT::integer(AnyExtSize);
4433 LLT OffsetCstRes = LLT::integer(PtrTy.getSizeInBits());
4434
4435 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4436 PtrReg, *LargeMMO);
4437
4438 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4439 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4440 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4441 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4442 SmallPtr, *SmallMMO);
4443
4444 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4445 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4446
4447 if (AnyExtTy == DstTy)
4448 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4449 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4450 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4451 LLT IntDstTy = DstTy.changeToInteger();
4452 if (IntDstTy == DstTy) {
4453 MIRBuilder.buildTrunc(DstReg, {Or});
4454 } else {
4455 auto Trunc = MIRBuilder.buildTrunc(IntDstTy, Or);
4456 MIRBuilder.buildBitcast(DstReg, Trunc);
4457 }
4458 } else if (DstTy.isPointer()) {
4459 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4460
4461 // FIXME: We currently consider this to be illegal for non-integral address
4462 // spaces, but we need still need a way to reinterpret the bits.
4463 MIRBuilder.buildIntToPtr(DstReg, Or);
4464 } else {
4465 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4466 MIRBuilder.buildBitcast(DstReg, Or);
4467 }
4468
4469 LoadMI.eraseFromParent();
4470 return Legalized;
4471}
4472
4474 // Lower a non-power of 2 store into multiple pow-2 stores.
4475 // E.g. split an i24 store into an i16 store + i8 store.
4476 // We do this by first extending the stored value to the next largest power
4477 // of 2 type, and then using truncating stores to store the components.
4478 // By doing this, likewise with G_LOAD, generate an extend that can be
4479 // artifact-combined away instead of leaving behind extracts.
4480 Register SrcReg = StoreMI.getValueReg();
4481 Register PtrReg = StoreMI.getPointerReg();
4482 LLT SrcTy = MRI.getType(SrcReg);
4483 MachineFunction &MF = MIRBuilder.getMF();
4484 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4485 LLT MemTy = MMO.getMemoryType();
4486
4487 unsigned StoreWidth = MemTy.getSizeInBits();
4488 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4489
4490 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4491 // Promote to a byte-sized store with upper bits zero if not
4492 // storing an integral number of bytes. For example, promote
4493 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4494 LLT WideTy = LLT::integer(StoreSizeInBits);
4495
4496 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4497 // Avoid creating a store with a narrower source than result.
4498 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4499 SrcTy = WideTy;
4500 }
4501
4502 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4503
4504 MachineMemOperand *NewMMO =
4505 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4506 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4507 StoreMI.eraseFromParent();
4508 return Legalized;
4509 }
4510
4511 if (MemTy.isVector()) {
4512 if (MemTy != SrcTy)
4513 return scalarizeVectorBooleanStore(StoreMI);
4514
4515 // TODO: We can do better than scalarizing the vector and at least split it
4516 // in half.
4517 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4518 }
4519
4520 unsigned MemSizeInBits = MemTy.getSizeInBits();
4521 uint64_t LargeSplitSize, SmallSplitSize;
4522
4523 if (!isPowerOf2_32(MemSizeInBits)) {
4524 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4525 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4526 } else {
4527 auto &Ctx = MF.getFunction().getContext();
4528 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4529 return UnableToLegalize; // Don't know what we're being asked to do.
4530
4531 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4532 }
4533
4534 // Extend to the next pow-2. If this store was itself the result of lowering,
4535 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4536 // that's wider than the stored size.
4537 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4538 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4539
4540 if (SrcTy.isPointer()) {
4541 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4542 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4543 }
4544
4545 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4546
4547 // Obtain the smaller value by shifting away the larger value.
4548 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4549 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4550
4551 // Generate the PtrAdd and truncating stores.
4552 LLT PtrTy = MRI.getType(PtrReg);
4553 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4554 LargeSplitSize / 8);
4555 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4556
4557 MachineMemOperand *LargeMMO =
4558 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4559 MachineMemOperand *SmallMMO =
4560 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4561 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4562 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4563 StoreMI.eraseFromParent();
4564 return Legalized;
4565}
4566
4569 Register SrcReg = StoreMI.getValueReg();
4570 Register PtrReg = StoreMI.getPointerReg();
4571 LLT SrcTy = MRI.getType(SrcReg);
4572 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4573 LLT MemTy = MMO.getMemoryType();
4574 LLT MemScalarTy = MemTy.getElementType();
4575 MachineFunction &MF = MIRBuilder.getMF();
4576
4577 assert(SrcTy.isVector() && "Expect a vector store type");
4578
4579 if (!MemScalarTy.isByteSized()) {
4580 // We need to build an integer scalar of the vector bit pattern.
4581 // It's not legal for us to add padding when storing a vector.
4582 unsigned NumBits = MemTy.getSizeInBits();
4583 LLT IntTy = LLT::integer(NumBits);
4584 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4585 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4586
4587 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4588 auto Elt = MIRBuilder.buildExtractVectorElement(
4589 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4590 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4591 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4592 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4593 ? (MemTy.getNumElements() - 1) - I
4594 : I;
4595 auto ShiftAmt = MIRBuilder.buildConstant(
4596 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4597 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4598 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4599 }
4600 auto PtrInfo = MMO.getPointerInfo();
4601 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4602 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4603 StoreMI.eraseFromParent();
4604 return Legalized;
4605 }
4606
4607 // TODO: implement simple scalarization.
4608 return UnableToLegalize;
4609}
4610
4612LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4613 switch (MI.getOpcode()) {
4614 case TargetOpcode::G_LOAD: {
4615 if (TypeIdx != 0)
4616 return UnableToLegalize;
4617 MachineMemOperand &MMO = **MI.memoperands_begin();
4618
4619 // Not sure how to interpret a bitcast of an extending load.
4620 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4621 return UnableToLegalize;
4622
4623 Observer.changingInstr(MI);
4624 bitcastDst(MI, CastTy, 0);
4625 MMO.setType(CastTy);
4626 // The range metadata is no longer valid when reinterpreted as a different
4627 // type.
4628 MMO.clearRanges();
4629 Observer.changedInstr(MI);
4630 return Legalized;
4631 }
4632 case TargetOpcode::G_STORE: {
4633 if (TypeIdx != 0)
4634 return UnableToLegalize;
4635
4636 MachineMemOperand &MMO = **MI.memoperands_begin();
4637
4638 // Not sure how to interpret a bitcast of a truncating store.
4639 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4640 return UnableToLegalize;
4641
4642 Observer.changingInstr(MI);
4643 bitcastSrc(MI, CastTy, 0);
4644 MMO.setType(CastTy);
4645 Observer.changedInstr(MI);
4646 return Legalized;
4647 }
4648 case TargetOpcode::G_SELECT: {
4649 if (TypeIdx != 0)
4650 return UnableToLegalize;
4651
4652 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4653 LLVM_DEBUG(
4654 dbgs() << "bitcast action not implemented for vector select\n");
4655 return UnableToLegalize;
4656 }
4657
4658 Observer.changingInstr(MI);
4659 bitcastSrc(MI, CastTy, 2);
4660 bitcastSrc(MI, CastTy, 3);
4661 bitcastDst(MI, CastTy, 0);
4662 Observer.changedInstr(MI);
4663 return Legalized;
4664 }
4665 case TargetOpcode::G_AND:
4666 case TargetOpcode::G_OR:
4667 case TargetOpcode::G_XOR: {
4668 Observer.changingInstr(MI);
4669 bitcastSrc(MI, CastTy, 1);
4670 bitcastSrc(MI, CastTy, 2);
4671 bitcastDst(MI, CastTy, 0);
4672 Observer.changedInstr(MI);
4673 return Legalized;
4674 }
4675 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4676 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4677 case TargetOpcode::G_INSERT_VECTOR_ELT:
4678 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4679 case TargetOpcode::G_CONCAT_VECTORS:
4680 return bitcastConcatVector(MI, TypeIdx, CastTy);
4681 case TargetOpcode::G_SHUFFLE_VECTOR:
4682 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4683 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4684 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4685 case TargetOpcode::G_INSERT_SUBVECTOR:
4686 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4687 default:
4688 return UnableToLegalize;
4689 }
4690}
4691
4692// Legalize an instruction by changing the opcode in place.
4693void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4695 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4697}
4698
4700LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4701 using namespace TargetOpcode;
4702 switch(MI.getOpcode()) {
4703 default:
4704 return UnableToLegalize;
4705 case TargetOpcode::G_FCONSTANT:
4706 return lowerFConstant(MI);
4707 case TargetOpcode::G_BITCAST:
4708 return lowerBitcast(MI);
4709 case TargetOpcode::G_SREM:
4710 case TargetOpcode::G_UREM: {
4711 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4712 auto Quot =
4713 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4714 {MI.getOperand(1), MI.getOperand(2)});
4715
4716 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4717 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4718 MI.eraseFromParent();
4719 return Legalized;
4720 }
4721 case TargetOpcode::G_SADDO:
4722 case TargetOpcode::G_SSUBO:
4723 return lowerSADDO_SSUBO(MI);
4724 case TargetOpcode::G_SADDE:
4725 return lowerSADDE(MI);
4726 case TargetOpcode::G_SSUBE:
4727 return lowerSSUBE(MI);
4728 case TargetOpcode::G_UMULH:
4729 case TargetOpcode::G_SMULH:
4730 return lowerSMULH_UMULH(MI);
4731 case TargetOpcode::G_SMULO:
4732 case TargetOpcode::G_UMULO: {
4733 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4734 // result.
4735 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4736 LLT Ty = MRI.getType(Res);
4737
4738 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4739 ? TargetOpcode::G_SMULH
4740 : TargetOpcode::G_UMULH;
4741
4742 Observer.changingInstr(MI);
4743 const auto &TII = MIRBuilder.getTII();
4744 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4745 MI.removeOperand(1);
4746 Observer.changedInstr(MI);
4747
4748 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4749 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4750
4751 // Move insert point forward so we can use the Res register if needed.
4752 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4753
4754 // For *signed* multiply, overflow is detected by checking:
4755 // (hi != (lo >> bitwidth-1))
4756 if (Opcode == TargetOpcode::G_SMULH) {
4757 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4758 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4759 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4760 } else {
4761 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4762 }
4763 return Legalized;
4764 }
4765 case TargetOpcode::G_FNEG: {
4766 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4767 LLT TyInt =
4768 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4769 Register CastedSubByReg = SubByReg;
4770
4771 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4772 !SubByRegTy.getScalarType().isInteger()) {
4773 auto BitcastDst = SubByRegTy.changeElementType(
4774 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4775 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4776 }
4777
4778 auto SignMask = MIRBuilder.buildConstant(
4779 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4780
4781 if (ResTy != TyInt) {
4782 Register NewDst =
4783 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4784 MIRBuilder.buildBitcast(Res, NewDst);
4785 } else
4786 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4787
4788 MI.eraseFromParent();
4789 return Legalized;
4790 }
4791 case TargetOpcode::G_FSUB:
4792 case TargetOpcode::G_STRICT_FSUB: {
4793 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4794 LLT Ty = MRI.getType(Res);
4795
4796 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4797 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4798
4799 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4800 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4801 else
4802 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4803
4804 MI.eraseFromParent();
4805 return Legalized;
4806 }
4807 case TargetOpcode::G_FMAD:
4808 return lowerFMad(MI);
4809 case TargetOpcode::G_FFLOOR:
4810 return lowerFFloor(MI);
4811 case TargetOpcode::G_LROUND:
4812 case TargetOpcode::G_LLROUND: {
4813 Register DstReg = MI.getOperand(0).getReg();
4814 Register SrcReg = MI.getOperand(1).getReg();
4815 LLT SrcTy = MRI.getType(SrcReg);
4816 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4817 {SrcReg});
4818 MIRBuilder.buildFPTOSI(DstReg, Round);
4819 MI.eraseFromParent();
4820 return Legalized;
4821 }
4822 case TargetOpcode::G_INTRINSIC_ROUND:
4823 return lowerIntrinsicRound(MI);
4824 case TargetOpcode::G_FRINT: {
4825 // Since round even is the assumed rounding mode for unconstrained FP
4826 // operations, rint and roundeven are the same operation.
4827 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4828 return Legalized;
4829 }
4830 case TargetOpcode::G_INTRINSIC_LRINT:
4831 case TargetOpcode::G_INTRINSIC_LLRINT: {
4832 Register DstReg = MI.getOperand(0).getReg();
4833 Register SrcReg = MI.getOperand(1).getReg();
4834 LLT SrcTy = MRI.getType(SrcReg);
4835 auto Round =
4836 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4837 MIRBuilder.buildFPTOSI(DstReg, Round);
4838 MI.eraseFromParent();
4839 return Legalized;
4840 }
4841 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4842 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4843 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4844 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4845 **MI.memoperands_begin());
4846 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4847 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4848 MI.eraseFromParent();
4849 return Legalized;
4850 }
4851 case TargetOpcode::G_LOAD:
4852 case TargetOpcode::G_SEXTLOAD:
4853 case TargetOpcode::G_ZEXTLOAD:
4854 return lowerLoad(cast<GAnyLoad>(MI));
4855 case TargetOpcode::G_STORE:
4856 return lowerStore(cast<GStore>(MI));
4857 case TargetOpcode::G_CTLZ_ZERO_POISON:
4858 case TargetOpcode::G_CTTZ_ZERO_POISON:
4859 case TargetOpcode::G_CTLZ:
4860 case TargetOpcode::G_CTTZ:
4861 case TargetOpcode::G_CTPOP:
4862 case TargetOpcode::G_CTLS:
4863 return lowerBitCount(MI);
4864 case G_UADDO: {
4865 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4866
4867 Register NewRes = MRI.cloneVirtualRegister(Res);
4868
4869 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4870 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4871
4872 MIRBuilder.buildCopy(Res, NewRes);
4873
4874 MI.eraseFromParent();
4875 return Legalized;
4876 }
4877 case G_UADDE: {
4878 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4879 const LLT CondTy = MRI.getType(CarryOut);
4880 const LLT Ty = MRI.getType(Res);
4881
4882 Register NewRes = MRI.cloneVirtualRegister(Res);
4883
4884 // Initial add of the two operands.
4885 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4886
4887 // Initial check for carry.
4888 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4889
4890 // Add the sum and the carry.
4891 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4892 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4893
4894 // Second check for carry. We can only carry if the initial sum is all 1s
4895 // and the carry is set, resulting in a new sum of 0.
4896 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4897 auto ResEqZero =
4898 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4899 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4900 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4901
4902 MIRBuilder.buildCopy(Res, NewRes);
4903
4904 MI.eraseFromParent();
4905 return Legalized;
4906 }
4907 case G_USUBO: {
4908 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4909
4910 MIRBuilder.buildSub(Res, LHS, RHS);
4911 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4912
4913 MI.eraseFromParent();
4914 return Legalized;
4915 }
4916 case G_USUBE: {
4917 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4918 const LLT CondTy = MRI.getType(BorrowOut);
4919 const LLT Ty = MRI.getType(Res);
4920
4921 // Initial subtract of the two operands.
4922 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4923
4924 // Initial check for borrow.
4925 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4926
4927 // Subtract the borrow from the first subtract.
4928 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4929 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4930
4931 // Second check for borrow. We can only borrow if the initial difference is
4932 // 0 and the borrow is set, resulting in a new difference of all 1s.
4933 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4934 auto TmpResEqZero =
4935 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4936 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4937 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4938
4939 MI.eraseFromParent();
4940 return Legalized;
4941 }
4942 case G_UITOFP:
4943 return lowerUITOFP(MI);
4944 case G_SITOFP:
4945 return lowerSITOFP(MI);
4946 case G_FPTOUI:
4947 return lowerFPTOUI(MI);
4948 case G_FPTOSI:
4949 return lowerFPTOSI(MI);
4950 case G_FPTOUI_SAT:
4951 case G_FPTOSI_SAT:
4952 return lowerFPTOINT_SAT(MI);
4953 case G_FPEXT:
4954 return lowerFPEXT(MI);
4955 case G_FPTRUNC:
4956 return lowerFPTRUNC(MI);
4957 case G_FPOWI:
4958 return lowerFPOWI(MI);
4959 case G_FMODF:
4960 return lowerFMODF(MI);
4961 case G_SMIN:
4962 case G_SMAX:
4963 case G_UMIN:
4964 case G_UMAX:
4965 return lowerMinMax(MI);
4966 case G_SCMP:
4967 case G_UCMP:
4968 return lowerThreewayCompare(MI);
4969 case G_FCOPYSIGN:
4970 return lowerFCopySign(MI);
4971 case G_FMINNUM:
4972 case G_FMAXNUM:
4973 case G_FMINIMUMNUM:
4974 case G_FMAXIMUMNUM:
4975 return lowerFMinNumMaxNum(MI);
4976 case G_FMINIMUM:
4977 case G_FMAXIMUM:
4978 return lowerFMinimumMaximum(MI);
4979 case G_MERGE_VALUES:
4980 return lowerMergeValues(MI);
4981 case G_UNMERGE_VALUES:
4982 return lowerUnmergeValues(MI);
4983 case TargetOpcode::G_SEXT_INREG: {
4984 assert(MI.getOperand(2).isImm() && "Expected immediate");
4985 int64_t SizeInBits = MI.getOperand(2).getImm();
4986
4987 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4988 LLT DstTy = MRI.getType(DstReg);
4989 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4990
4991 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4992 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4993 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4994 MI.eraseFromParent();
4995 return Legalized;
4996 }
4997 case G_EXTRACT_VECTOR_ELT:
4998 case G_INSERT_VECTOR_ELT:
5000 case G_SHUFFLE_VECTOR:
5001 return lowerShuffleVector(MI);
5002 case G_VECTOR_COMPRESS:
5003 return lowerVECTOR_COMPRESS(MI);
5004 case G_DYN_STACKALLOC:
5005 return lowerDynStackAlloc(MI);
5006 case G_INSERT_SUBVECTOR: {
5007 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
5008 MRI.getType(MI.getOperand(2).getReg()).isScalable())
5009 return UnableToLegalize;
5010
5011 // Check that subvector is half size of main vector
5012 Register Vector = MI.getOperand(1).getReg();
5013 Register Subvector = MI.getOperand(2).getReg();
5014 auto InsertionPointImm = MI.getOperand(3).getImm();
5015
5016 LLT VectorTy = MRI.getType(Vector);
5017 LLT DstTy = MRI.getType(Subvector);
5018 // If so, -> concat(subvector, extract(half of vector))
5019 // (Operands can be either way round depending on insertion point
5020 if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
5021 bool InsertInLowHalf = InsertionPointImm == 0;
5022 auto Extract = MIRBuilder.buildExtractSubvector(
5023 DstTy, Vector,
5024 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
5025
5026 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
5027 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
5028
5029 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
5030 {LowHalf, HighHalf});
5031 MI.eraseFromParent();
5032 return Legalized;
5033 }
5034 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
5035 else {
5036 // Extend subvector to same size as vector
5037 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
5038 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
5039
5040 // Calculate mask required for this shuffle
5041 SmallVector<int> Mask;
5042 for (int i = 0; i < VectorTy.getNumElements(); i++) {
5043 // If this index is within bounds, put subvector's index into mask
5044 if (i >= InsertionPointImm &&
5045 i < InsertionPointImm + DstTy.getNumElements())
5046 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
5047 else
5048 Mask.push_back(i);
5049 }
5050
5051 // Build shuffle
5052 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
5053 Mask);
5054 MI.eraseFromParent();
5055 return Legalized;
5056 }
5057 }
5058 case G_EXTRACT_SUBVECTOR: {
5059 Register DstReg = MI.getOperand(0).getReg();
5060 Register SrcReg = MI.getOperand(1).getReg();
5061 uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
5062
5063 LLT SrcTy = MRI.getType(SrcReg);
5064 LLT DstTy = MRI.getType(DstReg);
5065
5066 if (SrcTy.isScalable())
5067 return UnableToLegalize;
5068
5069 if (SrcTy.getScalarType() != DstTy.getScalarType())
5070 return UnableToLegalize;
5071
5072 // extract_subvector = build_vector(extract_element, extract_element, ...)
5073 SmallVector<Register> ExtractedElements;
5074 for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
5075 ExtractedElements.push_back(
5077 .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
5078 ExtractionPointImm + i)
5079 .getReg(0));
5080 }
5081
5082 MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
5083 MI.eraseFromParent();
5084 return Legalized;
5085 }
5086 case G_STACKSAVE:
5087 return lowerStackSave(MI);
5088 case G_STACKRESTORE:
5089 return lowerStackRestore(MI);
5090 case G_EXTRACT:
5091 return lowerExtract(MI);
5092 case G_INSERT:
5093 return lowerInsert(MI);
5094 case G_BSWAP:
5095 return lowerBswap(MI);
5096 case G_BITREVERSE:
5097 return lowerBitreverse(MI);
5098 case G_READ_REGISTER:
5099 case G_WRITE_REGISTER:
5100 return lowerReadWriteRegister(MI);
5101 case G_UADDSAT:
5102 case G_USUBSAT: {
5103 // Try to make a reasonable guess about which lowering strategy to use. The
5104 // target can override this with custom lowering and calling the
5105 // implementation functions.
5106 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5107 if (LI.isLegalOrCustom({G_UMIN, Ty}))
5108 return lowerAddSubSatToMinMax(MI);
5110 }
5111 case G_SADDSAT:
5112 case G_SSUBSAT: {
5113 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5114
5115 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5116 // since it's a shorter expansion. However, we would need to figure out the
5117 // preferred boolean type for the carry out for the query.
5118 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5119 return lowerAddSubSatToMinMax(MI);
5121 }
5122 case G_SSHLSAT:
5123 case G_USHLSAT:
5124 return lowerShlSat(MI);
5125 case G_TRUNC_SSAT_S:
5126 case G_TRUNC_USAT_U:
5127 case G_TRUNC_SSAT_U:
5128 return lowerTruncSat(MI);
5129 case G_ABS:
5130 return lowerAbsToAddXor(MI);
5131 case G_ABDS:
5132 case G_ABDU: {
5133 bool IsSigned = MI.getOpcode() == G_ABDS;
5134 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5135 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5136 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5137 return lowerAbsDiffToMinMax(MI);
5138 }
5139 return lowerAbsDiffToSelect(MI);
5140 }
5141 case G_FABS:
5142 return lowerFAbs(MI);
5143 case G_SELECT:
5144 return lowerSelect(MI);
5145 case G_IS_FPCLASS:
5146 return lowerISFPCLASS(MI);
5147 case G_SDIVREM:
5148 case G_UDIVREM:
5149 return lowerDIVREM(MI);
5150 case G_FSHL:
5151 case G_FSHR:
5152 return lowerFunnelShift(MI);
5153 case G_ROTL:
5154 case G_ROTR:
5155 return lowerRotate(MI);
5156 case G_MEMSET:
5157 case G_MEMCPY:
5158 case G_MEMMOVE:
5159 case G_MEMCPY_INLINE:
5160 case G_MEMSET_INLINE:
5161 return lowerMemCpyFamily(MI);
5162 case G_ZEXT:
5163 case G_SEXT:
5164 case G_ANYEXT:
5165 return lowerEXT(MI);
5166 case G_TRUNC:
5167 return lowerTRUNC(MI);
5169 return lowerVectorReduction(MI);
5170 case G_VAARG:
5171 return lowerVAArg(MI);
5172 case G_ATOMICRMW_SUB: {
5173 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5174 const LLT ValTy = MRI.getType(Val);
5175 MachineMemOperand *MMO = *MI.memoperands_begin();
5176
5177 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5178 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5179 MI.eraseFromParent();
5180 return Legalized;
5181 }
5182 case G_SMULFIX:
5183 case G_UMULFIX:
5184 case G_SMULFIXSAT:
5185 case G_UMULFIXSAT:
5186 return lowerMulfix(MI);
5187 }
5188}
5189
5191 Align MinAlign) const {
5192 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5193 // datalayout for the preferred alignment. Also there should be a target hook
5194 // for this to allow targets to reduce the alignment and ignore the
5195 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5196 // the type.
5197 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5198}
5199
5202 MachinePointerInfo &PtrInfo) {
5203 MachineFunction &MF = MIRBuilder.getMF();
5204 const DataLayout &DL = MIRBuilder.getDataLayout();
5205 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5206
5207 unsigned AddrSpace = DL.getAllocaAddrSpace();
5208 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5209
5210 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5211 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5212}
5213
5215 const SrcOp &Val) {
5216 LLT SrcTy = Val.getLLTTy(MRI);
5217 Align StackTypeAlign =
5218 std::max(getStackTemporaryAlignment(SrcTy),
5220 MachinePointerInfo PtrInfo;
5221 auto StackTemp =
5222 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5223
5224 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5225 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5226}
5227
5229 LLT VecTy) {
5230 LLT IdxTy = B.getMRI()->getType(IdxReg);
5231 unsigned NElts = VecTy.getNumElements();
5232
5233 int64_t IdxVal;
5234 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5235 if (IdxVal < VecTy.getNumElements())
5236 return IdxReg;
5237 // If a constant index would be out of bounds, clamp it as well.
5238 }
5239
5240 if (isPowerOf2_32(NElts)) {
5242 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5243 }
5244
5245 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5246 .getReg(0);
5247}
5248
5250 Register Index) {
5251 LLT EltTy = VecTy.getElementType();
5252
5253 // Calculate the element offset and add it to the pointer.
5254 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5255 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5256 "Converting bits to bytes lost precision");
5257
5258 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5259
5260 // Convert index to the correct size for the address space.
5261 const DataLayout &DL = MIRBuilder.getDataLayout();
5262 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5263 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5264 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5265 if (IdxTy != MRI.getType(Index))
5266 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5267
5268 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5269 MIRBuilder.buildConstant(IdxTy, EltSize));
5270
5271 LLT PtrTy = MRI.getType(VecPtr);
5272 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5273}
5274
5275#ifndef NDEBUG
5276/// Check that all vector operands have same number of elements. Other operands
5277/// should be listed in NonVecOp.
5280 std::initializer_list<unsigned> NonVecOpIndices) {
5281 if (MI.getNumMemOperands() != 0)
5282 return false;
5283
5284 LLT VecTy = MRI.getType(MI.getReg(0));
5285 if (!VecTy.isVector())
5286 return false;
5287 unsigned NumElts = VecTy.getNumElements();
5288
5289 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5290 MachineOperand &Op = MI.getOperand(OpIdx);
5291 if (!Op.isReg()) {
5292 if (!is_contained(NonVecOpIndices, OpIdx))
5293 return false;
5294 continue;
5295 }
5296
5297 LLT Ty = MRI.getType(Op.getReg());
5298 if (!Ty.isVector()) {
5299 if (!is_contained(NonVecOpIndices, OpIdx))
5300 return false;
5301 continue;
5302 }
5303
5304 if (Ty.getNumElements() != NumElts)
5305 return false;
5306 }
5307
5308 return true;
5309}
5310#endif
5311
5312/// Fill \p DstOps with DstOps that have same number of elements combined as
5313/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5314/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5315/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5316static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5317 unsigned NumElts) {
5318 LLT LeftoverTy;
5319 assert(Ty.isVector() && "Expected vector type");
5320 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5321 int NumParts, NumLeftover;
5322 std::tie(NumParts, NumLeftover) =
5323 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5324
5325 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5326 for (int i = 0; i < NumParts; ++i) {
5327 DstOps.push_back(NarrowTy);
5328 }
5329
5330 if (LeftoverTy.isValid()) {
5331 assert(NumLeftover == 1 && "expected exactly one leftover");
5332 DstOps.push_back(LeftoverTy);
5333 }
5334}
5335
5336/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5337/// made from \p Op depending on operand type.
5339 MachineOperand &Op) {
5340 for (unsigned i = 0; i < N; ++i) {
5341 if (Op.isReg())
5342 Ops.push_back(Op.getReg());
5343 else if (Op.isImm())
5344 Ops.push_back(Op.getImm());
5345 else if (Op.isPredicate())
5346 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5347 else
5348 llvm_unreachable("Unsupported type");
5349 }
5350}
5351
5352// Handle splitting vector operations which need to have the same number of
5353// elements in each type index, but each type index may have a different element
5354// type.
5355//
5356// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5357// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5358// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5359//
5360// Also handles some irregular breakdown cases, e.g.
5361// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5362// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5363// s64 = G_SHL s64, s32
5366 GenericMachineInstr &MI, unsigned NumElts,
5367 std::initializer_list<unsigned> NonVecOpIndices) {
5368 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5369 "Non-compatible opcode or not specified non-vector operands");
5370 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5371
5372 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5373 unsigned NumDefs = MI.getNumDefs();
5374
5375 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5376 // Build instructions with DstOps to use instruction found by CSE directly.
5377 // CSE copies found instruction into given vreg when building with vreg dest.
5378 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5379 // Output registers will be taken from created instructions.
5380 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5381 for (unsigned i = 0; i < NumDefs; ++i) {
5382 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5383 }
5384
5385 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5386 // Operands listed in NonVecOpIndices will be used as is without splitting;
5387 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5388 // scalar condition (op 1), immediate in sext_inreg (op 2).
5389 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5390 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5391 ++UseIdx, ++UseNo) {
5392 if (is_contained(NonVecOpIndices, UseIdx)) {
5393 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5394 MI.getOperand(UseIdx));
5395 } else {
5396 SmallVector<Register, 8> SplitPieces;
5397 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5398 MRI);
5399 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5400 }
5401 }
5402
5403 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5404
5405 // Take i-th piece of each input operand split and build sub-vector/scalar
5406 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5407 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5409 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5410 Defs.push_back(OutputOpsPieces[DstNo][i]);
5411
5413 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5414 Uses.push_back(InputOpsPieces[InputNo][i]);
5415
5416 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5417 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5418 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5419 }
5420
5421 // Merge small outputs into MI's output for each def operand.
5422 if (NumLeftovers) {
5423 for (unsigned i = 0; i < NumDefs; ++i)
5424 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5425 } else {
5426 for (unsigned i = 0; i < NumDefs; ++i)
5427 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5428 }
5429
5430 MI.eraseFromParent();
5431 return Legalized;
5432}
5433
5436 unsigned NumElts) {
5437 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5438
5439 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5440 unsigned NumDefs = MI.getNumDefs();
5441
5442 SmallVector<DstOp, 8> OutputOpsPieces;
5443 SmallVector<Register, 8> OutputRegs;
5444 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5445
5446 // Instructions that perform register split will be inserted in basic block
5447 // where register is defined (basic block is in the next operand).
5448 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5449 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5450 UseIdx += 2, ++UseNo) {
5451 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5452 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5453 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5454 MIRBuilder, MRI);
5455 }
5456
5457 // Build PHIs with fewer elements.
5458 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5459 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5460 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5461 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5462 Phi.addDef(
5463 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5464 OutputRegs.push_back(Phi.getReg(0));
5465
5466 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5467 Phi.addUse(InputOpsPieces[j][i]);
5468 Phi.add(MI.getOperand(1 + j * 2 + 1));
5469 }
5470 }
5471
5472 // Set the insert point after the existing PHIs
5473 MachineBasicBlock &MBB = *MI.getParent();
5474 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5475
5476 // Merge small outputs into MI's def.
5477 if (NumLeftovers) {
5478 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5479 } else {
5480 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5481 }
5482
5483 MI.eraseFromParent();
5484 return Legalized;
5485}
5486
5489 unsigned TypeIdx,
5490 LLT NarrowTy) {
5491 const int NumDst = MI.getNumOperands() - 1;
5492 const Register SrcReg = MI.getOperand(NumDst).getReg();
5493 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5494 LLT SrcTy = MRI.getType(SrcReg);
5495
5496 if (TypeIdx != 1 || NarrowTy == DstTy)
5497 return UnableToLegalize;
5498
5499 // Requires compatible types. Otherwise SrcReg should have been defined by
5500 // merge-like instruction that would get artifact combined. Most likely
5501 // instruction that defines SrcReg has to perform more/fewer elements
5502 // legalization compatible with NarrowTy.
5503 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5504 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5505
5506 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5507 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5508 return UnableToLegalize;
5509
5510 // This is most likely DstTy (smaller then register size) packed in SrcTy
5511 // (larger then register size) and since unmerge was not combined it will be
5512 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5513 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5514
5515 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5516 //
5517 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5518 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5519 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5520 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5521 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5522 const int PartsPerUnmerge = NumDst / NumUnmerge;
5523
5524 for (int I = 0; I != NumUnmerge; ++I) {
5525 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5526
5527 for (int J = 0; J != PartsPerUnmerge; ++J)
5528 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5529 MIB.addUse(Unmerge.getReg(I));
5530 }
5531
5532 MI.eraseFromParent();
5533 return Legalized;
5534}
5535
5538 LLT NarrowTy) {
5539 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5540 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5541 // that should have been artifact combined. Most likely instruction that uses
5542 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5543 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5544 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5545 if (NarrowTy == SrcTy)
5546 return UnableToLegalize;
5547
5548 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5549 // is for old mir tests. Since the changes to more/fewer elements it should no
5550 // longer be possible to generate MIR like this when starting from llvm-ir
5551 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5552 if (TypeIdx == 1) {
5553 assert(SrcTy.isVector() && "Expected vector types");
5554 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5555 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5556 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5557 return UnableToLegalize;
5558 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5559 //
5560 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5561 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5562 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5563 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5564 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5565 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5566
5568 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5569 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5570 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5571 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5572 Elts.push_back(Unmerge.getReg(j));
5573 }
5574
5575 SmallVector<Register, 8> NarrowTyElts;
5576 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5577 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5578 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5579 ++i, Offset += NumNarrowTyElts) {
5580 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5581 NarrowTyElts.push_back(
5582 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5583 }
5584
5585 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5586 MI.eraseFromParent();
5587 return Legalized;
5588 }
5589
5590 assert(TypeIdx == 0 && "Bad type index");
5591 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5592 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5593 return UnableToLegalize;
5594
5595 // This is most likely SrcTy (smaller then register size) packed in DstTy
5596 // (larger then register size) and since merge was not combined it will be
5597 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5598 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5599
5600 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5601 //
5602 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5603 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5604 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5605 SmallVector<Register, 8> NarrowTyElts;
5606 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5607 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5608 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5609 for (unsigned i = 0; i < NumParts; ++i) {
5611 for (unsigned j = 0; j < NumElts; ++j)
5612 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5613 NarrowTyElts.push_back(
5614 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5615 }
5616
5617 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5618 MI.eraseFromParent();
5619 return Legalized;
5620}
5621
5624 unsigned TypeIdx,
5625 LLT NarrowVecTy) {
5626 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5627 Register InsertVal;
5628 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5629
5630 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5631 if (IsInsert)
5632 InsertVal = MI.getOperand(2).getReg();
5633
5634 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5635 LLT VecTy = MRI.getType(SrcVec);
5636
5637 // If the index is a constant, we can really break this down as you would
5638 // expect, and index into the target size pieces.
5639 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5640 if (MaybeCst) {
5641 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5642 // Avoid out of bounds indexing the pieces.
5643 if (IdxVal >= VecTy.getNumElements()) {
5644 MIRBuilder.buildUndef(DstReg);
5645 MI.eraseFromParent();
5646 return Legalized;
5647 }
5648
5649 if (!NarrowVecTy.isVector()) {
5650 SmallVector<Register, 8> SplitPieces;
5651 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5652 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5653 if (IsInsert) {
5654 SplitPieces[IdxVal] = InsertVal;
5655 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5656 } else {
5657 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5658 }
5659 } else {
5660 SmallVector<Register, 8> VecParts;
5661 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5662
5663 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5664 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5665 TargetOpcode::G_ANYEXT);
5666
5667 unsigned NewNumElts = NarrowVecTy.getNumElements();
5668
5669 LLT IdxTy = MRI.getType(Idx);
5670 int64_t PartIdx = IdxVal / NewNumElts;
5671 auto NewIdx =
5672 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5673
5674 if (IsInsert) {
5675 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5676
5677 // Use the adjusted index to insert into one of the subvectors.
5678 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5679 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5680 VecParts[PartIdx] = InsertPart.getReg(0);
5681
5682 // Recombine the inserted subvector with the others to reform the result
5683 // vector.
5684 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5685 } else {
5686 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5687 }
5688 }
5689
5690 MI.eraseFromParent();
5691 return Legalized;
5692 }
5693
5694 // With a variable index, we can't perform the operation in a smaller type, so
5695 // we're forced to expand this.
5696 //
5697 // TODO: We could emit a chain of compare/select to figure out which piece to
5698 // index.
5700}
5701
5704 LLT NarrowTy) {
5705 // FIXME: Don't know how to handle secondary types yet.
5706 if (TypeIdx != 0)
5707 return UnableToLegalize;
5708
5709 if (!NarrowTy.isByteSized()) {
5710 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5711 return UnableToLegalize;
5712 }
5713
5714 // This implementation doesn't work for atomics. Give up instead of doing
5715 // something invalid.
5716 if (LdStMI.isAtomic())
5717 return UnableToLegalize;
5718
5719 bool IsLoad = isa<GLoad>(LdStMI);
5720 Register ValReg = LdStMI.getReg(0);
5721 Register AddrReg = LdStMI.getPointerReg();
5722 LLT ValTy = MRI.getType(ValReg);
5723
5724 // FIXME: Do we need a distinct NarrowMemory legalize action?
5725 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5726 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5727 return UnableToLegalize;
5728 }
5729
5730 int NumParts = -1;
5731 int NumLeftover = -1;
5732 LLT LeftoverTy;
5733 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5734 if (IsLoad) {
5735 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5736 } else {
5737 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5738 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5739 NumParts = NarrowRegs.size();
5740 NumLeftover = NarrowLeftoverRegs.size();
5741 }
5742 }
5743
5744 if (NumParts == -1)
5745 return UnableToLegalize;
5746
5747 LLT PtrTy = MRI.getType(AddrReg);
5748 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5749
5750 unsigned TotalSize = ValTy.getSizeInBits();
5751
5752 // Split the load/store into PartTy sized pieces starting at Offset. If this
5753 // is a load, return the new registers in ValRegs. For a store, each elements
5754 // of ValRegs should be PartTy. Returns the next offset that needs to be
5755 // handled.
5756 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5757 auto MMO = LdStMI.getMMO();
5758 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5759 unsigned NumParts, unsigned Offset) -> unsigned {
5760 MachineFunction &MF = MIRBuilder.getMF();
5761 unsigned PartSize = PartTy.getSizeInBits();
5762 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5763 ++Idx) {
5764 unsigned ByteOffset = Offset / 8;
5765 Register NewAddrReg;
5766
5767 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5768 ByteOffset);
5769
5770 MachineMemOperand *NewMMO =
5771 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5772
5773 if (IsLoad) {
5774 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5775 ValRegs.push_back(Dst);
5776 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5777 } else {
5778 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5779 }
5780 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5781 }
5782
5783 return Offset;
5784 };
5785
5786 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5787 unsigned HandledOffset =
5788 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5789
5790 // Handle the rest of the register if this isn't an even type breakdown.
5791 if (LeftoverTy.isValid())
5792 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5793
5794 if (IsLoad) {
5795 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5796 LeftoverTy, NarrowLeftoverRegs);
5797 }
5798
5799 LdStMI.eraseFromParent();
5800 return Legalized;
5801}
5802
5805 LLT NarrowTy) {
5806 using namespace TargetOpcode;
5808 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5809
5810 switch (MI.getOpcode()) {
5811 case G_IMPLICIT_DEF:
5812 case G_TRUNC:
5813 case G_AND:
5814 case G_OR:
5815 case G_XOR:
5816 case G_ADD:
5817 case G_SUB:
5818 case G_MUL:
5819 case G_PTR_ADD:
5820 case G_SMULH:
5821 case G_UMULH:
5822 case G_FADD:
5823 case G_FMUL:
5824 case G_FSUB:
5825 case G_FNEG:
5826 case G_FABS:
5827 case G_FCANONICALIZE:
5828 case G_FDIV:
5829 case G_FREM:
5830 case G_FMA:
5831 case G_FMAD:
5832 case G_FPOW:
5833 case G_FEXP:
5834 case G_FEXP2:
5835 case G_FEXP10:
5836 case G_FLOG:
5837 case G_FLOG2:
5838 case G_FLOG10:
5839 case G_FLDEXP:
5840 case G_FNEARBYINT:
5841 case G_FCEIL:
5842 case G_FFLOOR:
5843 case G_FRINT:
5844 case G_INTRINSIC_LRINT:
5845 case G_INTRINSIC_LLRINT:
5846 case G_INTRINSIC_ROUND:
5847 case G_INTRINSIC_ROUNDEVEN:
5848 case G_LROUND:
5849 case G_LLROUND:
5850 case G_INTRINSIC_TRUNC:
5851 case G_FMODF:
5852 case G_FCOS:
5853 case G_FSIN:
5854 case G_FTAN:
5855 case G_FACOS:
5856 case G_FASIN:
5857 case G_FATAN:
5858 case G_FATAN2:
5859 case G_FCOSH:
5860 case G_FSINH:
5861 case G_FTANH:
5862 case G_FSQRT:
5863 case G_BSWAP:
5864 case G_BITREVERSE:
5865 case G_SDIV:
5866 case G_UDIV:
5867 case G_SREM:
5868 case G_UREM:
5869 case G_SDIVREM:
5870 case G_UDIVREM:
5871 case G_SMIN:
5872 case G_SMAX:
5873 case G_UMIN:
5874 case G_UMAX:
5875 case G_ABS:
5876 case G_FMINNUM:
5877 case G_FMAXNUM:
5878 case G_FMINNUM_IEEE:
5879 case G_FMAXNUM_IEEE:
5880 case G_FMINIMUM:
5881 case G_FMAXIMUM:
5882 case G_FMINIMUMNUM:
5883 case G_FMAXIMUMNUM:
5884 case G_FSHL:
5885 case G_FSHR:
5886 case G_ROTL:
5887 case G_ROTR:
5888 case G_FREEZE:
5889 case G_SADDSAT:
5890 case G_SSUBSAT:
5891 case G_UADDSAT:
5892 case G_USUBSAT:
5893 case G_UMULO:
5894 case G_SMULO:
5895 case G_SHL:
5896 case G_LSHR:
5897 case G_ASHR:
5898 case G_SSHLSAT:
5899 case G_USHLSAT:
5900 case G_CTLZ:
5901 case G_CTLZ_ZERO_POISON:
5902 case G_CTTZ:
5903 case G_CTTZ_ZERO_POISON:
5904 case G_CTPOP:
5905 case G_CTLS:
5906 case G_FCOPYSIGN:
5907 case G_ZEXT:
5908 case G_SEXT:
5909 case G_ANYEXT:
5910 case G_FPEXT:
5911 case G_FPTRUNC:
5912 case G_SITOFP:
5913 case G_UITOFP:
5914 case G_FPTOSI:
5915 case G_FPTOUI:
5916 case G_FPTOSI_SAT:
5917 case G_FPTOUI_SAT:
5918 case G_INTTOPTR:
5919 case G_PTRTOINT:
5920 case G_ADDRSPACE_CAST:
5921 case G_UADDO:
5922 case G_USUBO:
5923 case G_UADDE:
5924 case G_USUBE:
5925 case G_SADDO:
5926 case G_SSUBO:
5927 case G_SADDE:
5928 case G_SSUBE:
5929 case G_STRICT_FADD:
5930 case G_STRICT_FSUB:
5931 case G_STRICT_FMUL:
5932 case G_STRICT_FMA:
5933 case G_STRICT_FLDEXP:
5934 case G_FFREXP:
5935 case G_TRUNC_SSAT_S:
5936 case G_TRUNC_SSAT_U:
5937 case G_TRUNC_USAT_U:
5938 return fewerElementsVectorMultiEltType(GMI, NumElts);
5939 case G_ICMP:
5940 case G_FCMP:
5941 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5942 case G_IS_FPCLASS:
5943 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5944 case G_SELECT:
5945 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5946 return fewerElementsVectorMultiEltType(GMI, NumElts);
5947 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5948 case G_PHI:
5949 return fewerElementsVectorPhi(GMI, NumElts);
5950 case G_UNMERGE_VALUES:
5951 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5952 case G_BUILD_VECTOR:
5953 assert(TypeIdx == 0 && "not a vector type index");
5954 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5955 case G_CONCAT_VECTORS:
5956 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5957 return UnableToLegalize;
5958 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5959 case G_EXTRACT_SUBVECTOR: {
5960 Register DstReg = MI.getOperand(0).getReg();
5961 LLT DstTy = MRI.getType(DstReg);
5962 Register SrcReg = MI.getOperand(1).getReg();
5963 uint64_t InsertionPointImm = MI.getOperand(2).getImm();
5964
5965 // If Dst > NarrowTy bits, then cannot legalize
5966 if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
5967 return UnableToLegalize;
5968
5969 // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
5970 if (!DstTy.getElementCount().isKnownMultipleOf(NarrowTy.getElementCount()))
5971 return UnableToLegalize;
5972
5973 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5974 uint64_t RequiredSubvectorIndex =
5975 InsertionPointImm / NarrowTy.getNumElements();
5976 // If Dst and Narrow are both same size, convert to a copy
5977 if (DstTy.getNumElements() == NarrowTy.getNumElements())
5978 MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
5979 else
5980 MIRBuilder.buildExtractSubvector(
5981 DstReg, Unmerge.getReg(RequiredSubvectorIndex),
5982 InsertionPointImm % NarrowTy.getNumElements());
5983
5984 MI.eraseFromParent();
5985 return Legalized;
5986 }
5987 case G_EXTRACT_VECTOR_ELT:
5988 case G_INSERT_VECTOR_ELT:
5989 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5990 case G_LOAD:
5991 case G_STORE:
5992 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5993 case G_SEXT_INREG:
5994 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5996 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5997 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5998 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5999 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
6000 case G_SHUFFLE_VECTOR:
6001 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
6002 case G_FPOWI:
6003 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
6004 case G_BITCAST:
6005 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
6006 case G_INTRINSIC_FPTRUNC_ROUND:
6007 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
6008 default:
6009 return UnableToLegalize;
6010 }
6011}
6012
6015 LLT NarrowTy) {
6016 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
6017 "Not a bitcast operation");
6018
6019 if (TypeIdx != 0)
6020 return UnableToLegalize;
6021
6022 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
6023
6024 unsigned NewElemCount =
6025 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
6026 SmallVector<Register> SrcVRegs, BitcastVRegs;
6027 if (NewElemCount == 1) {
6028 LLT SrcNarrowTy = SrcTy.getElementType();
6029
6030 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
6031 getUnmergeResults(SrcVRegs, *Unmerge);
6032 } else {
6033 LLT SrcNarrowTy =
6035
6036 // Split the Src and Dst Reg into smaller registers
6037 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
6038 return UnableToLegalize;
6039 }
6040
6041 // Build new smaller bitcast instructions
6042 // Not supporting Leftover types for now but will have to
6043 for (Register Reg : SrcVRegs)
6044 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
6045
6046 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
6047 MI.eraseFromParent();
6048 return Legalized;
6049}
6050
6052 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6053 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
6054 if (TypeIdx != 0)
6055 return UnableToLegalize;
6056
6057 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
6058 MI.getFirst3RegLLTs();
6059 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
6060 // The shuffle should be canonicalized by now.
6061 if (DstTy != Src1Ty)
6062 return UnableToLegalize;
6063 if (DstTy != Src2Ty)
6064 return UnableToLegalize;
6065
6066 if (!isPowerOf2_32(DstTy.getNumElements()))
6067 return UnableToLegalize;
6068
6069 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
6070 // Further legalization attempts will be needed to do split further.
6071 NarrowTy =
6072 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
6073 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
6074
6075 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
6076 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
6077 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
6078 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
6079 SplitSrc2Regs[1]};
6080
6081 Register Hi, Lo;
6082
6083 // If Lo or Hi uses elements from at most two of the four input vectors, then
6084 // express it as a vector shuffle of those two inputs. Otherwise extract the
6085 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
6087 for (unsigned High = 0; High < 2; ++High) {
6088 Register &Output = High ? Hi : Lo;
6089
6090 // Build a shuffle mask for the output, discovering on the fly which
6091 // input vectors to use as shuffle operands (recorded in InputUsed).
6092 // If building a suitable shuffle vector proves too hard, then bail
6093 // out with useBuildVector set.
6094 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
6095 unsigned FirstMaskIdx = High * NewElts;
6096 bool UseBuildVector = false;
6097 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6098 // The mask element. This indexes into the input.
6099 int Idx = Mask[FirstMaskIdx + MaskOffset];
6100
6101 // The input vector this mask element indexes into.
6102 unsigned Input = (unsigned)Idx / NewElts;
6103
6104 if (Input >= std::size(Inputs)) {
6105 // The mask element does not index into any input vector.
6106 Ops.push_back(-1);
6107 continue;
6108 }
6109
6110 // Turn the index into an offset from the start of the input vector.
6111 Idx -= Input * NewElts;
6112
6113 // Find or create a shuffle vector operand to hold this input.
6114 unsigned OpNo;
6115 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
6116 if (InputUsed[OpNo] == Input) {
6117 // This input vector is already an operand.
6118 break;
6119 } else if (InputUsed[OpNo] == -1U) {
6120 // Create a new operand for this input vector.
6121 InputUsed[OpNo] = Input;
6122 break;
6123 }
6124 }
6125
6126 if (OpNo >= std::size(InputUsed)) {
6127 // More than two input vectors used! Give up on trying to create a
6128 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
6129 UseBuildVector = true;
6130 break;
6131 }
6132
6133 // Add the mask index for the new shuffle vector.
6134 Ops.push_back(Idx + OpNo * NewElts);
6135 }
6136
6137 if (UseBuildVector) {
6138 LLT EltTy = NarrowTy.getElementType();
6140
6141 // Extract the input elements by hand.
6142 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6143 // The mask element. This indexes into the input.
6144 int Idx = Mask[FirstMaskIdx + MaskOffset];
6145
6146 // The input vector this mask element indexes into.
6147 unsigned Input = (unsigned)Idx / NewElts;
6148
6149 if (Input >= std::size(Inputs)) {
6150 // The mask element is "undef" or indexes off the end of the input.
6151 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6152 continue;
6153 }
6154
6155 // Turn the index into an offset from the start of the input vector.
6156 Idx -= Input * NewElts;
6157
6158 // Extract the vector element by hand.
6159 SVOps.push_back(MIRBuilder
6160 .buildExtractVectorElement(
6161 EltTy, Inputs[Input],
6162 MIRBuilder.buildConstant(LLT::integer(32), Idx))
6163 .getReg(0));
6164 }
6165
6166 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6167 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6168 } else if (InputUsed[0] == -1U) {
6169 // No input vectors were used! The result is undefined.
6170 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6171 } else if (NewElts == 1) {
6172 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6173 } else {
6174 Register Op0 = Inputs[InputUsed[0]];
6175 // If only one input was used, use an undefined vector for the other.
6176 Register Op1 = InputUsed[1] == -1U
6177 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6178 : Inputs[InputUsed[1]];
6179 // At least one input vector was used. Create a new shuffle vector.
6180 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6181 }
6182
6183 Ops.clear();
6184 }
6185
6186 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6187 MI.eraseFromParent();
6188 return Legalized;
6189}
6190
6192 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6193 auto &RdxMI = cast<GVecReduce>(MI);
6194
6195 if (TypeIdx != 1)
6196 return UnableToLegalize;
6197
6198 // The semantics of the normal non-sequential reductions allow us to freely
6199 // re-associate the operation.
6200 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6201
6202 if (NarrowTy.isVector() &&
6203 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6204 return UnableToLegalize;
6205
6206 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6207 SmallVector<Register> SplitSrcs;
6208 // If NarrowTy is a scalar then we're being asked to scalarize.
6209 const unsigned NumParts =
6210 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6211 : SrcTy.getNumElements();
6212
6213 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6214 if (NarrowTy.isScalar()) {
6215 if (DstTy != NarrowTy)
6216 return UnableToLegalize; // FIXME: handle implicit extensions.
6217
6218 if (isPowerOf2_32(NumParts)) {
6219 // Generate a tree of scalar operations to reduce the critical path.
6220 SmallVector<Register> PartialResults;
6221 unsigned NumPartsLeft = NumParts;
6222 while (NumPartsLeft > 1) {
6223 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6224 PartialResults.emplace_back(
6226 .buildInstr(ScalarOpc, {NarrowTy},
6227 {SplitSrcs[Idx], SplitSrcs[Idx + 1]},
6228 MI.getFlags())
6229 .getReg(0));
6230 }
6231 SplitSrcs = PartialResults;
6232 PartialResults.clear();
6233 NumPartsLeft = SplitSrcs.size();
6234 }
6235 assert(SplitSrcs.size() == 1);
6236 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6237 MI.eraseFromParent();
6238 return Legalized;
6239 }
6240 // If we can't generate a tree, then just do sequential operations.
6241 Register Acc = SplitSrcs[0];
6242 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6243 Acc = MIRBuilder
6244 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]},
6245 MI.getFlags())
6246 .getReg(0);
6247 MIRBuilder.buildCopy(DstReg, Acc);
6248 MI.eraseFromParent();
6249 return Legalized;
6250 }
6251 SmallVector<Register> PartialReductions;
6252 for (unsigned Part = 0; Part < NumParts; ++Part) {
6253 PartialReductions.push_back(MIRBuilder
6254 .buildInstr(RdxMI.getOpcode(), {DstTy},
6255 {SplitSrcs[Part]},
6256 MI.getFlags())
6257 .getReg(0));
6258 }
6259
6260 // If the types involved are powers of 2, we can generate intermediate vector
6261 // ops, before generating a final reduction operation.
6262 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6263 isPowerOf2_32(NarrowTy.getNumElements())) {
6264 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6265 }
6266
6267 Register Acc = PartialReductions[0];
6268 for (unsigned Part = 1; Part < NumParts; ++Part) {
6269 if (Part == NumParts - 1) {
6270 MIRBuilder.buildInstr(ScalarOpc, {DstReg}, {Acc, PartialReductions[Part]},
6271 MI.getFlags());
6272 } else {
6273 Acc = MIRBuilder
6274 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]},
6275 MI.getFlags())
6276 .getReg(0);
6277 }
6278 }
6279 MI.eraseFromParent();
6280 return Legalized;
6281}
6282
6285 unsigned int TypeIdx,
6286 LLT NarrowTy) {
6287 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6288 MI.getFirst3RegLLTs();
6289 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6290 DstTy != NarrowTy)
6291 return UnableToLegalize;
6292
6293 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6294 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6295 "Unexpected vecreduce opcode");
6296 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6297 ? TargetOpcode::G_FADD
6298 : TargetOpcode::G_FMUL;
6299
6300 SmallVector<Register> SplitSrcs;
6301 unsigned NumParts = SrcTy.getNumElements();
6302 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6303 Register Acc = ScalarReg;
6304 for (unsigned i = 0; i < NumParts; i++)
6305 Acc = MIRBuilder
6306 .buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]},
6307 MI.getFlags())
6308 .getReg(0);
6309
6310 MIRBuilder.buildCopy(DstReg, Acc);
6311 MI.eraseFromParent();
6312 return Legalized;
6313}
6314
6316LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6317 LLT SrcTy, LLT NarrowTy,
6318 unsigned ScalarOpc) {
6319 SmallVector<Register> SplitSrcs;
6320 // Split the sources into NarrowTy size pieces.
6321 extractParts(SrcReg, NarrowTy,
6322 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6323 MIRBuilder, MRI);
6324 // We're going to do a tree reduction using vector operations until we have
6325 // one NarrowTy size value left.
6326 while (SplitSrcs.size() > 1) {
6327 SmallVector<Register> PartialRdxs;
6328 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6329 Register LHS = SplitSrcs[Idx];
6330 Register RHS = SplitSrcs[Idx + 1];
6331 // Create the intermediate vector op.
6332 Register Res =
6334 .buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}, MI.getFlags())
6335 .getReg(0);
6336 PartialRdxs.push_back(Res);
6337 }
6338 SplitSrcs = std::move(PartialRdxs);
6339 }
6340 // Finally generate the requested NarrowTy based reduction.
6341 Observer.changingInstr(MI);
6342 MI.getOperand(1).setReg(SplitSrcs[0]);
6343 Observer.changedInstr(MI);
6344 return Legalized;
6345}
6346
6349 const LLT HalfTy, const LLT AmtTy) {
6350
6351 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6352 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6353 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6354
6355 if (Amt.isZero()) {
6356 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6357 MI.eraseFromParent();
6358 return Legalized;
6359 }
6360
6361 LLT NVT = HalfTy;
6362 unsigned NVTBits = HalfTy.getSizeInBits();
6363 unsigned VTBits = 2 * NVTBits;
6364
6365 SrcOp Lo(Register(0)), Hi(Register(0));
6366 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6367 if (Amt.ugt(VTBits)) {
6368 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6369 } else if (Amt.ugt(NVTBits)) {
6370 Lo = MIRBuilder.buildConstant(NVT, 0);
6371 Hi = MIRBuilder.buildShl(NVT, InL,
6372 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6373 } else if (Amt == NVTBits) {
6374 Lo = MIRBuilder.buildConstant(NVT, 0);
6375 Hi = InL;
6376 } else {
6377 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6378 auto OrLHS =
6379 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6380 auto OrRHS = MIRBuilder.buildLShr(
6381 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6382 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6383 }
6384 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6385 if (Amt.ugt(VTBits)) {
6386 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6387 } else if (Amt.ugt(NVTBits)) {
6388 Lo = MIRBuilder.buildLShr(NVT, InH,
6389 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6390 Hi = MIRBuilder.buildConstant(NVT, 0);
6391 } else if (Amt == NVTBits) {
6392 Lo = InH;
6393 Hi = MIRBuilder.buildConstant(NVT, 0);
6394 } else {
6395 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6396
6397 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6398 auto OrRHS = MIRBuilder.buildShl(
6399 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6400
6401 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6402 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6403 }
6404 } else {
6405 if (Amt.ugt(VTBits)) {
6406 Hi = Lo = MIRBuilder.buildAShr(
6407 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6408 } else if (Amt.ugt(NVTBits)) {
6409 Lo = MIRBuilder.buildAShr(NVT, InH,
6410 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6411 Hi = MIRBuilder.buildAShr(NVT, InH,
6412 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6413 } else if (Amt == NVTBits) {
6414 Lo = InH;
6415 Hi = MIRBuilder.buildAShr(NVT, InH,
6416 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6417 } else {
6418 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6419
6420 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6421 auto OrRHS = MIRBuilder.buildShl(
6422 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6423
6424 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6425 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6426 }
6427 }
6428
6429 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6430 MI.eraseFromParent();
6431
6432 return Legalized;
6433}
6434
6437 LLT RequestedTy) {
6438 if (TypeIdx == 1) {
6439 Observer.changingInstr(MI);
6440 narrowScalarSrc(MI, RequestedTy, 2);
6441 Observer.changedInstr(MI);
6442 return Legalized;
6443 }
6444
6445 Register DstReg = MI.getOperand(0).getReg();
6446 LLT DstTy = MRI.getType(DstReg);
6447 if (DstTy.isVector())
6448 return UnableToLegalize;
6449
6450 Register Amt = MI.getOperand(2).getReg();
6451 LLT ShiftAmtTy = MRI.getType(Amt);
6452 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6453 if (DstEltSize % 2 != 0)
6454 return UnableToLegalize;
6455
6456 // Check if we should use multi-way splitting instead of recursive binary
6457 // splitting.
6458 //
6459 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6460 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6461 // and dependency chains created by usual binary splitting approach
6462 // (128->64->32).
6463 //
6464 // The >= 8 parts threshold ensures we only use this optimization when binary
6465 // splitting would require multiple recursive passes, avoiding overhead for
6466 // simple 2-way splits where binary approach is sufficient.
6467 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6468 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6469 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6470 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6471 // steps).
6472 if (NumParts >= 8)
6473 return narrowScalarShiftMultiway(MI, RequestedTy);
6474 }
6475
6476 // Fall back to binary splitting:
6477 // Ignore the input type. We can only go to exactly half the size of the
6478 // input. If that isn't small enough, the resulting pieces will be further
6479 // legalized.
6480 const unsigned NewBitSize = DstEltSize / 2;
6481 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6482 const LLT CondTy = LLT::integer(1);
6483
6484 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6485 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6486 ShiftAmtTy);
6487 }
6488
6489 // TODO: Expand with known bits.
6490
6491 // Handle the fully general expansion by an unknown amount.
6492 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6493
6494 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6495 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6496 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6497
6498 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6499 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6500
6501 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6502 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6503 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6504
6505 Register ResultRegs[2];
6506 switch (MI.getOpcode()) {
6507 case TargetOpcode::G_SHL: {
6508 // Short: ShAmt < NewBitSize
6509 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6510
6511 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6512 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6513 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6514
6515 // Long: ShAmt >= NewBitSize
6516 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6517 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6518
6519 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6520 auto Hi = MIRBuilder.buildSelect(
6521 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6522
6523 ResultRegs[0] = Lo.getReg(0);
6524 ResultRegs[1] = Hi.getReg(0);
6525 break;
6526 }
6527 case TargetOpcode::G_LSHR:
6528 case TargetOpcode::G_ASHR: {
6529 // Short: ShAmt < NewBitSize
6530 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6531
6532 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6533 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6534 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6535
6536 // Long: ShAmt >= NewBitSize
6538 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6539 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6540 } else {
6541 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6542 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6543 }
6544 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6545 {InH, AmtExcess}); // Lo from Hi part.
6546
6547 auto Lo = MIRBuilder.buildSelect(
6548 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6549
6550 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6551
6552 ResultRegs[0] = Lo.getReg(0);
6553 ResultRegs[1] = Hi.getReg(0);
6554 break;
6555 }
6556 default:
6557 llvm_unreachable("not a shift");
6558 }
6559
6560 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6561 MI.eraseFromParent();
6562 return Legalized;
6563}
6564
6566 unsigned PartIdx,
6567 unsigned NumParts,
6568 ArrayRef<Register> SrcParts,
6569 const ShiftParams &Params,
6570 LLT TargetTy, LLT ShiftAmtTy) {
6571 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6572 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6573 assert(WordShiftConst && BitShiftConst && "Expected constants");
6574
6575 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6576 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6577 const bool NeedsInterWordShift = ShiftBits != 0;
6578
6579 switch (Opcode) {
6580 case TargetOpcode::G_SHL: {
6581 // Data moves from lower indices to higher indices
6582 // If this part would come from a source beyond our range, it's zero
6583 if (PartIdx < ShiftWords)
6584 return Params.Zero;
6585
6586 unsigned SrcIdx = PartIdx - ShiftWords;
6587 if (!NeedsInterWordShift)
6588 return SrcParts[SrcIdx];
6589
6590 // Combine shifted main part with carry from previous part
6591 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6592 if (SrcIdx > 0) {
6593 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6594 Params.InvBitShift);
6595 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6596 }
6597 return Hi.getReg(0);
6598 }
6599
6600 case TargetOpcode::G_LSHR: {
6601 unsigned SrcIdx = PartIdx + ShiftWords;
6602 if (SrcIdx >= NumParts)
6603 return Params.Zero;
6604 if (!NeedsInterWordShift)
6605 return SrcParts[SrcIdx];
6606
6607 // Combine shifted main part with carry from next part
6608 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6609 if (SrcIdx + 1 < NumParts) {
6610 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6611 Params.InvBitShift);
6612 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6613 }
6614 return Lo.getReg(0);
6615 }
6616
6617 case TargetOpcode::G_ASHR: {
6618 // Like LSHR but preserves sign bit
6619 unsigned SrcIdx = PartIdx + ShiftWords;
6620 if (SrcIdx >= NumParts)
6621 return Params.SignBit;
6622 if (!NeedsInterWordShift)
6623 return SrcParts[SrcIdx];
6624
6625 // Only the original MSB part uses arithmetic shift to preserve sign. All
6626 // other parts use logical shift since they're just moving data bits.
6627 auto Lo =
6628 (SrcIdx == NumParts - 1)
6629 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6630 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6631 Register HiSrc =
6632 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6633 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6634 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6635 }
6636
6637 default:
6638 llvm_unreachable("not a shift");
6639 }
6640}
6641
6643 Register MainOperand,
6644 Register ShiftAmt,
6645 LLT TargetTy,
6646 Register CarryOperand) {
6647 // This helper generates a single output part for variable shifts by combining
6648 // the main operand (shifted by BitShift) with carry bits from an adjacent
6649 // part.
6650
6651 // For G_ASHR, individual parts don't have their own sign bit, only the
6652 // complete value does. So we use LSHR for the main operand shift in ASHR
6653 // context.
6654 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6655 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6656 : Opcode;
6657
6658 // Perform the primary shift on the main operand
6659 Register MainShifted =
6660 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6661 .getReg(0);
6662
6663 // No carry operand available
6664 if (!CarryOperand.isValid())
6665 return MainShifted;
6666
6667 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6668 // so carry bits aren't needed.
6669 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6670 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6671 LLT BoolTy = LLT::integer(1);
6672 auto IsZeroBitShift =
6673 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6674
6675 // Extract bits from the adjacent part that will "carry over" into this part.
6676 // The carry direction is opposite to the main shift direction, so we can
6677 // align the two shifted values before combining them with OR.
6678
6679 // Determine the carry shift opcode (opposite direction)
6680 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6681 : TargetOpcode::G_SHL;
6682
6683 // Calculate inverse shift amount: BitWidth - ShiftAmt
6684 auto TargetBitsConst =
6685 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6686 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6687
6688 // Shift the carry operand
6689 Register CarryBits =
6691 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6692 .getReg(0);
6693
6694 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6695 // TargetBits which would be poison for the individual carry shift operation).
6696 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6697 Register SafeCarryBits =
6698 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6699 .getReg(0);
6700
6701 // Combine the main shifted part with the carry bits
6702 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6703}
6704
6707 const APInt &Amt,
6708 LLT TargetTy,
6709 LLT ShiftAmtTy) {
6710 // Any wide shift can be decomposed into WordShift + BitShift components.
6711 // When shift amount is known constant, directly compute the decomposition
6712 // values and generate constant registers.
6713 Register DstReg = MI.getOperand(0).getReg();
6714 Register SrcReg = MI.getOperand(1).getReg();
6715 LLT DstTy = MRI.getType(DstReg);
6716
6717 const unsigned DstBits = DstTy.getScalarSizeInBits();
6718 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6719 const unsigned NumParts = DstBits / TargetBits;
6720
6721 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6722
6723 // When the shift amount is known at compile time, we just calculate which
6724 // source parts contribute to each output part.
6725
6726 SmallVector<Register, 8> SrcParts;
6727 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6728
6729 if (Amt.isZero()) {
6730 // No shift needed, just copy
6731 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6732 MI.eraseFromParent();
6733 return Legalized;
6734 }
6735
6736 ShiftParams Params;
6737 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6738 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6739
6740 // Generate constants and values needed by all shift types
6741 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6742 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6743 Params.InvBitShift =
6744 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6745 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6746
6747 // For ASHR, we need the sign-extended value to fill shifted-out positions
6748 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6749 Params.SignBit =
6751 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6752 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6753 .getReg(0);
6754
6756 for (unsigned I = 0; I < NumParts; ++I)
6757 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6758 Params, TargetTy, ShiftAmtTy);
6759
6760 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6761 MI.eraseFromParent();
6762 return Legalized;
6763}
6764
6767 Register DstReg = MI.getOperand(0).getReg();
6768 Register SrcReg = MI.getOperand(1).getReg();
6769 Register AmtReg = MI.getOperand(2).getReg();
6770 LLT DstTy = MRI.getType(DstReg);
6771 LLT ShiftAmtTy = MRI.getType(AmtReg);
6772
6773 const unsigned DstBits = DstTy.getScalarSizeInBits();
6774 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6775 const unsigned NumParts = DstBits / TargetBits;
6776
6777 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6778 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6779
6780 // If the shift amount is known at compile time, we can use direct indexing
6781 // instead of generating select chains in the general case.
6782 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6783 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6784 ShiftAmtTy);
6785
6786 // For runtime-variable shift amounts, we must generate a more complex
6787 // sequence that handles all possible shift values using select chains.
6788
6789 // Split the input into target-sized pieces
6790 SmallVector<Register, 8> SrcParts;
6791 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6792
6793 // Shifting by zero should be a no-op.
6794 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6795 LLT BoolTy = LLT::integer(1);
6796 auto IsZeroShift =
6797 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6798
6799 // Any wide shift can be decomposed into two components:
6800 // 1. WordShift: number of complete target-sized words to shift
6801 // 2. BitShift: number of bits to shift within each word
6802 //
6803 // Example: 128-bit >> 50 with 32-bit target:
6804 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6805 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6806 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6807 auto TargetBitsLog2Const =
6808 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6809 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6810
6811 Register WordShift =
6812 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6813 Register BitShift =
6814 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6815
6816 // Fill values:
6817 // - SHL/LSHR: fill with zeros
6818 // - ASHR: fill with sign-extended MSB
6819 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6820
6821 Register FillValue;
6822 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6823 auto TargetBitsMinusOneConst =
6824 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6825 FillValue = MIRBuilder
6826 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6827 TargetBitsMinusOneConst)
6828 .getReg(0);
6829 } else {
6830 FillValue = ZeroReg;
6831 }
6832
6834
6835 // For each output part, generate a select chain that chooses the correct
6836 // result based on the runtime WordShift value. This handles all possible
6837 // word shift amounts by pre-calculating what each would produce.
6838 for (unsigned I = 0; I < NumParts; ++I) {
6839 // Initialize with appropriate default value for this shift type
6840 Register InBoundsResult = FillValue;
6841
6842 // clang-format off
6843 // Build a branchless select chain by pre-computing results for all possible
6844 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6845 //
6846 // K=0: select(WordShift==0, result0, FillValue)
6847 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6848 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6849 // clang-format on
6850 for (unsigned K = 0; K < NumParts; ++K) {
6851 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6852 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6853 WordShift, WordShiftKConst);
6854
6855 // Calculate source indices for this word shift
6856 //
6857 // For 4-part 128-bit value with K=1 word shift:
6858 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6859 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6860 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6861 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6862 int MainSrcIdx;
6863 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6864
6865 switch (MI.getOpcode()) {
6866 case TargetOpcode::G_SHL:
6867 MainSrcIdx = (int)I - (int)K;
6868 CarrySrcIdx = MainSrcIdx - 1;
6869 break;
6870 case TargetOpcode::G_LSHR:
6871 case TargetOpcode::G_ASHR:
6872 MainSrcIdx = (int)I + (int)K;
6873 CarrySrcIdx = MainSrcIdx + 1;
6874 break;
6875 default:
6876 llvm_unreachable("Not a shift");
6877 }
6878
6879 // Check bounds and build the result for this word shift
6880 Register ResultForK;
6881 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6882 Register MainOp = SrcParts[MainSrcIdx];
6883 Register CarryOp;
6884
6885 // Determine carry operand with bounds checking
6886 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6887 CarryOp = SrcParts[CarrySrcIdx];
6888 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6889 CarrySrcIdx >= (int)NumParts)
6890 CarryOp = FillValue; // Use sign extension
6891
6892 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6893 TargetTy, CarryOp);
6894 } else {
6895 // Out of bounds - use fill value for this k
6896 ResultForK = FillValue;
6897 }
6898
6899 // Select this result if WordShift equals k
6900 InBoundsResult =
6902 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6903 .getReg(0);
6904 }
6905
6906 // Handle zero-shift special case: if shift is 0, use original input
6907 DstParts[I] =
6909 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6910 .getReg(0);
6911 }
6912
6913 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6914 MI.eraseFromParent();
6915 return Legalized;
6916}
6917
6920 LLT MoreTy) {
6921 assert(TypeIdx == 0 && "Expecting only Idx 0");
6922
6923 Observer.changingInstr(MI);
6924 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6925 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6926 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6927 moreElementsVectorSrc(MI, MoreTy, I);
6928 }
6929
6930 MachineBasicBlock &MBB = *MI.getParent();
6931 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6932 moreElementsVectorDst(MI, MoreTy, 0);
6933 Observer.changedInstr(MI);
6934 return Legalized;
6935}
6936
6937MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6938 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6939 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6940
6941 switch (Opcode) {
6942 default:
6944 "getNeutralElementForVecReduce called with invalid opcode!");
6945 case TargetOpcode::G_VECREDUCE_ADD:
6946 case TargetOpcode::G_VECREDUCE_OR:
6947 case TargetOpcode::G_VECREDUCE_XOR:
6948 case TargetOpcode::G_VECREDUCE_UMAX:
6949 return MIRBuilder.buildConstant(Ty, 0);
6950 case TargetOpcode::G_VECREDUCE_MUL:
6951 return MIRBuilder.buildConstant(Ty, 1);
6952 case TargetOpcode::G_VECREDUCE_AND:
6953 case TargetOpcode::G_VECREDUCE_UMIN:
6955 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6956 case TargetOpcode::G_VECREDUCE_SMAX:
6958 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6959 case TargetOpcode::G_VECREDUCE_SMIN:
6961 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6962 case TargetOpcode::G_VECREDUCE_FADD:
6963 return MIRBuilder.buildFConstant(Ty, -0.0);
6964 case TargetOpcode::G_VECREDUCE_FMUL:
6965 return MIRBuilder.buildFConstant(Ty, 1.0);
6966 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6967 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6968 assert(false && "getNeutralElementForVecReduce unimplemented for "
6969 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6970 }
6971 llvm_unreachable("switch expected to return!");
6972}
6973
6976 LLT MoreTy) {
6977 unsigned Opc = MI.getOpcode();
6978 switch (Opc) {
6979 case TargetOpcode::G_IMPLICIT_DEF:
6980 case TargetOpcode::G_LOAD: {
6981 if (TypeIdx != 0)
6982 return UnableToLegalize;
6983 Observer.changingInstr(MI);
6984 moreElementsVectorDst(MI, MoreTy, 0);
6985 Observer.changedInstr(MI);
6986 return Legalized;
6987 }
6988 case TargetOpcode::G_STORE:
6989 if (TypeIdx != 0)
6990 return UnableToLegalize;
6991 Observer.changingInstr(MI);
6992 moreElementsVectorSrc(MI, MoreTy, 0);
6993 Observer.changedInstr(MI);
6994 return Legalized;
6995 case TargetOpcode::G_AND:
6996 case TargetOpcode::G_OR:
6997 case TargetOpcode::G_XOR:
6998 case TargetOpcode::G_ADD:
6999 case TargetOpcode::G_SUB:
7000 case TargetOpcode::G_MUL:
7001 case TargetOpcode::G_FADD:
7002 case TargetOpcode::G_FSUB:
7003 case TargetOpcode::G_FMUL:
7004 case TargetOpcode::G_FDIV:
7005 case TargetOpcode::G_FCOPYSIGN:
7006 case TargetOpcode::G_UADDSAT:
7007 case TargetOpcode::G_USUBSAT:
7008 case TargetOpcode::G_SADDSAT:
7009 case TargetOpcode::G_SSUBSAT:
7010 case TargetOpcode::G_SMIN:
7011 case TargetOpcode::G_SMAX:
7012 case TargetOpcode::G_UMIN:
7013 case TargetOpcode::G_UMAX:
7014 case TargetOpcode::G_FMINNUM:
7015 case TargetOpcode::G_FMAXNUM:
7016 case TargetOpcode::G_FMINNUM_IEEE:
7017 case TargetOpcode::G_FMAXNUM_IEEE:
7018 case TargetOpcode::G_FMINIMUM:
7019 case TargetOpcode::G_FMAXIMUM:
7020 case TargetOpcode::G_FMINIMUMNUM:
7021 case TargetOpcode::G_FMAXIMUMNUM:
7022 case TargetOpcode::G_STRICT_FADD:
7023 case TargetOpcode::G_STRICT_FSUB:
7024 case TargetOpcode::G_STRICT_FMUL: {
7025 Observer.changingInstr(MI);
7026 moreElementsVectorSrc(MI, MoreTy, 1);
7027 moreElementsVectorSrc(MI, MoreTy, 2);
7028 moreElementsVectorDst(MI, MoreTy, 0);
7029 Observer.changedInstr(MI);
7030 return Legalized;
7031 }
7032 case TargetOpcode::G_SHL:
7033 case TargetOpcode::G_ASHR:
7034 case TargetOpcode::G_LSHR: {
7035 Observer.changingInstr(MI);
7036 moreElementsVectorSrc(MI, MoreTy, 1);
7037 // The shift operand may have a different scalar type from the source and
7038 // destination operands.
7039 LLT ShiftMoreTy = MoreTy.changeElementType(
7040 MRI.getType(MI.getOperand(2).getReg()).getElementType());
7041 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
7042 moreElementsVectorDst(MI, MoreTy, 0);
7043 Observer.changedInstr(MI);
7044 return Legalized;
7045 }
7046 case TargetOpcode::G_FMA:
7047 case TargetOpcode::G_STRICT_FMA:
7048 case TargetOpcode::G_FSHR:
7049 case TargetOpcode::G_FSHL: {
7050 Observer.changingInstr(MI);
7051 moreElementsVectorSrc(MI, MoreTy, 1);
7052 moreElementsVectorSrc(MI, MoreTy, 2);
7053 moreElementsVectorSrc(MI, MoreTy, 3);
7054 moreElementsVectorDst(MI, MoreTy, 0);
7055 Observer.changedInstr(MI);
7056 return Legalized;
7057 }
7058 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
7059 case TargetOpcode::G_EXTRACT:
7060 if (TypeIdx != 1)
7061 return UnableToLegalize;
7062 Observer.changingInstr(MI);
7063 moreElementsVectorSrc(MI, MoreTy, 1);
7064 Observer.changedInstr(MI);
7065 return Legalized;
7066 case TargetOpcode::G_INSERT:
7067 case TargetOpcode::G_INSERT_VECTOR_ELT:
7068 case TargetOpcode::G_FREEZE:
7069 case TargetOpcode::G_FNEG:
7070 case TargetOpcode::G_FABS:
7071 case TargetOpcode::G_FSQRT:
7072 case TargetOpcode::G_FCEIL:
7073 case TargetOpcode::G_FFLOOR:
7074 case TargetOpcode::G_FNEARBYINT:
7075 case TargetOpcode::G_FRINT:
7076 case TargetOpcode::G_INTRINSIC_ROUND:
7077 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
7078 case TargetOpcode::G_INTRINSIC_TRUNC:
7079 case TargetOpcode::G_BITREVERSE:
7080 case TargetOpcode::G_BSWAP:
7081 case TargetOpcode::G_FCANONICALIZE:
7082 case TargetOpcode::G_SEXT_INREG:
7083 case TargetOpcode::G_ABS:
7084 case TargetOpcode::G_CTLZ:
7085 case TargetOpcode::G_CTPOP:
7086 if (TypeIdx != 0)
7087 return UnableToLegalize;
7088 Observer.changingInstr(MI);
7089 moreElementsVectorSrc(MI, MoreTy, 1);
7090 moreElementsVectorDst(MI, MoreTy, 0);
7091 Observer.changedInstr(MI);
7092 return Legalized;
7093 case TargetOpcode::G_SELECT: {
7094 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
7095 if (TypeIdx == 1) {
7096 if (!CondTy.isScalar() ||
7097 DstTy.getElementCount() != MoreTy.getElementCount())
7098 return UnableToLegalize;
7099
7100 // This is turning a scalar select of vectors into a vector
7101 // select. Broadcast the select condition.
7102 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
7103 Observer.changingInstr(MI);
7104 MI.getOperand(1).setReg(ShufSplat.getReg(0));
7105 Observer.changedInstr(MI);
7106 return Legalized;
7107 }
7108
7109 if (CondTy.isVector())
7110 return UnableToLegalize;
7111
7112 Observer.changingInstr(MI);
7113 moreElementsVectorSrc(MI, MoreTy, 2);
7114 moreElementsVectorSrc(MI, MoreTy, 3);
7115 moreElementsVectorDst(MI, MoreTy, 0);
7116 Observer.changedInstr(MI);
7117 return Legalized;
7118 }
7119 case TargetOpcode::G_UNMERGE_VALUES:
7120 return UnableToLegalize;
7121 case TargetOpcode::G_PHI:
7122 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
7123 case TargetOpcode::G_SHUFFLE_VECTOR:
7124 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
7125 case TargetOpcode::G_BUILD_VECTOR: {
7127 for (auto Op : MI.uses()) {
7128 Elts.push_back(Op.getReg());
7129 }
7130
7131 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
7132 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
7133 }
7134
7135 MIRBuilder.buildDeleteTrailingVectorElements(
7136 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
7137 MI.eraseFromParent();
7138 return Legalized;
7139 }
7140 case TargetOpcode::G_SEXT:
7141 case TargetOpcode::G_ZEXT:
7142 case TargetOpcode::G_ANYEXT:
7143 case TargetOpcode::G_TRUNC:
7144 case TargetOpcode::G_FPTRUNC:
7145 case TargetOpcode::G_FPEXT:
7146 case TargetOpcode::G_FPTOSI:
7147 case TargetOpcode::G_FPTOUI:
7148 case TargetOpcode::G_FPTOSI_SAT:
7149 case TargetOpcode::G_FPTOUI_SAT:
7150 case TargetOpcode::G_SITOFP:
7151 case TargetOpcode::G_UITOFP:
7152 case TargetOpcode::G_TRUNC_SSAT_S:
7153 case TargetOpcode::G_TRUNC_SSAT_U:
7154 case TargetOpcode::G_TRUNC_USAT_U: {
7155 Observer.changingInstr(MI);
7156 LLT SrcExtTy;
7157 LLT DstExtTy;
7158 if (TypeIdx == 0) {
7159 DstExtTy = MoreTy;
7160 SrcExtTy = MoreTy.changeElementType(
7161 MRI.getType(MI.getOperand(1).getReg()).getElementType());
7162 } else {
7163 DstExtTy = MoreTy.changeElementType(
7164 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7165 SrcExtTy = MoreTy;
7166 }
7167 moreElementsVectorSrc(MI, SrcExtTy, 1);
7168 moreElementsVectorDst(MI, DstExtTy, 0);
7169 Observer.changedInstr(MI);
7170 return Legalized;
7171 }
7172 case TargetOpcode::G_ICMP:
7173 case TargetOpcode::G_FCMP: {
7174 if (TypeIdx != 1)
7175 return UnableToLegalize;
7176
7177 Observer.changingInstr(MI);
7178 moreElementsVectorSrc(MI, MoreTy, 2);
7179 moreElementsVectorSrc(MI, MoreTy, 3);
7180 LLT CondTy = MoreTy.changeVectorElementType(
7181 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7182 moreElementsVectorDst(MI, CondTy, 0);
7183 Observer.changedInstr(MI);
7184 return Legalized;
7185 }
7186 case TargetOpcode::G_BITCAST: {
7187 if (TypeIdx != 0)
7188 return UnableToLegalize;
7189
7190 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7191 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7192
7193 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7194 if (coefficient % DstTy.getNumElements() != 0)
7195 return UnableToLegalize;
7196
7197 coefficient = coefficient / DstTy.getNumElements();
7198
7199 LLT NewTy = SrcTy.changeElementCount(
7200 ElementCount::get(coefficient, MoreTy.isScalable()));
7201 Observer.changingInstr(MI);
7202 moreElementsVectorSrc(MI, NewTy, 1);
7203 moreElementsVectorDst(MI, MoreTy, 0);
7204 Observer.changedInstr(MI);
7205 return Legalized;
7206 }
7207 case TargetOpcode::G_VECREDUCE_FADD:
7208 case TargetOpcode::G_VECREDUCE_FMUL:
7209 case TargetOpcode::G_VECREDUCE_ADD:
7210 case TargetOpcode::G_VECREDUCE_MUL:
7211 case TargetOpcode::G_VECREDUCE_AND:
7212 case TargetOpcode::G_VECREDUCE_OR:
7213 case TargetOpcode::G_VECREDUCE_XOR:
7214 case TargetOpcode::G_VECREDUCE_SMAX:
7215 case TargetOpcode::G_VECREDUCE_SMIN:
7216 case TargetOpcode::G_VECREDUCE_UMAX:
7217 case TargetOpcode::G_VECREDUCE_UMIN: {
7218 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7219 MachineOperand &MO = MI.getOperand(1);
7220 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7221 auto NeutralElement = getNeutralElementForVecReduce(
7222 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7223
7224 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7225 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7226 i != e; i++) {
7227 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7228 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7229 NeutralElement, Idx);
7230 }
7231
7232 Observer.changingInstr(MI);
7233 MO.setReg(NewVec.getReg(0));
7234 Observer.changedInstr(MI);
7235 return Legalized;
7236 }
7237
7238 default:
7239 return UnableToLegalize;
7240 }
7241}
7242
7245 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7246 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7247 unsigned MaskNumElts = Mask.size();
7248 unsigned SrcNumElts = SrcTy.getNumElements();
7249 LLT DestEltTy = DstTy.getElementType();
7250
7251 if (MaskNumElts == SrcNumElts)
7252 return Legalized;
7253
7254 if (MaskNumElts < SrcNumElts) {
7255 // Extend mask to match new destination vector size with
7256 // undef values.
7257 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7258 llvm::copy(Mask, NewMask.begin());
7259
7260 moreElementsVectorDst(MI, SrcTy, 0);
7261 MIRBuilder.setInstrAndDebugLoc(MI);
7262 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7263 MI.getOperand(1).getReg(),
7264 MI.getOperand(2).getReg(), NewMask);
7265 MI.eraseFromParent();
7266
7267 return Legalized;
7268 }
7269
7270 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7271 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7272 LLT PaddedTy =
7273 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7274
7275 // Create new source vectors by concatenating the initial
7276 // source vectors with undefined vectors of the same size.
7277 auto Undef = MIRBuilder.buildUndef(SrcTy);
7278 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7279 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7280 MOps1[0] = MI.getOperand(1).getReg();
7281 MOps2[0] = MI.getOperand(2).getReg();
7282
7283 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7284 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7285
7286 // Readjust mask for new input vector length.
7287 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7288 for (unsigned I = 0; I != MaskNumElts; ++I) {
7289 int Idx = Mask[I];
7290 if (Idx >= static_cast<int>(SrcNumElts))
7291 Idx += PaddedMaskNumElts - SrcNumElts;
7292 MappedOps[I] = Idx;
7293 }
7294
7295 // If we got more elements than required, extract subvector.
7296 if (MaskNumElts != PaddedMaskNumElts) {
7297 auto Shuffle =
7298 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7299
7300 SmallVector<Register, 16> Elts(MaskNumElts);
7301 for (unsigned I = 0; I < MaskNumElts; ++I) {
7302 Elts[I] =
7303 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7304 .getReg(0);
7305 }
7306 MIRBuilder.buildBuildVector(DstReg, Elts);
7307 } else {
7308 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7309 }
7310
7311 MI.eraseFromParent();
7313}
7314
7317 unsigned int TypeIdx, LLT MoreTy) {
7318 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7319 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7320 unsigned NumElts = DstTy.getNumElements();
7321 unsigned WidenNumElts = MoreTy.getNumElements();
7322
7323 if (DstTy.isVector() && Src1Ty.isVector() &&
7324 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7326 }
7327
7328 if (TypeIdx != 0)
7329 return UnableToLegalize;
7330
7331 // Expect a canonicalized shuffle.
7332 if (DstTy != Src1Ty || DstTy != Src2Ty)
7333 return UnableToLegalize;
7334
7335 moreElementsVectorSrc(MI, MoreTy, 1);
7336 moreElementsVectorSrc(MI, MoreTy, 2);
7337
7338 // Adjust mask based on new input vector length.
7339 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7340 for (unsigned I = 0; I != NumElts; ++I) {
7341 int Idx = Mask[I];
7342 if (Idx < static_cast<int>(NumElts))
7343 NewMask[I] = Idx;
7344 else
7345 NewMask[I] = Idx - NumElts + WidenNumElts;
7346 }
7347 moreElementsVectorDst(MI, MoreTy, 0);
7348 MIRBuilder.setInstrAndDebugLoc(MI);
7349 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7350 MI.getOperand(1).getReg(),
7351 MI.getOperand(2).getReg(), NewMask);
7352 MI.eraseFromParent();
7353 return Legalized;
7354}
7355
7356void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7357 ArrayRef<Register> Src1Regs,
7358 ArrayRef<Register> Src2Regs,
7359 LLT NarrowTy) {
7361 unsigned SrcParts = Src1Regs.size();
7362 unsigned DstParts = DstRegs.size();
7363
7364 unsigned DstIdx = 0; // Low bits of the result.
7365 Register FactorSum =
7366 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7367 DstRegs[DstIdx] = FactorSum;
7368
7369 Register CarrySumPrevDstIdx;
7371
7372 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7373 // Collect high parts of muls from previous DstIdx.
7374 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7375 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7376 MachineInstrBuilder Umulh =
7377 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7378 Factors.push_back(Umulh.getReg(0));
7379 }
7380 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7381 // the low Src1 part, so multiply-add selectors can use it as the first
7382 // accumulated cross product.
7383 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7384 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7385 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7386 unsigned i = RevI - 1;
7388 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7389 Factors.push_back(Mul.getReg(0));
7390 }
7391 // Add CarrySum from additions calculated for previous DstIdx.
7392 if (DstIdx != 1) {
7393 Factors.push_back(CarrySumPrevDstIdx);
7394 }
7395
7396 Register CarrySum;
7397 // Add all factors and accumulate all carries into CarrySum.
7398 if (DstIdx != DstParts - 1) {
7399 MachineInstrBuilder Uaddo =
7400 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7401 FactorSum = Uaddo.getReg(0);
7402 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7403 for (unsigned i = 2; i < Factors.size(); ++i) {
7404 MachineInstrBuilder Uaddo =
7405 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7406 FactorSum = Uaddo.getReg(0);
7407 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7408 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7409 }
7410 } else {
7411 // Since value for the next index is not calculated, neither is CarrySum.
7412 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7413 for (unsigned i = 2; i < Factors.size(); ++i)
7414 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7415 }
7416
7417 CarrySumPrevDstIdx = CarrySum;
7418 DstRegs[DstIdx] = FactorSum;
7419 Factors.clear();
7420 }
7421}
7422
7425 LLT NarrowTy) {
7426 if (TypeIdx != 0)
7427 return UnableToLegalize;
7428
7429 Register DstReg = MI.getOperand(0).getReg();
7430 LLT DstType = MRI.getType(DstReg);
7431 // FIXME: add support for vector types
7432 if (DstType.isVector())
7433 return UnableToLegalize;
7434
7435 unsigned Opcode = MI.getOpcode();
7436 unsigned OpO, OpE, OpF;
7437 switch (Opcode) {
7438 case TargetOpcode::G_SADDO:
7439 case TargetOpcode::G_SADDE:
7440 case TargetOpcode::G_UADDO:
7441 case TargetOpcode::G_UADDE:
7442 case TargetOpcode::G_ADD:
7443 OpO = TargetOpcode::G_UADDO;
7444 OpE = TargetOpcode::G_UADDE;
7445 OpF = TargetOpcode::G_UADDE;
7446 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7447 OpF = TargetOpcode::G_SADDE;
7448 break;
7449 case TargetOpcode::G_SSUBO:
7450 case TargetOpcode::G_SSUBE:
7451 case TargetOpcode::G_USUBO:
7452 case TargetOpcode::G_USUBE:
7453 case TargetOpcode::G_SUB:
7454 OpO = TargetOpcode::G_USUBO;
7455 OpE = TargetOpcode::G_USUBE;
7456 OpF = TargetOpcode::G_USUBE;
7457 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7458 OpF = TargetOpcode::G_SSUBE;
7459 break;
7460 default:
7461 llvm_unreachable("Unexpected add/sub opcode!");
7462 }
7463
7464 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7465 unsigned NumDefs = MI.getNumExplicitDefs();
7466 Register Src1 = MI.getOperand(NumDefs).getReg();
7467 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7468 Register CarryDst, CarryIn;
7469 if (NumDefs == 2)
7470 CarryDst = MI.getOperand(1).getReg();
7471 if (MI.getNumOperands() == NumDefs + 3)
7472 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7473
7474 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7475 LLT LeftoverTy, DummyTy;
7476 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7477 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7478 MIRBuilder, MRI);
7479 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7480 MRI);
7481
7482 int NarrowParts = Src1Regs.size();
7483 Src1Regs.append(Src1Left);
7484 Src2Regs.append(Src2Left);
7485 DstRegs.reserve(Src1Regs.size());
7486
7487 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7488 Register DstReg =
7489 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7490 Register CarryOut;
7491 // Forward the final carry-out to the destination register
7492 if (i == e - 1 && CarryDst)
7493 CarryOut = CarryDst;
7494 else
7495 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7496
7497 if (!CarryIn) {
7498 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7499 {Src1Regs[i], Src2Regs[i]});
7500 } else if (i == e - 1) {
7501 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7502 {Src1Regs[i], Src2Regs[i], CarryIn});
7503 } else {
7504 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7505 {Src1Regs[i], Src2Regs[i], CarryIn});
7506 }
7507
7508 DstRegs.push_back(DstReg);
7509 CarryIn = CarryOut;
7510 }
7511 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7512 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7513 ArrayRef(DstRegs).drop_front(NarrowParts));
7514
7515 MI.eraseFromParent();
7516 return Legalized;
7517}
7518
7521 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7522
7523 LLT Ty = MRI.getType(DstReg);
7524 if (Ty.isVector())
7525 return UnableToLegalize;
7526
7527 unsigned Size = Ty.getSizeInBits();
7528 unsigned NarrowSize = NarrowTy.getSizeInBits();
7529 if (Size % NarrowSize != 0)
7530 return UnableToLegalize;
7531
7532 unsigned NumParts = Size / NarrowSize;
7533 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH ||
7534 MI.getOpcode() == TargetOpcode::G_SMULH;
7535 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7536
7537 SmallVector<Register, 2> Src1Parts, Src2Parts;
7538 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7539 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7540 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7541 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7542
7543 // Take only high half of registers if this is high mul.
7544 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7545
7546 if (MI.getOpcode() == TargetOpcode::G_SMULH) {
7547 Register UnsignedHigh = MRI.createGenericVirtualRegister(Ty);
7548 MIRBuilder.buildMergeLikeInstr(UnsignedHigh, DstRegs);
7549
7550 // Extract the sign from the highest narrow part of each operand.
7551 auto ShiftAmt = MIRBuilder.buildConstant(NarrowTy, NarrowSize - 1);
7552
7553 auto SignAPart =
7554 MIRBuilder.buildAShr(NarrowTy, Src1Parts.back(), ShiftAmt.getReg(0));
7555 auto SignBPart =
7556 MIRBuilder.buildAShr(NarrowTy, Src2Parts.back(), ShiftAmt.getReg(0));
7557
7558 // Replicate the sign parts to construct full-width sign masks.
7559 SmallVector<Register, 2> SignAParts(NumParts, SignAPart.getReg(0));
7560 SmallVector<Register, 2> SignBParts(NumParts, SignBPart.getReg(0));
7561
7562 auto SignA = MIRBuilder.buildMergeLikeInstr(Ty, SignAParts);
7563 auto SignB = MIRBuilder.buildMergeLikeInstr(Ty, SignBParts);
7564
7565 // Ca = (Src1 < 0) ? Src2 : 0
7566 // Cb = (Src2 < 0) ? Src1 : 0
7567 auto Ca = MIRBuilder.buildAnd(Ty, SignA, Src2);
7568 auto Cb = MIRBuilder.buildAnd(Ty, SignB, Src1);
7569
7570 // SignedHigh = UnsignedHigh - Ca - Cb
7571 auto Tmp = MIRBuilder.buildSub(Ty, UnsignedHigh, Ca);
7572 MIRBuilder.buildSub(DstReg, Tmp, Cb);
7573 } else {
7574 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7575 }
7576
7577 MI.eraseFromParent();
7578 return Legalized;
7579}
7580
7583 LLT NarrowTy) {
7584 if (TypeIdx != 0)
7585 return UnableToLegalize;
7586
7587 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7588
7589 Register Src = MI.getOperand(1).getReg();
7590 LLT SrcTy = MRI.getType(Src);
7591
7592 // If all finite floats fit into the narrowed integer type, we can just swap
7593 // out the result type. Only IEEE half qualifies: bfloat is also 16 bits wide
7594 // but has float's exponent range. LLT::float16() is equivalent to
7595 // LLT::scalar(16) on targets without extended LLTs.
7596 if (SrcTy.getScalarType() != LLT::float16() ||
7597 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7598 return UnableToLegalize;
7599
7600 Observer.changingInstr(MI);
7601 narrowScalarDst(MI, NarrowTy, 0,
7602 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7603 Observer.changedInstr(MI);
7604 return Legalized;
7605}
7606
7609 LLT NarrowTy) {
7610 if (TypeIdx != 1)
7611 return UnableToLegalize;
7612
7613 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7614
7615 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7616 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7617 // NarrowSize.
7618 if (SizeOp1 % NarrowSize != 0)
7619 return UnableToLegalize;
7620 int NumParts = SizeOp1 / NarrowSize;
7621
7622 SmallVector<Register, 2> SrcRegs, DstRegs;
7623 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7624 MIRBuilder, MRI);
7625
7626 Register OpReg = MI.getOperand(0).getReg();
7627 uint64_t OpStart = MI.getOperand(2).getImm();
7628 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7629 for (int i = 0; i < NumParts; ++i) {
7630 unsigned SrcStart = i * NarrowSize;
7631
7632 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7633 // No part of the extract uses this subregister, ignore it.
7634 continue;
7635 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7636 // The entire subregister is extracted, forward the value.
7637 DstRegs.push_back(SrcRegs[i]);
7638 continue;
7639 }
7640
7641 // OpSegStart is where this destination segment would start in OpReg if it
7642 // extended infinitely in both directions.
7643 int64_t ExtractOffset;
7644 uint64_t SegSize;
7645 if (OpStart < SrcStart) {
7646 ExtractOffset = 0;
7647 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7648 } else {
7649 ExtractOffset = OpStart - SrcStart;
7650 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7651 }
7652
7653 Register SegReg = SrcRegs[i];
7654 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7655 // A genuine extract is needed.
7656 SegReg = MRI.createGenericVirtualRegister(LLT::integer(SegSize));
7657 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7658 }
7659
7660 DstRegs.push_back(SegReg);
7661 }
7662
7663 Register DstReg = MI.getOperand(0).getReg();
7664 if (MRI.getType(DstReg).isVector())
7665 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7666 else if (DstRegs.size() > 1)
7667 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7668 else
7669 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7670 MI.eraseFromParent();
7671 return Legalized;
7672}
7673
7676 LLT NarrowTy) {
7677 // FIXME: Don't know how to handle secondary types yet.
7678 if (TypeIdx != 0)
7679 return UnableToLegalize;
7680
7681 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7682 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7683 LLT LeftoverTy;
7684 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7685 LeftoverRegs, MIRBuilder, MRI);
7686
7687 SrcRegs.append(LeftoverRegs);
7688
7689 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7690 Register OpReg = MI.getOperand(2).getReg();
7691 uint64_t OpStart = MI.getOperand(3).getImm();
7692 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7693 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7694 unsigned DstStart = I * NarrowSize;
7695
7696 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7697 // The entire subregister is defined by this insert, forward the new
7698 // value.
7699 DstRegs.push_back(OpReg);
7700 continue;
7701 }
7702
7703 Register SrcReg = SrcRegs[I];
7704 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7705 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7706 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7707 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7708 }
7709
7710 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7711 // No part of the insert affects this subregister, forward the original.
7712 DstRegs.push_back(SrcReg);
7713 continue;
7714 }
7715
7716 // OpSegStart is where this destination segment would start in OpReg if it
7717 // extended infinitely in both directions.
7718 int64_t ExtractOffset, InsertOffset;
7719 uint64_t SegSize;
7720 if (OpStart < DstStart) {
7721 InsertOffset = 0;
7722 ExtractOffset = DstStart - OpStart;
7723 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7724 } else {
7725 InsertOffset = OpStart - DstStart;
7726 ExtractOffset = 0;
7727 SegSize = std::min(NarrowSize - InsertOffset, OpSize);
7728 }
7729
7730 Register SegReg = OpReg;
7731 if (ExtractOffset != 0 || SegSize != OpSize) {
7732 // A genuine extract is needed.
7733 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7734 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7735 }
7736
7737 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7738 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7739 DstRegs.push_back(DstReg);
7740 }
7741
7742 uint64_t WideSize = DstRegs.size() * NarrowSize;
7743 Register DstReg = MI.getOperand(0).getReg();
7744 if (WideSize > RegTy.getSizeInBits()) {
7745 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7746 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7747 MIRBuilder.buildTrunc(DstReg, MergeReg);
7748 } else
7749 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7750
7751 MI.eraseFromParent();
7752 return Legalized;
7753}
7754
7757 LLT NarrowTy) {
7758 Register DstReg = MI.getOperand(0).getReg();
7759 LLT DstTy = MRI.getType(DstReg);
7760
7761 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7762
7763 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7764 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7765 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7766 LLT LeftoverTy;
7767 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7768 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7769 return UnableToLegalize;
7770
7771 LLT Unused;
7772 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7773 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7774 llvm_unreachable("inconsistent extractParts result");
7775
7776 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7777 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7778 {Src0Regs[I], Src1Regs[I]});
7779 DstRegs.push_back(Inst.getReg(0));
7780 }
7781
7782 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7783 auto Inst = MIRBuilder.buildInstr(
7784 MI.getOpcode(),
7785 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7786 DstLeftoverRegs.push_back(Inst.getReg(0));
7787 }
7788
7789 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7790 LeftoverTy, DstLeftoverRegs);
7791
7792 MI.eraseFromParent();
7793 return Legalized;
7794}
7795
7798 LLT NarrowTy) {
7799 if (TypeIdx != 0)
7800 return UnableToLegalize;
7801
7802 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7803
7804 LLT DstTy = MRI.getType(DstReg);
7805 if (DstTy.isVector())
7806 return UnableToLegalize;
7807
7809 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7810 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7811 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7812
7813 MI.eraseFromParent();
7814 return Legalized;
7815}
7816
7819 LLT NarrowTy) {
7820 if (TypeIdx != 0)
7821 return UnableToLegalize;
7822
7823 Register CondReg = MI.getOperand(1).getReg();
7824 LLT CondTy = MRI.getType(CondReg);
7825 if (CondTy.isVector()) // TODO: Handle vselect
7826 return UnableToLegalize;
7827
7828 Register DstReg = MI.getOperand(0).getReg();
7829 LLT DstTy = MRI.getType(DstReg);
7830
7831 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7832 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7833 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7834 LLT LeftoverTy;
7835 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7836 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7837 return UnableToLegalize;
7838
7839 LLT Unused;
7840 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7841 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7842 llvm_unreachable("inconsistent extractParts result");
7843
7844 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7845 auto Select = MIRBuilder.buildSelect(NarrowTy,
7846 CondReg, Src1Regs[I], Src2Regs[I]);
7847 DstRegs.push_back(Select.getReg(0));
7848 }
7849
7850 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7851 auto Select = MIRBuilder.buildSelect(
7852 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7853 DstLeftoverRegs.push_back(Select.getReg(0));
7854 }
7855
7856 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7857 LeftoverTy, DstLeftoverRegs);
7858
7859 MI.eraseFromParent();
7860 return Legalized;
7861}
7862
7865 LLT NarrowTy) {
7866 if (TypeIdx != 1)
7867 return UnableToLegalize;
7868
7869 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7870 unsigned NarrowSize = NarrowTy.getSizeInBits();
7871
7872 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7873 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7874
7876 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7877 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7878 auto C_0 = B.buildConstant(NarrowTy, 0);
7879 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7880 UnmergeSrc.getReg(1), C_0);
7881 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7882 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7883 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7884 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7885 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7886 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7887
7888 MI.eraseFromParent();
7889 return Legalized;
7890 }
7891
7892 return UnableToLegalize;
7893}
7894
7897 LLT NarrowTy) {
7898 if (TypeIdx != 1)
7899 return UnableToLegalize;
7900
7901 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7902 unsigned NarrowSize = NarrowTy.getSizeInBits();
7903
7904 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7905 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7906
7908 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7909 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7910 auto C_0 = B.buildConstant(NarrowTy, 0);
7911 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7912 UnmergeSrc.getReg(0), C_0);
7913 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7914 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7915 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7916 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7917 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7918 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7919
7920 MI.eraseFromParent();
7921 return Legalized;
7922 }
7923
7924 return UnableToLegalize;
7925}
7926
7929 LLT NarrowTy) {
7930 if (TypeIdx != 1)
7931 return UnableToLegalize;
7932
7933 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7934 unsigned NarrowSize = NarrowTy.getSizeInBits();
7935
7936 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7937 return UnableToLegalize;
7938
7940
7941 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7942 Register Lo = UnmergeSrc.getReg(0);
7943 Register Hi = UnmergeSrc.getReg(1);
7944
7945 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7946 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7947
7948 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7949
7950 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7951 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7952 // Otherwise the leading zeros represent additional sign bits of the original
7953 // value.
7954 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7955 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7956
7957 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7958 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7959 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7960
7961 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7962
7963 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7964
7965 MI.eraseFromParent();
7966 return Legalized;
7967}
7968
7971 LLT NarrowTy) {
7972 if (TypeIdx != 1)
7973 return UnableToLegalize;
7974
7975 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7976 unsigned NarrowSize = NarrowTy.getSizeInBits();
7977
7978 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7979 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
7980
7981 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
7982 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
7983 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
7984
7985 MI.eraseFromParent();
7986 return Legalized;
7987 }
7988
7989 return UnableToLegalize;
7990}
7991
7994 LLT NarrowTy) {
7995 if (TypeIdx != 1)
7996 return UnableToLegalize;
7997
7999 Register ExpReg = MI.getOperand(2).getReg();
8000 LLT ExpTy = MRI.getType(ExpReg);
8001
8002 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
8003
8004 // Clamp the exponent to the range of the target type.
8005 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
8006 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
8007 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
8008 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
8009
8010 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
8011 Observer.changingInstr(MI);
8012 MI.getOperand(2).setReg(Trunc.getReg(0));
8013 Observer.changedInstr(MI);
8014 return Legalized;
8015}
8016
8019 unsigned Opc = MI.getOpcode();
8020 const auto &TII = MIRBuilder.getTII();
8021 auto isSupported = [this](const LegalityQuery &Q) {
8022 auto QAction = LI.getAction(Q).Action;
8023 return QAction == Legal || QAction == Libcall || QAction == Custom;
8024 };
8025 switch (Opc) {
8026 default:
8027 return UnableToLegalize;
8028 case TargetOpcode::G_CTLZ_ZERO_POISON: {
8029 // This trivially expands to CTLZ.
8030 Observer.changingInstr(MI);
8031 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
8032 Observer.changedInstr(MI);
8033 return Legalized;
8034 }
8035 case TargetOpcode::G_CTLZ: {
8036 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8037 unsigned Len = SrcTy.getScalarSizeInBits();
8038
8039 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
8040 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
8041 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
8042 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
8043 auto ICmp = MIRBuilder.buildICmp(
8044 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
8045 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
8046 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
8047 MI.eraseFromParent();
8048 return Legalized;
8049 }
8050 // for now, we do this:
8051 // NewLen = NextPowerOf2(Len);
8052 // x = x | (x >> 1);
8053 // x = x | (x >> 2);
8054 // ...
8055 // x = x | (x >>16);
8056 // x = x | (x >>32); // for 64-bit input
8057 // Upto NewLen/2
8058 // return Len - popcount(x);
8059 //
8060 // Ref: "Hacker's Delight" by Henry Warren
8061 Register Op = SrcReg;
8062 unsigned NewLen = PowerOf2Ceil(Len);
8063 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
8064 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
8065 auto MIBOp = MIRBuilder.buildOr(
8066 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
8067 Op = MIBOp.getReg(0);
8068 }
8069 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
8070 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
8071 MIBPop);
8072 MI.eraseFromParent();
8073 return Legalized;
8074 }
8075 case TargetOpcode::G_CTTZ_ZERO_POISON: {
8076 // This trivially expands to CTTZ.
8077 Observer.changingInstr(MI);
8078 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
8079 Observer.changedInstr(MI);
8080 return Legalized;
8081 }
8082 case TargetOpcode::G_CTTZ: {
8083 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8084
8085 unsigned Len = SrcTy.getScalarSizeInBits();
8086 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
8087 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
8088 // zero.
8089 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
8090 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
8091 auto ICmp = MIRBuilder.buildICmp(
8092 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
8093 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
8094 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
8095 MI.eraseFromParent();
8096 return Legalized;
8097 }
8098 // for now, we use: { return popcount(~x & (x - 1)); }
8099 // unless the target has ctlz but not ctpop, in which case we use:
8100 // { return 32 - nlz(~x & (x-1)); }
8101 // Ref: "Hacker's Delight" by Henry Warren
8102 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
8103 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
8104 auto MIBTmp = MIRBuilder.buildAnd(
8105 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
8106 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
8107 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
8108 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
8109 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
8110 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
8111 MI.eraseFromParent();
8112 return Legalized;
8113 }
8114 Observer.changingInstr(MI);
8115 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
8116 MI.getOperand(1).setReg(MIBTmp.getReg(0));
8117 Observer.changedInstr(MI);
8118 return Legalized;
8119 }
8120 case TargetOpcode::G_CTPOP: {
8121 Register SrcReg = MI.getOperand(1).getReg();
8122 LLT Ty = MRI.getType(SrcReg);
8123 unsigned Size = Ty.getScalarSizeInBits();
8125
8126 // Bail out on irregular type lengths.
8127 if (Size > 128 || Size % 8 != 0)
8128 return UnableToLegalize;
8129
8130 // Count set bits in blocks of 2 bits. Default approach would be
8131 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
8132 // We use following formula instead:
8133 // B2Count = val - { (val >> 1) & 0x55555555 }
8134 // since it gives same result in blocks of 2 with one instruction less.
8135 auto C_1 = B.buildConstant(Ty, 1);
8136 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
8137 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
8138 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
8139 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
8140 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
8141
8142 // In order to get count in blocks of 4 add values from adjacent block of 2.
8143 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
8144 auto C_2 = B.buildConstant(Ty, 2);
8145 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
8146 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
8147 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
8148 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
8149 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
8150 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
8151
8152 // For count in blocks of 8 bits we don't have to mask high 4 bits before
8153 // addition since count value sits in range {0,...,8} and 4 bits are enough
8154 // to hold such binary values. After addition high 4 bits still hold count
8155 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
8156 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
8157 auto C_4 = B.buildConstant(Ty, 4);
8158 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
8159 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
8160 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
8161 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
8162 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
8163
8164 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
8165
8166 // Avoid the multiply when shift-add is cheaper.
8167 if (Size == 16 && !Ty.isVector()) {
8168 // v = (v + (v >> 8)) & 0xFF;
8169 auto C_8 = B.buildConstant(Ty, 8);
8170 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
8171 auto Res = B.buildAdd(Ty, B8Count, HighSum);
8172 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
8173 MI.eraseFromParent();
8174 return Legalized;
8175 }
8176
8177 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
8178 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
8179 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
8180
8181 // Shift count result from 8 high bits to low bits.
8182 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
8183
8184 auto IsMulSupported = [this](const LLT Ty) {
8185 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
8186 return Action == Legal || Action == WidenScalar || Action == Custom;
8187 };
8188 if (IsMulSupported(Ty)) {
8189 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
8190 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8191 } else {
8192 auto ResTmp = B8Count;
8193 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
8194 auto ShiftC = B.buildConstant(Ty, Shift);
8195 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
8196 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
8197 }
8198 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8199 }
8200 MI.eraseFromParent();
8201 return Legalized;
8202 }
8203 case TargetOpcode::G_CTLS: {
8204 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8205
8206 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
8207 auto SignIdxC =
8208 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
8209 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
8210
8211 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
8212
8213 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
8214 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
8215
8216 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8217 MI.eraseFromParent();
8218 return Legalized;
8219 }
8220 }
8221}
8222
8223// Check that (every element of) Reg is undef or not an exact multiple of BW.
8225 Register Reg, unsigned BW) {
8226 return matchUnaryPredicate(
8227 MRI, Reg,
8228 [=](const Constant *C) {
8229 // Null constant here means an undef.
8231 return !CI || CI->getValue().urem(BW) != 0;
8232 },
8233 /*AllowUndefs*/ true);
8234}
8235
8236// Check that (every element of) Reg is a constant that is not an exact multiple
8237// of BW.
8239 unsigned BW) {
8240 return matchUnaryPredicate(MRI, Reg, [=](const Constant *C) {
8241 return cast<ConstantInt>(C)->getValue().urem(BW) != 0;
8242 });
8243}
8244
8247 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8248 LLT Ty = MRI.getType(Dst);
8249 LLT ShTy = MRI.getType(Z);
8250
8251 unsigned BW = Ty.getScalarSizeInBits();
8252
8253 if (!isPowerOf2_32(BW))
8254 return UnableToLegalize;
8255
8256 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8257 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8258
8259 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8260 // fshl X, Y, Z -> fshr X, Y, -Z
8261 // fshr X, Y, Z -> fshl X, Y, -Z
8262 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8263 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8264 } else {
8265 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8266 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8267 auto One = MIRBuilder.buildConstant(ShTy, 1);
8268 if (IsFSHL) {
8269 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8270 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8271 } else {
8272 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8273 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8274 }
8275
8276 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8277 }
8278
8279 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8280 MI.eraseFromParent();
8281 return Legalized;
8282}
8283
8286 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8287 LLT Ty = MRI.getType(Dst);
8288 LLT ShTy = MRI.getType(Z);
8289
8290 const unsigned BW = Ty.getScalarSizeInBits();
8291 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8292
8293 Register ShX, ShY;
8294 Register ShAmt, InvShAmt;
8295 unsigned OrFlags = MachineInstr::NoFlags;
8296
8297 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8298 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8299 // fshl: X << C | Y >> (BW - C)
8300 // fshr: X << (BW - C) | Y >> C
8301 // where C = Z % BW is not zero
8302 // If Z has undef elements, C may be zero so the or isn't disjoint.
8303 if (isNonZeroModBitWidth(MRI, Z, BW))
8304 OrFlags |= MachineInstr::Disjoint;
8305 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8306 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8307 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8308 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8309 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8310 } else {
8311 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8312 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8313 // The extra shift by 1 guarantees the two sides don't overlap.
8314 OrFlags |= MachineInstr::Disjoint;
8315 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8316 if (isPowerOf2_32(BW)) {
8317 // Z % BW -> Z & (BW - 1)
8318 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8319 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8320 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8321 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8322 } else {
8323 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8324 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8325 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8326 }
8327
8328 auto One = MIRBuilder.buildConstant(ShTy, 1);
8329 if (IsFSHL) {
8330 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8331 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8332 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8333 } else {
8334 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8335 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8336 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8337 }
8338 }
8339
8340 MIRBuilder.buildOr(Dst, ShX, ShY, OrFlags);
8341 MI.eraseFromParent();
8342 return Legalized;
8343}
8344
8347 // These operations approximately do the following (while avoiding undefined
8348 // shifts by BW):
8349 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8350 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8351 Register Dst = MI.getOperand(0).getReg();
8352 LLT Ty = MRI.getType(Dst);
8353 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8354
8355 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8356 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8357
8358 // TODO: Use smarter heuristic that accounts for vector legalization.
8359 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8360 return lowerFunnelShiftAsShifts(MI);
8361
8362 // This only works for powers of 2, fallback to shifts if it fails.
8363 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8364 if (Result == UnableToLegalize)
8365 return lowerFunnelShiftAsShifts(MI);
8366 return Result;
8367}
8368
8370 auto [Dst, Src] = MI.getFirst2Regs();
8371 LLT DstTy = MRI.getType(Dst);
8372 LLT SrcTy = MRI.getType(Src);
8373
8374 uint32_t DstTySize = DstTy.getSizeInBits();
8375 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8376 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8377
8378 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8379 !isPowerOf2_32(SrcTyScalarSize))
8380 return UnableToLegalize;
8381
8382 // The step between extend is too large, split it by creating an intermediate
8383 // extend instruction
8384 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8385 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8386 // If the destination type is illegal, split it into multiple statements
8387 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8388 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8389 // Unmerge the vector
8390 LLT EltTy = MidTy.changeElementCount(
8392 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8393
8394 // ZExt the vectors
8395 LLT ZExtResTy = DstTy.changeElementCount(
8397 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8398 {UnmergeSrc.getReg(0)});
8399 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8400 {UnmergeSrc.getReg(1)});
8401
8402 // Merge the ending vectors
8403 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8404
8405 MI.eraseFromParent();
8406 return Legalized;
8407 }
8408 return UnableToLegalize;
8409}
8410
8412 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8413 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8414 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8415 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8416 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8417 // %lo16(<4 x s16>) = G_TRUNC %inlo
8418 // %hi16(<4 x s16>) = G_TRUNC %inhi
8419 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8420 // %res(<8 x s8>) = G_TRUNC %in16
8421
8422 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8423
8424 Register DstReg = MI.getOperand(0).getReg();
8425 Register SrcReg = MI.getOperand(1).getReg();
8426 LLT DstTy = MRI.getType(DstReg);
8427 LLT SrcTy = MRI.getType(SrcReg);
8428
8429 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8431 isPowerOf2_32(SrcTy.getNumElements()) &&
8432 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8433 // Split input type.
8434 LLT SplitSrcTy = SrcTy.changeElementCount(
8435 SrcTy.getElementCount().divideCoefficientBy(2));
8436
8437 // First, split the source into two smaller vectors.
8438 SmallVector<Register, 2> SplitSrcs;
8439 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8440
8441 // Truncate the splits into intermediate narrower elements.
8442 LLT InterTy;
8443 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8444 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8445 else
8446 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8447 for (Register &Src : SplitSrcs)
8448 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8449
8450 // Combine the new truncates into one vector
8451 auto Merge = MIRBuilder.buildMergeLikeInstr(
8452 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8453
8454 // Truncate the new vector to the final result type
8455 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8456 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8457 else
8458 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8459
8460 MI.eraseFromParent();
8461
8462 return Legalized;
8463 }
8464 return UnableToLegalize;
8465}
8466
8469 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8470 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8471 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8472 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8473 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8474 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8475 MI.eraseFromParent();
8476 return Legalized;
8477}
8478
8480 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8481
8482 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8483 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8484
8485 MIRBuilder.setInstrAndDebugLoc(MI);
8486
8487 // If a rotate in the other direction is supported, use it.
8488 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8489 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8490 isPowerOf2_32(EltSizeInBits))
8491 return lowerRotateWithReverseRotate(MI);
8492
8493 // If a funnel shift is supported, use it.
8494 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8495 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8496 bool IsFShLegal = false;
8497 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8498 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8499 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8500 Register R3) {
8501 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8502 MI.eraseFromParent();
8503 return Legalized;
8504 };
8505 // If a funnel shift in the other direction is supported, use it.
8506 if (IsFShLegal) {
8507 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8508 } else if (isPowerOf2_32(EltSizeInBits)) {
8509 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8510 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8511 }
8512 }
8513
8514 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8515 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8516 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8517 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8518 Register ShVal;
8519 Register RevShiftVal;
8520 unsigned OrFlags = MachineInstr::NoFlags;
8521 if (isPowerOf2_32(EltSizeInBits)) {
8522 // If c may be zero modulo w, both shifts may return x so the or isn't
8523 // disjoint.
8524 if (isNonZeroModBitWidth(MRI, Amt, EltSizeInBits))
8525 OrFlags |= MachineInstr::Disjoint;
8526 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8527 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8528 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8529 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8530 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8531 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8532 RevShiftVal =
8533 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8534 } else {
8535 OrFlags |= MachineInstr::Disjoint;
8536 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8537 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8538 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8539 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8540 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8541 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8542 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8543 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8544 RevShiftVal =
8545 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8546 }
8547 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, OrFlags);
8548 MI.eraseFromParent();
8549 return Legalized;
8550}
8551
8552// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8553// operations and G_SITOFP
8556 auto [Dst, Src] = MI.getFirst2Regs();
8557 const LLT S64 = LLT::scalar(64);
8558 const LLT S32 = LLT::scalar(32);
8559 const LLT S1 = LLT::scalar(1);
8560
8561 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8562
8563 // For i64 < INT_MAX we simply reuse SITOFP.
8564 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8565 // saved before division, convert to float by SITOFP, multiply the result
8566 // by 2.
8567 auto One = MIRBuilder.buildConstant(S64, 1);
8568 auto Zero = MIRBuilder.buildConstant(S64, 0);
8569 // Result if Src < INT_MAX
8570 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8571 // Result if Src >= INT_MAX
8572 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8573 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8574 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8575 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8576 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8577 // Check if the original value is larger than INT_MAX by comparing with
8578 // zero to pick one of the two conversions.
8579 auto IsLarge =
8580 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
8581 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8582
8583 MI.eraseFromParent();
8584 return Legalized;
8585}
8586
8587// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8588// IEEE double representation.
8591 auto [Dst, Src] = MI.getFirst2Regs();
8592 const LLT S64 = LLT::scalar(64);
8593 const LLT S32 = LLT::scalar(32);
8594
8595 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8596
8597 // We create double value from 32 bit parts with 32 exponent difference.
8598 // Note that + and - are float operations that adjust the implicit leading
8599 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8600 //
8601 // X = 2^52 * 1.0...LowBits
8602 // Y = 2^84 * 1.0...HighBits
8603 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8604 // = - 2^52 * 1.0...HighBits
8605 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8606 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8607 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8608 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8609 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8610 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8611
8612 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8613 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8614 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8615 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8616 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8617 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8618 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8619
8620 MI.eraseFromParent();
8621 return Legalized;
8622}
8623
8624/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8625/// convert fpround f64->f16 without double-rounding, so we manually perform the
8626/// lowering here where we know it is valid.
8629 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8630 auto DstFpTy =
8631 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8632 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8633 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8634 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8635 LLT F32Ty = DstFpTy.changeElementSize(32);
8636 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8637 MIRBuilder.buildFPTrunc(Dst, M2);
8638 MI.eraseFromParent();
8640}
8641
8643 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8644
8645 if (SrcTy == LLT::scalar(1)) {
8646 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8647 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8648 MIRBuilder.buildSelect(Dst, Src, True, False);
8649 MI.eraseFromParent();
8650 return Legalized;
8651 }
8652
8653 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8654 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8655
8656 if (SrcTy != LLT::scalar(64))
8657 return UnableToLegalize;
8658
8659 if (DstTy == LLT::scalar(32))
8660 // TODO: SelectionDAG has several alternative expansions to port which may
8661 // be more reasonable depending on the available instructions. We also need
8662 // a more advanced mechanism to choose an optimal version depending on
8663 // target features such as sitofp or CTLZ availability.
8665
8666 if (DstTy == LLT::scalar(64))
8668
8669 return UnableToLegalize;
8670}
8671
8673 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8674
8675 const LLT I64 = LLT::integer(64);
8676 const LLT I32 = LLT::integer(32);
8677 const LLT I1 = LLT::integer(1);
8678
8679 if (SrcTy == I1) {
8680 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8681 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8682 MIRBuilder.buildSelect(Dst, Src, True, False);
8683 MI.eraseFromParent();
8684 return Legalized;
8685 }
8686
8687 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8688 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8689
8690 if (SrcTy != I64)
8691 return UnableToLegalize;
8692
8693 if (DstTy.getScalarSizeInBits() == 32) {
8694 // signed cl2f(long l) {
8695 // long s = l >> 63;
8696 // float r = cul2f((l + s) ^ s);
8697 // return s ? -r : r;
8698 // }
8699 Register L = Src;
8700 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8701 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8702
8703 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8704 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8705 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8706
8707 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8708 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8709 MIRBuilder.buildConstant(I64, 0));
8710 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8711 MI.eraseFromParent();
8712 return Legalized;
8713 }
8714
8715 return UnableToLegalize;
8716}
8717
8719 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8720 const LLT S64 = LLT::scalar(64);
8721 const LLT S32 = LLT::scalar(32);
8722
8723 if (SrcTy != S64 && SrcTy != S32)
8724 return UnableToLegalize;
8725 if (DstTy != S32 && DstTy != S64)
8726 return UnableToLegalize;
8727
8728 // FPTOSI gives same result as FPTOUI for positive signed integers.
8729 // FPTOUI needs to deal with fp values that convert to unsigned integers
8730 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8731
8732 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8733 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8735 APInt::getZero(SrcTy.getSizeInBits()));
8736 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8737
8738 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8739
8740 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8741 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8742 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8743 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8744 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8745 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8746 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8747
8748 const LLT S1 = LLT::scalar(1);
8749
8750 MachineInstrBuilder FCMP =
8751 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8752 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8753
8754 MI.eraseFromParent();
8755 return Legalized;
8756}
8757
8759 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8760 const LLT S64 = LLT::scalar(64);
8761 const LLT S32 = LLT::scalar(32);
8762
8763 // FIXME: Only f32 to i64 conversions are supported.
8764 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8765 return UnableToLegalize;
8766
8767 // Expand f32 -> i64 conversion
8768 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8769 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8770
8771 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8772
8773 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8774 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8775
8776 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8777 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8778
8779 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8780 APInt::getSignMask(SrcEltBits));
8781 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8782 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8783 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8784 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8785
8786 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8787 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8788 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8789
8790 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8791 R = MIRBuilder.buildZExt(DstTy, R);
8792
8793 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8794 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8795 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8796 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8797
8798 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8799 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8800
8801 const LLT S1 = LLT::scalar(1);
8802 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8803 S1, Exponent, ExponentLoBit);
8804
8805 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8806
8807 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8808 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8809
8810 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8811
8812 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8813 S1, Exponent, ZeroSrcTy);
8814
8815 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8816 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8817
8818 MI.eraseFromParent();
8819 return Legalized;
8820}
8821
8824 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8825
8826 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8827 unsigned SatWidth = DstTy.getScalarSizeInBits();
8828
8829 // Determine minimum and maximum integer values and their corresponding
8830 // floating-point values.
8831 APInt MinInt, MaxInt;
8832 if (IsSigned) {
8833 MinInt = APInt::getSignedMinValue(SatWidth);
8834 MaxInt = APInt::getSignedMaxValue(SatWidth);
8835 } else {
8836 MinInt = APInt::getMinValue(SatWidth);
8837 MaxInt = APInt::getMaxValue(SatWidth);
8838 }
8839
8840 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8841 APFloat MinFloat(Semantics);
8842 APFloat MaxFloat(Semantics);
8843
8844 APFloat::opStatus MinStatus =
8845 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8846 APFloat::opStatus MaxStatus =
8847 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8848 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8849 !(MaxStatus & APFloat::opStatus::opInexact);
8850
8851 // If the integer bounds are exactly representable as floats, emit a
8852 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8853 // and selects.
8854 if (AreExactFloatBounds) {
8855 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8856 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8857 auto MaxP =
8858 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8859 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8860 // Clamp by MaxFloat from above. NaN cannot occur.
8861 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8862 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8864 auto Min =
8865 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8866 // Convert clamped value to integer. In the unsigned case we're done,
8867 // because we mapped NaN to MinFloat, which will cast to zero.
8868 if (!IsSigned) {
8869 MIRBuilder.buildFPTOUI(Dst, Min);
8870 MI.eraseFromParent();
8871 return Legalized;
8872 }
8873
8874 // Otherwise, select 0 if Src is NaN.
8875 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8876 auto IsZero =
8877 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8878 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8879 FpToInt);
8880 MI.eraseFromParent();
8881 return Legalized;
8882 }
8883
8884 // Result of direct conversion. The assumption here is that the operation is
8885 // non-trapping and it's fine to apply it to an out-of-range value if we
8886 // select it away later.
8887 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8888 : MIRBuilder.buildFPTOUI(DstTy, Src);
8889
8890 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8891 // MinInt if Src is NaN.
8892 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8893 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8894 auto Max = MIRBuilder.buildSelect(
8895 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8896 // If Src OGT MaxFloat, select MaxInt.
8897 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8898 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8899
8900 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8901 // is already zero.
8902 if (!IsSigned) {
8903 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8904 Max);
8905 MI.eraseFromParent();
8906 return Legalized;
8907 }
8908
8909 // Otherwise, select 0 if Src is NaN.
8910 auto Min = MIRBuilder.buildSelect(
8911 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8912 auto IsZero =
8913 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8914 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8915 MI.eraseFromParent();
8916 return Legalized;
8917}
8918
8919// Floating-point conversions using truncating and extending loads and stores.
8922 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8923 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8924 "Only G_FPEXT and G_FPTRUNC are expected");
8925
8926 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8927 MachinePointerInfo PtrInfo;
8928 unsigned StoreOpc;
8929 unsigned LoadOpc;
8930 LLT StackTy;
8931 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8932 StackTy = SrcTy;
8933 StoreOpc = TargetOpcode::G_STORE;
8934 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8935 } else {
8936 StackTy = DstTy;
8937 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8938 LoadOpc = TargetOpcode::G_LOAD;
8939 }
8940
8941 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8942 auto StackTemp =
8943 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8944
8945 MachineFunction &MF = MIRBuilder.getMF();
8946 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8947 StackTy, StackTyAlign);
8948 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8949
8950 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8951 StackTy, StackTyAlign);
8952 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8953
8954 MI.eraseFromParent();
8955 return Legalized;
8956}
8957
8958// Expand a bf16 -> f32/f64 fpext with a shift and bitcast. This is based on the
8959// SDAG ISD::BF16_TO_FP lowering.
8962 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8963 assert(SrcTy.getScalarType().isBFloat16() &&
8964 "expected a bf16 source for bf16 fpext lowering");
8965
8966 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8967 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8968 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
8969
8970 auto SrcI =
8971 MIRBuilder.buildAnyExt(I32Ty, MIRBuilder.buildBitcast(I16Ty, SrcReg));
8972 auto Shl =
8973 MIRBuilder.buildShl(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8974
8975 if (DstTy.getScalarType().isFloat32())
8976 MIRBuilder.buildBitcast(DstReg, Shl);
8977 else
8978 MIRBuilder.buildFPExt(DstReg, MIRBuilder.buildBitcast(F32Ty, Shl));
8979
8980 MI.eraseFromParent();
8981 return Legalized;
8982}
8983
8985 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
8986 if (SrcTy.getScalarType().isBFloat16() &&
8987 (DstTy.getScalarType().isFloat32() || DstTy.getScalarType().isFloat64()))
8988 return lowerFPEXT_BF16(MI);
8989
8990 return lowerFPExtAndTruncMem(MI);
8991}
8992
8993// f64 -> f16 conversion using round-to-nearest-even rounding mode.
8996 const LLT S1 = LLT::scalar(1);
8997 const LLT I32 = LLT::integer(32);
8998
8999 auto [Dst, Src] = MI.getFirst2Regs();
9000 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
9001 MRI.getType(Src).getScalarType() == LLT::float64());
9002
9003 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
9004 return UnableToLegalize;
9005
9006 if (MI.getFlag(MachineInstr::FmAfn)) {
9007 unsigned Flags = MI.getFlags();
9008 auto Src32 = MIRBuilder.buildFPTrunc(LLT::float32(), Src, Flags);
9009 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
9010 MI.eraseFromParent();
9011 return Legalized;
9012 }
9013
9014 const unsigned ExpMask = 0x7ff;
9015 const unsigned ExpBiasf64 = 1023;
9016 const unsigned ExpBiasf16 = 15;
9017
9018 auto Unmerge = MIRBuilder.buildUnmerge(I32, Src);
9019 Register U = Unmerge.getReg(0);
9020 Register UH = Unmerge.getReg(1);
9021
9022 auto E = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 20));
9023 E = MIRBuilder.buildAnd(I32, E, MIRBuilder.buildConstant(I32, ExpMask));
9024
9025 // Subtract the fp64 exponent bias (1023) to get the real exponent and
9026 // add the f16 bias (15) to get the biased exponent for the f16 format.
9027 E = MIRBuilder.buildAdd(
9028 I32, E, MIRBuilder.buildConstant(I32, -ExpBiasf64 + ExpBiasf16));
9029
9030 auto M = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 8));
9031 M = MIRBuilder.buildAnd(I32, M, MIRBuilder.buildConstant(I32, 0xffe));
9032
9033 auto MaskedSig =
9034 MIRBuilder.buildAnd(I32, UH, MIRBuilder.buildConstant(I32, 0x1ff));
9035 MaskedSig = MIRBuilder.buildOr(I32, MaskedSig, U);
9036
9037 auto Zero = MIRBuilder.buildConstant(I32, 0);
9038 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
9039 auto Lo40Set = MIRBuilder.buildZExt(I32, SigCmpNE0);
9040 M = MIRBuilder.buildOr(I32, M, Lo40Set);
9041
9042 // (M != 0 ? 0x0200 : 0) | 0x7c00;
9043 auto Bits0x200 = MIRBuilder.buildConstant(I32, 0x0200);
9044 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
9045 auto SelectCC = MIRBuilder.buildSelect(I32, CmpM_NE0, Bits0x200, Zero);
9046
9047 auto Bits0x7c00 = MIRBuilder.buildConstant(I32, 0x7c00);
9048 auto I = MIRBuilder.buildOr(I32, SelectCC, Bits0x7c00);
9049
9050 // N = M | (E << 12);
9051 auto EShl12 = MIRBuilder.buildShl(I32, E, MIRBuilder.buildConstant(I32, 12));
9052 auto N = MIRBuilder.buildOr(I32, M, EShl12);
9053
9054 // B = clamp(1-E, 0, 13);
9055 auto One = MIRBuilder.buildConstant(I32, 1);
9056 auto OneSubExp = MIRBuilder.buildSub(I32, One, E);
9057 auto B = MIRBuilder.buildSMax(I32, OneSubExp, Zero);
9058 B = MIRBuilder.buildSMin(I32, B, MIRBuilder.buildConstant(I32, 13));
9059
9060 auto SigSetHigh =
9061 MIRBuilder.buildOr(I32, M, MIRBuilder.buildConstant(I32, 0x1000));
9062
9063 auto D = MIRBuilder.buildLShr(I32, SigSetHigh, B);
9064 auto D0 = MIRBuilder.buildShl(I32, D, B);
9065
9066 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
9067 D0, SigSetHigh);
9068 auto D1 = MIRBuilder.buildZExt(I32, D0_NE_SigSetHigh);
9069 D = MIRBuilder.buildOr(I32, D, D1);
9070
9071 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
9072 auto V = MIRBuilder.buildSelect(I32, CmpELtOne, D, N);
9073
9074 auto VLow3 = MIRBuilder.buildAnd(I32, V, MIRBuilder.buildConstant(I32, 7));
9075 V = MIRBuilder.buildLShr(I32, V, MIRBuilder.buildConstant(I32, 2));
9076
9077 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
9078 MIRBuilder.buildConstant(I32, 3));
9079 auto V0 = MIRBuilder.buildZExt(I32, VLow3Eq3);
9080
9081 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
9082 MIRBuilder.buildConstant(I32, 5));
9083 auto V1 = MIRBuilder.buildZExt(I32, VLow3Gt5);
9084
9085 V1 = MIRBuilder.buildOr(I32, V0, V1);
9086 V = MIRBuilder.buildAdd(I32, V, V1);
9087
9088 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, E,
9089 MIRBuilder.buildConstant(I32, 30));
9090 V = MIRBuilder.buildSelect(I32, CmpEGt30,
9091 MIRBuilder.buildConstant(I32, 0x7c00), V);
9092
9093 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, E,
9094 MIRBuilder.buildConstant(I32, 1039));
9095 V = MIRBuilder.buildSelect(I32, CmpEGt1039, I, V);
9096
9097 // Extract the sign bit.
9098 auto Sign = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 16));
9099 Sign = MIRBuilder.buildAnd(I32, Sign, MIRBuilder.buildConstant(I32, 0x8000));
9100
9101 // Insert the sign bit
9102 V = MIRBuilder.buildOr(I32, Sign, V);
9103
9104 MIRBuilder.buildTrunc(Dst, V);
9105 MI.eraseFromParent();
9106 return Legalized;
9107}
9108
9109// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
9112 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9113 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9114 SrcTy.getScalarType() == LLT::float32());
9115
9116 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
9117 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
9118 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
9119
9120 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
9121
9122 // Conversions should set NaN's quiet bit. This also prevents NaNs from
9123 // turning into infinities.
9124 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
9125 MIRBuilder.buildConstant(I32Ty, 0x400000));
9126
9127 // Factor in the contribution of the low 16 bits.
9128 auto Lsb =
9129 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
9130 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
9131 auto RoundingBias =
9132 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
9133 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
9134
9135 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
9136 // 0x80000000.
9137 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9138 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
9139 MIRBuilder.buildFConstant(SrcTy, 0));
9140 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
9141 }
9142
9143 // Now that we have rounded, shift the bits into position.
9144 auto Srl =
9145 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
9146 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
9147 MIRBuilder.buildBitcast(DstReg, Trunc);
9148 MI.eraseFromParent();
9149 return Legalized;
9150}
9151
9152// Round a wide fp value to ResultTy's element size, forcing inexact
9153// results to the odd value so a subsequent narrowing round is correct. This
9154// avoids double-rounding when narrowing e.g. f64 -> f32 -> bf16. See Boldo &
9155// Melquiond, "When double rounding is odd" (2005).
9157 LLT OperandTy = MRI.getType(Op);
9158 if (OperandTy.getScalarType() == ResultTy.getScalarType())
9159 return Op;
9160
9161 LLT ResultIntTy =
9163 LLT ResultCCTy = ResultTy.changeElementType(LLT::integer(1));
9164 LLT OperandCCTy = OperandTy.changeElementType(LLT::integer(1));
9165
9166 auto Narrow = MIRBuilder.buildFPTrunc(ResultTy, Op);
9167 auto NarrowAsWide = MIRBuilder.buildFPExt(OperandTy, Narrow);
9168
9169 auto NarrowBits = MIRBuilder.buildBitcast(ResultIntTy, Narrow);
9170 auto One = MIRBuilder.buildConstant(ResultIntTy, 1);
9171 auto NegativeOne = MIRBuilder.buildConstant(ResultIntTy, -1);
9172 auto Zero = MIRBuilder.buildConstant(ResultIntTy, 0);
9173 auto And = MIRBuilder.buildAnd(ResultIntTy, NarrowBits, One);
9174 // The result is already odd so we don't need to do anything.
9175 auto AlreadyOdd =
9176 MIRBuilder.buildICmp(CmpInst::ICMP_NE, ResultCCTy, And, Zero);
9177
9178 // We keep results which are exact, odd or NaN.
9179 auto KeepNarrow =
9180 MIRBuilder.buildFCmp(CmpInst::FCMP_UEQ, OperandCCTy, Op, NarrowAsWide);
9181 KeepNarrow = MIRBuilder.buildOr(OperandCCTy, KeepNarrow, AlreadyOdd);
9182 // We morally performed a round-down if AbsNarrow is smaller than AbsWide.
9183 auto AbsWide = MIRBuilder.buildFAbs(OperandTy, Op);
9184 auto AbsNarrowAsWide = MIRBuilder.buildFAbs(OperandTy, NarrowAsWide);
9185 auto NarrowIsRd = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, OperandCCTy,
9186 AbsWide, AbsNarrowAsWide);
9187 // If narrow is the rounded-down value, pick the rounded-up value as it will
9188 // be odd; otherwise adjust down.
9189 auto Adjust =
9190 MIRBuilder.buildSelect(ResultIntTy, NarrowIsRd, One, NegativeOne);
9191 auto Adjusted = MIRBuilder.buildAdd(ResultIntTy, NarrowBits, Adjust);
9192 auto Res =
9193 MIRBuilder.buildSelect(ResultIntTy, KeepNarrow, NarrowBits, Adjusted);
9194 return MIRBuilder.buildBitcast(ResultTy, Res).getReg(0);
9195}
9196
9197// f64 -> bf16 conversion, correcting for double rounding.
9200 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9201 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9202 SrcTy.getScalarType() == LLT::float64());
9203
9204 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
9205 Register OddF32 = lowerRoundInexactToOdd(F32Ty, SrcReg);
9206 MIRBuilder.buildFPTrunc(DstReg, OddF32, MI.getFlags());
9207 MI.eraseFromParent();
9208 return Legalized;
9209}
9210
9213 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9214 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
9216
9217 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
9219
9220 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat64())
9222
9223 return lowerFPExtAndTruncMem(MI);
9224}
9225
9227 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9228 LLT Ty = MRI.getType(Dst);
9229
9230 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
9231 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
9232 MI.eraseFromParent();
9233 return Legalized;
9234}
9235
9237 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
9238 LLT Ty = MRI.getType(Src);
9239 auto Flags = MI.getFlags();
9240 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9241
9242 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
9243 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
9244
9245 Register FracToUse;
9246 if (MI.getFlag(MachineInstr::FmNoInfs)) {
9247 FracToUse = FracPart.getReg(0);
9248 } else {
9249 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
9250 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
9251 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
9252 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
9253 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9254 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
9255 FracToUse = Select.getReg(0);
9256 }
9257
9258 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
9259 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
9260
9261 MI.eraseFromParent();
9262 return Legalized;
9263}
9264
9266 switch (Opc) {
9267 case TargetOpcode::G_SMIN:
9268 return CmpInst::ICMP_SLT;
9269 case TargetOpcode::G_SMAX:
9270 return CmpInst::ICMP_SGT;
9271 case TargetOpcode::G_UMIN:
9272 return CmpInst::ICMP_ULT;
9273 case TargetOpcode::G_UMAX:
9274 return CmpInst::ICMP_UGT;
9275 default:
9276 llvm_unreachable("not in integer min/max");
9277 }
9278}
9279
9281 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9282
9283 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9284 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9285
9286 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9287 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9288
9289 MI.eraseFromParent();
9290 return Legalized;
9291}
9292
9295 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9296
9297 Register Dst = Cmp->getReg(0);
9298 LLT DstTy = MRI.getType(Dst);
9299 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9300 LLT CmpTy = DstTy.changeElementSize(1);
9301
9302 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9305 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9308
9309 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9310 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9311 Cmp->getRHSReg());
9312 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9313 Cmp->getRHSReg());
9314
9315 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9316 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9317 if (TLI.preferSelectsOverBooleanArithmetic(
9318 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9320 auto One = MIRBuilder.buildConstant(DstTy, 1);
9321 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9322
9323 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9324 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9325 } else {
9327 std::swap(IsGT, IsLT);
9328 // Extend boolean results to DstTy, which is at least i2, before subtracting
9329 // them.
9330 unsigned BoolExtOp =
9331 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9332 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9333 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9334 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9335 }
9336
9337 MI.eraseFromParent();
9338 return Legalized;
9339}
9340
9343 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9344 const int Src0Size = Src0Ty.getScalarSizeInBits();
9345 const int Src1Size = Src1Ty.getScalarSizeInBits();
9346
9347 LLT DstIntTy =
9348 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9349 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9350 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9351
9352 Register Src0Int = Src0;
9353 Register Src1Int = Src1;
9354
9355 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9356 Src0Ty.getScalarType().isInteger()))
9357 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9358
9359 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9360 Src1Ty.getScalarType().isInteger()))
9361 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9362
9363 auto SignBitMask =
9364 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9365
9366 auto NotSignBitMask = MIRBuilder.buildConstant(
9367 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9368
9369 Register And0 =
9370 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9371 Register And1;
9372 if (Src0Ty == Src1Ty) {
9373 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9374 } else if (Src0Size > Src1Size) {
9375 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9376 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9377 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9378 And1 = MIRBuilder.buildAnd(Src0IntTy, Shift, SignBitMask).getReg(0);
9379 } else {
9380 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9381 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9382 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9383 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9384 }
9385
9386 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9387 // constants are a nan and -0.0, but the final result should preserve
9388 // everything.
9389 unsigned Flags = MI.getFlags();
9390
9391 // We masked the sign bit and the not-sign bit, so these are disjoint.
9392 Flags |= MachineInstr::Disjoint;
9393
9394 if (DstTy == DstIntTy)
9395 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9396 else {
9397 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9398 MIRBuilder.buildBitcast(Dst, NewDst);
9399 }
9400
9401 MI.eraseFromParent();
9402 return Legalized;
9403}
9404
9407 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9408 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9409 // depend on fminnum/fmaxnum.
9410
9411 unsigned NewOp;
9412 switch (MI.getOpcode()) {
9413 case TargetOpcode::G_FMINNUM:
9414 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9415 break;
9416 case TargetOpcode::G_FMINIMUMNUM:
9417 NewOp = TargetOpcode::G_FMINNUM;
9418 break;
9419 case TargetOpcode::G_FMAXNUM:
9420 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9421 break;
9422 case TargetOpcode::G_FMAXIMUMNUM:
9423 NewOp = TargetOpcode::G_FMAXNUM;
9424 break;
9425 default:
9426 llvm_unreachable("unexpected min/max opcode");
9427 }
9428
9429 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9430 LLT Ty = MRI.getType(Dst);
9431
9432 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9433 // Insert canonicalizes if it's possible we need to quiet to get correct
9434 // sNaN behavior.
9435
9436 // Note this must be done here, and not as an optimization combine in the
9437 // absence of a dedicate quiet-snan instruction as we're using an
9438 // omni-purpose G_FCANONICALIZE.
9439 if (!VT->isKnownNeverSNaN(Src0))
9440 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9441
9442 if (!VT->isKnownNeverSNaN(Src1))
9443 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9444 }
9445
9446 // If there are no nans, it's safe to simply replace this with the non-IEEE
9447 // version.
9448 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9449 MI.eraseFromParent();
9450 return Legalized;
9451}
9452
9455 unsigned Opc = MI.getOpcode();
9456 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9457 LLT Ty = MRI.getType(Dst);
9458 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9459
9460 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9461 unsigned OpcIeee =
9462 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9463 unsigned OpcNonIeee =
9464 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9465 bool MinMaxMustRespectOrderedZero = false;
9466 Register Res;
9467
9468 // IEEE variants don't need canonicalization
9469 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9470 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9471 MinMaxMustRespectOrderedZero = true;
9472 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9473 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9474 } else {
9475 auto Compare = MIRBuilder.buildFCmp(
9476 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9477 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9478 }
9479
9480 // Propagate any NaN of both operands
9481 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9482 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9483 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9484
9485 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9486 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9487 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9488 if (Ty.isVector())
9489 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9490
9491 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9492 }
9493
9494 // fminimum/fmaximum requires -0.0 less than +0.0
9495 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9496 GISelValueTracking VT(MIRBuilder.getMF());
9497 // FIXME: Also demand for subnormal classes depending on the denormal mode.
9498 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9499 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9500
9501 // FIXME: Must use isKnownNeverLogicalZero(Mode)
9502 if (!Src0Info.isKnownNever(fcZero) && !Src1Info.isKnownNever(fcZero)) {
9503 const unsigned Flags = MI.getFlags();
9504 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9505 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9506
9507 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9508
9509 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9510 auto LHSSelect =
9511 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9512
9513 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9514 auto RHSSelect =
9515 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9516
9517 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9518 }
9519 }
9520
9521 MIRBuilder.buildCopy(Dst, Res);
9522 MI.eraseFromParent();
9523 return Legalized;
9524}
9525
9527 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9528 Register DstReg = MI.getOperand(0).getReg();
9529 LLT Ty = MRI.getType(DstReg);
9530 unsigned Flags = MI.getFlags();
9531
9532 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9533 Flags);
9534 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9535 MI.eraseFromParent();
9536 return Legalized;
9537}
9538
9541 auto [DstReg, X] = MI.getFirst2Regs();
9542 const unsigned Flags = MI.getFlags();
9543 const LLT Ty = MRI.getType(DstReg);
9544 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9545
9546 // round(x) =>
9547 // t = trunc(x);
9548 // d = fabs(x - t);
9549 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9550 // return t + o;
9551
9552 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9553
9554 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9555 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9556
9557 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9558 auto Cmp =
9559 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9560
9561 // Could emit G_UITOFP instead
9562 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9563 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9564 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9565 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9566
9567 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9568
9569 MI.eraseFromParent();
9570 return Legalized;
9571}
9572
9574 auto [DstReg, SrcReg] = MI.getFirst2Regs();
9575 unsigned Flags = MI.getFlags();
9576 LLT Ty = MRI.getType(DstReg);
9577 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9578
9579 // result = trunc(src);
9580 // if (src < 0.0 && src != result)
9581 // result += -1.0.
9582
9583 auto Trunc = MIRBuilder.buildIntrinsicTrunc(Ty, SrcReg, Flags);
9584 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9585
9586 auto Lt0 = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, CondTy,
9587 SrcReg, Zero, Flags);
9588 auto NeTrunc = MIRBuilder.buildFCmp(CmpInst::FCMP_ONE, CondTy,
9589 SrcReg, Trunc, Flags);
9590 auto And = MIRBuilder.buildAnd(CondTy, Lt0, NeTrunc);
9591 auto AddVal = MIRBuilder.buildSITOFP(Ty, And);
9592
9593 MIRBuilder.buildFAdd(DstReg, Trunc, AddVal, Flags);
9594 MI.eraseFromParent();
9595 return Legalized;
9596}
9597
9600 const unsigned NumOps = MI.getNumOperands();
9601 auto [DstReg, DstTy, Src0Reg, Src0Ty] = MI.getFirst2RegLLTs();
9602 unsigned PartSize = Src0Ty.getSizeInBits();
9603
9604 LLT WideTy = LLT::integer(DstTy.getSizeInBits());
9605 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src0Reg).getReg(0);
9606
9607 for (unsigned I = 2; I != NumOps; ++I) {
9608 const unsigned Offset = (I - 1) * PartSize;
9609
9610 Register SrcReg = MI.getOperand(I).getReg();
9611 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
9612
9613 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
9614 MRI.createGenericVirtualRegister(WideTy);
9615
9616 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
9617 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
9618 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
9619 ResultReg = NextResult;
9620 }
9621
9622 if (DstTy.isPointer()) {
9623 if (MIRBuilder.getDataLayout().isNonIntegralAddressSpace(
9624 DstTy.getAddressSpace())) {
9625 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
9626 return UnableToLegalize;
9627 }
9628
9629 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
9630 } else if (WideTy != DstTy) {
9631 MIRBuilder.buildBitcast(DstReg, ResultReg);
9632 }
9633
9634 MI.eraseFromParent();
9635 return Legalized;
9636}
9637
9640 const unsigned NumDst = MI.getNumOperands() - 1;
9641 Register SrcReg = MI.getOperand(NumDst).getReg();
9642 Register Dst0Reg = MI.getOperand(0).getReg();
9643 LLT DstTy = MRI.getType(Dst0Reg);
9644 if (DstTy.isPointer())
9645 return UnableToLegalize; // TODO
9646
9647 SrcReg = coerceToInteger(SrcReg);
9648 if (!SrcReg)
9649 return UnableToLegalize;
9650
9651 // Expand scalarizing unmerge as bitcast to integer and shift.
9652 LLT IntTy = MRI.getType(SrcReg);
9653
9654 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
9655
9656 const unsigned DstSize = DstTy.getSizeInBits();
9657 unsigned Offset = DstSize;
9658 for (unsigned I = 1; I != NumDst; ++I, Offset += DstSize) {
9659 auto ShiftAmt = MIRBuilder.buildConstant(IntTy, Offset);
9660 auto Shift = MIRBuilder.buildLShr(IntTy, SrcReg, ShiftAmt);
9661 MIRBuilder.buildTrunc(MI.getOperand(I), Shift);
9662 }
9663
9664 MI.eraseFromParent();
9665 return Legalized;
9666}
9667
9668/// Lower a vector extract or insert by writing the vector to a stack temporary
9669/// and reloading the element or vector.
9670///
9671/// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
9672/// =>
9673/// %stack_temp = G_FRAME_INDEX
9674/// G_STORE %vec, %stack_temp
9675/// %idx = clamp(%idx, %vec.getNumElements())
9676/// %element_ptr = G_PTR_ADD %stack_temp, %idx
9677/// %dst = G_LOAD %element_ptr
9680 Register DstReg = MI.getOperand(0).getReg();
9681 Register SrcVec = MI.getOperand(1).getReg();
9682 Register InsertVal;
9683 if (MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT)
9684 InsertVal = MI.getOperand(2).getReg();
9685
9686 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
9687
9688 LLT VecTy = MRI.getType(SrcVec);
9689 LLT EltTy = VecTy.getElementType();
9690 unsigned NumElts = VecTy.getNumElements();
9691
9692 int64_t IdxVal;
9693 if (mi_match(Idx, MRI, m_ICst(IdxVal)) && IdxVal <= NumElts) {
9695 extractParts(SrcVec, EltTy, NumElts, SrcRegs, MIRBuilder, MRI);
9696
9697 if (InsertVal) {
9698 SrcRegs[IdxVal] = MI.getOperand(2).getReg();
9699 MIRBuilder.buildMergeLikeInstr(DstReg, SrcRegs);
9700 } else {
9701 MIRBuilder.buildCopy(DstReg, SrcRegs[IdxVal]);
9702 }
9703
9704 MI.eraseFromParent();
9705 return Legalized;
9706 }
9707
9708 if (!EltTy.isByteSized()) { // Not implemented.
9709 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
9710 return UnableToLegalize;
9711 }
9712
9713 unsigned EltBytes = EltTy.getSizeInBytes();
9714 Align VecAlign = getStackTemporaryAlignment(VecTy);
9715 Align EltAlign;
9716
9717 MachinePointerInfo PtrInfo;
9718 auto StackTemp = createStackTemporary(
9719 TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign, PtrInfo);
9720 MIRBuilder.buildStore(SrcVec, StackTemp, PtrInfo, VecAlign);
9721
9722 // Get the pointer to the element, and be sure not to hit undefined behavior
9723 // if the index is out of bounds.
9724 Register EltPtr = getVectorElementPointer(StackTemp.getReg(0), VecTy, Idx);
9725
9726 if (mi_match(Idx, MRI, m_ICst(IdxVal))) {
9727 int64_t Offset = IdxVal * EltBytes;
9728 PtrInfo = PtrInfo.getWithOffset(Offset);
9729 EltAlign = commonAlignment(VecAlign, Offset);
9730 } else {
9731 // We lose information with a variable offset.
9732 EltAlign = getStackTemporaryAlignment(EltTy);
9733 PtrInfo = MachinePointerInfo(MRI.getType(EltPtr).getAddressSpace());
9734 }
9735
9736 if (InsertVal) {
9737 // Write the inserted element
9738 MIRBuilder.buildStore(InsertVal, EltPtr, PtrInfo, EltAlign);
9739
9740 // Reload the whole vector.
9741 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
9742 } else {
9743 MIRBuilder.buildLoad(DstReg, EltPtr, PtrInfo, EltAlign);
9744 }
9745
9746 MI.eraseFromParent();
9747 return Legalized;
9748}
9749
9752 auto [DstReg, DstTy, Src0Reg, Src0Ty, Src1Reg, Src1Ty] =
9753 MI.getFirst3RegLLTs();
9754 LLT IdxTy = LLT::scalar(32);
9755
9756 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
9759 LLT EltTy = DstTy.getScalarType();
9760
9761 DenseMap<unsigned, Register> CachedExtract;
9762
9763 for (int Idx : Mask) {
9764 if (Idx < 0) {
9765 if (!Undef.isValid())
9766 Undef = MIRBuilder.buildUndef(EltTy).getReg(0);
9767 BuildVec.push_back(Undef);
9768 continue;
9769 }
9770
9771 assert(!Src0Ty.isScalar() && "Unexpected scalar G_SHUFFLE_VECTOR");
9772
9773 int NumElts = Src0Ty.getNumElements();
9774 Register SrcVec = Idx < NumElts ? Src0Reg : Src1Reg;
9775 int ExtractIdx = Idx < NumElts ? Idx : Idx - NumElts;
9776 auto [It, Inserted] = CachedExtract.try_emplace(Idx);
9777 if (Inserted) {
9778 auto IdxK = MIRBuilder.buildConstant(IdxTy, ExtractIdx);
9779 It->second =
9780 MIRBuilder.buildExtractVectorElement(EltTy, SrcVec, IdxK).getReg(0);
9781 }
9782 BuildVec.push_back(It->second);
9783 }
9784
9785 assert(DstTy.isVector() && "Unexpected scalar G_SHUFFLE_VECTOR");
9786 MIRBuilder.buildBuildVector(DstReg, BuildVec);
9787 MI.eraseFromParent();
9788 return Legalized;
9789}
9790
9793 auto [Dst, DstTy, Vec, VecTy, Mask, MaskTy, Passthru, PassthruTy] =
9794 MI.getFirst4RegLLTs();
9795
9796 if (VecTy.isScalableVector())
9797 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
9798
9799 Align VecAlign = getStackTemporaryAlignment(VecTy);
9800 MachinePointerInfo PtrInfo;
9801 Register StackPtr =
9802 createStackTemporary(TypeSize::getFixed(VecTy.getSizeInBytes()), VecAlign,
9803 PtrInfo)
9804 .getReg(0);
9805 MachinePointerInfo ValPtrInfo =
9807
9808 LLT IdxTy = LLT::integer(32);
9809 LLT ValTy = VecTy.getElementType();
9810 Align ValAlign = getStackTemporaryAlignment(ValTy);
9811
9812 auto OutPos = MIRBuilder.buildConstant(IdxTy, 0);
9813
9814 bool HasPassthru = !mi_match(Passthru, MRI, m_GImplicitDef());
9815
9816 if (HasPassthru)
9817 MIRBuilder.buildStore(Passthru, StackPtr, PtrInfo, VecAlign);
9818
9819 Register LastWriteVal;
9820 std::optional<APInt> PassthruSplatVal =
9821 isConstantOrConstantSplatVector(Passthru, MRI);
9822
9823 if (PassthruSplatVal.has_value()) {
9824 LastWriteVal =
9825 MIRBuilder.buildConstant(ValTy, PassthruSplatVal.value()).getReg(0);
9826 } else if (HasPassthru) {
9827 auto Popcount = MIRBuilder.buildZExt(MaskTy.changeElementSize(32), Mask);
9828 Popcount = MIRBuilder.buildInstr(TargetOpcode::G_VECREDUCE_ADD,
9829 {LLT::integer(32)}, {Popcount});
9830
9831 Register LastElmtPtr =
9832 getVectorElementPointer(StackPtr, VecTy, Popcount.getReg(0));
9833 LastWriteVal =
9834 MIRBuilder.buildLoad(ValTy, LastElmtPtr, ValPtrInfo, ValAlign)
9835 .getReg(0);
9836 }
9837
9838 unsigned NumElmts = VecTy.getNumElements();
9839 for (unsigned I = 0; I < NumElmts; ++I) {
9840 auto Idx = MIRBuilder.buildConstant(IdxTy, I);
9841 auto Val = MIRBuilder.buildExtractVectorElement(ValTy, Vec, Idx);
9842 Register ElmtPtr =
9843 getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9844 MIRBuilder.buildStore(Val, ElmtPtr, ValPtrInfo, ValAlign);
9845
9846 LLT MaskITy = MaskTy.getElementType();
9847 auto MaskI = MIRBuilder.buildExtractVectorElement(MaskITy, Mask, Idx);
9848 if (MaskITy.getSizeInBits() > 1)
9849 MaskI = MIRBuilder.buildTrunc(LLT::integer(1), MaskI);
9850
9851 MaskI = MIRBuilder.buildZExt(IdxTy, MaskI);
9852 OutPos = MIRBuilder.buildAdd(IdxTy, OutPos, MaskI);
9853
9854 if (HasPassthru && I == NumElmts - 1) {
9855 auto EndOfVector =
9856 MIRBuilder.buildConstant(IdxTy, VecTy.getNumElements() - 1);
9857 auto AllLanesSelected = MIRBuilder.buildICmp(
9858 CmpInst::ICMP_UGT, LLT::integer(1), OutPos, EndOfVector);
9859 OutPos = MIRBuilder.buildInstr(TargetOpcode::G_UMIN, {IdxTy},
9860 {OutPos, EndOfVector});
9861 ElmtPtr = getVectorElementPointer(StackPtr, VecTy, OutPos.getReg(0));
9862
9863 LastWriteVal =
9864 MIRBuilder.buildSelect(ValTy, AllLanesSelected, Val, LastWriteVal)
9865 .getReg(0);
9866 MIRBuilder.buildStore(LastWriteVal, ElmtPtr, ValPtrInfo, ValAlign);
9867 }
9868 }
9869
9870 // TODO: Use StackPtr's FrameIndex alignment.
9871 MIRBuilder.buildLoad(Dst, StackPtr, PtrInfo, VecAlign);
9872
9873 MI.eraseFromParent();
9874 return Legalized;
9875}
9876
9878 Register AllocSize,
9879 Align Alignment,
9880 LLT PtrTy) {
9882
9883 auto SPTmp = MIRBuilder.buildCopy(PtrTy, SPReg);
9884 SPTmp = MIRBuilder.buildCast(IntPtrTy, SPTmp);
9885
9886 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
9887 // have to generate an extra instruction to negate the alloc and then use
9888 // G_PTR_ADD to add the negative offset.
9889 auto Alloc = MIRBuilder.buildSub(IntPtrTy, SPTmp, AllocSize);
9890 if (Alignment > Align(1)) {
9891 APInt AlignMask(IntPtrTy.getSizeInBits(), Alignment.value(), true);
9892 AlignMask.negate();
9893 auto AlignCst = MIRBuilder.buildConstant(IntPtrTy, AlignMask);
9894 Alloc = MIRBuilder.buildAnd(IntPtrTy, Alloc, AlignCst);
9895 }
9896
9897 return MIRBuilder.buildCast(PtrTy, Alloc).getReg(0);
9898}
9899
9902 const auto &MF = *MI.getMF();
9903 const auto &TFI = *MF.getSubtarget().getFrameLowering();
9904 if (TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp)
9905 return UnableToLegalize;
9906
9907 Register Dst = MI.getOperand(0).getReg();
9908 Register AllocSize = MI.getOperand(1).getReg();
9909 Align Alignment = assumeAligned(MI.getOperand(2).getImm());
9910
9911 LLT PtrTy = MRI.getType(Dst);
9912 Register SPReg = TLI.getStackPointerRegisterToSaveRestore();
9913 Register SPTmp =
9914 getDynStackAllocTargetPtr(SPReg, AllocSize, Alignment, PtrTy);
9915
9916 MIRBuilder.buildCopy(SPReg, SPTmp);
9917 MIRBuilder.buildCopy(Dst, SPTmp);
9918
9919 MI.eraseFromParent();
9920 return Legalized;
9921}
9922
9925 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9926 if (!StackPtr)
9927 return UnableToLegalize;
9928
9929 MIRBuilder.buildCopy(MI.getOperand(0), StackPtr);
9930 MI.eraseFromParent();
9931 return Legalized;
9932}
9933
9936 Register StackPtr = TLI.getStackPointerRegisterToSaveRestore();
9937 if (!StackPtr)
9938 return UnableToLegalize;
9939
9940 MIRBuilder.buildCopy(StackPtr, MI.getOperand(0));
9941 MI.eraseFromParent();
9942 return Legalized;
9943}
9944
9947 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9948 unsigned Offset = MI.getOperand(2).getImm();
9949
9950 // Extract sub-vector or one element
9951 if (SrcTy.isVector()) {
9952 unsigned SrcEltSize = SrcTy.getElementType().getSizeInBits();
9953 unsigned DstSize = DstTy.getSizeInBits();
9954
9955 if ((Offset % SrcEltSize == 0) && (DstSize % SrcEltSize == 0) &&
9956 (Offset + DstSize <= SrcTy.getSizeInBits())) {
9957 // Unmerge and allow access to each Src element for the artifact combiner.
9958 auto Unmerge = MIRBuilder.buildUnmerge(SrcTy.getElementType(), SrcReg);
9959
9960 // Take element(s) we need to extract and copy it (merge them).
9961 SmallVector<Register, 8> SubVectorElts;
9962 for (unsigned Idx = Offset / SrcEltSize;
9963 Idx < (Offset + DstSize) / SrcEltSize; ++Idx) {
9964 SubVectorElts.push_back(Unmerge.getReg(Idx));
9965 }
9966 if (SubVectorElts.size() == 1)
9967 MIRBuilder.buildCopy(DstReg, SubVectorElts[0]);
9968 else
9969 MIRBuilder.buildMergeLikeInstr(DstReg, SubVectorElts);
9970
9971 MI.eraseFromParent();
9972 return Legalized;
9973 }
9974 }
9975
9976 const DataLayout &DL = MIRBuilder.getDataLayout();
9977 if ((SrcTy.isPointer() &&
9978 DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) ||
9979 (DstTy.isPointer() &&
9980 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace()))) {
9981 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
9982 return UnableToLegalize;
9983 }
9984
9985 if ((DstTy.isScalar() || DstTy.isPointer()) &&
9986 (SrcTy.isScalar() || SrcTy.isPointer() ||
9987 (SrcTy.isVector() && DstTy == SrcTy.getElementType()))) {
9988 LLT SrcIntTy = SrcTy;
9989 if (!SrcTy.isScalar()) {
9990 SrcIntTy = LLT::integer(SrcTy.getSizeInBits());
9991 SrcReg = MIRBuilder.buildCast(SrcIntTy, SrcReg).getReg(0);
9992 }
9993
9994 Register ResultReg = DstReg;
9995 if (DstTy.isPointer())
9996 ResultReg =
9997 MRI.createGenericVirtualRegister(LLT::integer(DstTy.getSizeInBits()));
9998
9999 if (Offset == 0)
10000 MIRBuilder.buildTrunc(ResultReg, SrcReg);
10001 else {
10002 auto ShiftAmt = MIRBuilder.buildConstant(SrcIntTy, Offset);
10003 auto Shr = MIRBuilder.buildLShr(SrcIntTy, SrcReg, ShiftAmt);
10004 MIRBuilder.buildTrunc(ResultReg, Shr);
10005 }
10006
10007 if (DstTy.isPointer())
10008 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
10009
10010 MI.eraseFromParent();
10011 return Legalized;
10012 }
10013
10014 return UnableToLegalize;
10015}
10016
10018 auto [Dst, Src, InsertSrc] = MI.getFirst3Regs();
10019 uint64_t Offset = MI.getOperand(3).getImm();
10020
10021 LLT DstTy = MRI.getType(Src);
10022 LLT InsertTy = MRI.getType(InsertSrc);
10023
10024 const DataLayout &DL = MIRBuilder.getDataLayout();
10025 bool IsNonIntegralInsert =
10026 InsertTy.isPointerOrPointerVector() &&
10027 DL.isNonIntegralAddressSpace(InsertTy.getAddressSpace());
10028 bool IsNonIntegralDst = DstTy.isPointerOrPointerVector() &&
10029 DL.isNonIntegralAddressSpace(DstTy.getAddressSpace());
10030
10031 // Insert sub-vector or one element
10032 if (DstTy.isVector()) {
10033 LLT EltTy = DstTy.getElementType();
10034
10035 if ((IsNonIntegralInsert || IsNonIntegralDst) && InsertTy != EltTy) {
10036 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
10037 return UnableToLegalize;
10038 }
10039
10040 unsigned EltSize = EltTy.getSizeInBits();
10041 unsigned InsertSize = InsertTy.getSizeInBits();
10042
10043 if ((Offset % EltSize == 0) && (InsertSize % EltSize == 0) &&
10044 (Offset + InsertSize <= DstTy.getSizeInBits())) {
10045 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, Src);
10047 unsigned Idx = 0;
10048 // Elements from Src before insert start Offset
10049 for (; Idx < Offset / EltSize; ++Idx) {
10050 DstElts.push_back(UnmergeSrc.getReg(Idx));
10051 }
10052
10053 // Replace elements in Src with elements from InsertSrc
10054 if (InsertTy.getSizeInBits() > EltSize) {
10055 auto UnmergeInsertSrc = MIRBuilder.buildUnmerge(EltTy, InsertSrc);
10056 for (unsigned i = 0; Idx < (Offset + InsertSize) / EltSize;
10057 ++Idx, ++i) {
10058 DstElts.push_back(UnmergeInsertSrc.getReg(i));
10059 }
10060 } else {
10061 if (InsertTy.isPointer() && !EltTy.isPointer())
10062 InsertSrc = MIRBuilder.buildPtrToInt(EltTy, InsertSrc).getReg(0);
10063 else if (!InsertTy.isPointer() && EltTy.isPointer())
10064 InsertSrc = MIRBuilder.buildIntToPtr(EltTy, InsertSrc).getReg(0);
10065 DstElts.push_back(InsertSrc);
10066 ++Idx;
10067 }
10068
10069 // Remaining elements from Src after insert
10070 for (; Idx < DstTy.getNumElements(); ++Idx) {
10071 DstElts.push_back(UnmergeSrc.getReg(Idx));
10072 }
10073
10074 MIRBuilder.buildMergeLikeInstr(Dst, DstElts);
10075 MI.eraseFromParent();
10076 return Legalized;
10077 }
10078 }
10079
10080 if (InsertTy.isVector() ||
10081 (DstTy.isVector() && DstTy.getElementType() != InsertTy))
10082 return UnableToLegalize;
10083
10084 if (IsNonIntegralDst || IsNonIntegralInsert) {
10085 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
10086 return UnableToLegalize;
10087 }
10088
10089 LLT IntDstTy = DstTy;
10090
10091 if (!DstTy.isScalar()) {
10092 IntDstTy = LLT::scalar(DstTy.getSizeInBits());
10093 Src = MIRBuilder.buildCast(IntDstTy, Src).getReg(0);
10094 }
10095
10096 if (!InsertTy.isScalar()) {
10097 const LLT IntInsertTy = LLT::scalar(InsertTy.getSizeInBits());
10098 InsertSrc = MIRBuilder.buildPtrToInt(IntInsertTy, InsertSrc).getReg(0);
10099 }
10100
10101 Register ExtInsSrc = MIRBuilder.buildZExt(IntDstTy, InsertSrc).getReg(0);
10102 if (Offset != 0) {
10103 auto ShiftAmt = MIRBuilder.buildConstant(IntDstTy, Offset);
10104 ExtInsSrc = MIRBuilder.buildShl(IntDstTy, ExtInsSrc, ShiftAmt).getReg(0);
10105 }
10106
10108 DstTy.getSizeInBits(), Offset + InsertTy.getSizeInBits(), Offset);
10109
10110 auto Mask = MIRBuilder.buildConstant(IntDstTy, MaskVal);
10111 auto MaskedSrc = MIRBuilder.buildAnd(IntDstTy, Src, Mask);
10112 auto Or = MIRBuilder.buildOr(IntDstTy, MaskedSrc, ExtInsSrc);
10113
10114 MIRBuilder.buildCast(Dst, Or);
10115 MI.eraseFromParent();
10116 return Legalized;
10117}
10118
10121 auto [Dst0, Dst0Ty, Dst1, Dst1Ty, LHS, LHSTy, RHS, RHSTy] =
10122 MI.getFirst4RegLLTs();
10123 const bool IsAdd = MI.getOpcode() == TargetOpcode::G_SADDO;
10124
10125 LLT Ty = Dst0Ty;
10126 LLT BoolTy = Dst1Ty;
10127
10128 Register NewDst0 = MRI.cloneVirtualRegister(Dst0);
10129
10130 if (IsAdd)
10131 MIRBuilder.buildAdd(NewDst0, LHS, RHS);
10132 else
10133 MIRBuilder.buildSub(NewDst0, LHS, RHS);
10134
10135 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
10136
10137 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10138
10139 if (IsAdd) {
10140 // For an addition, the result should be less than one of the operands (LHS)
10141 // if and only if the other operand (RHS) is negative, otherwise there will
10142 // be overflow.
10143 auto ResultLowerThanLHS =
10144 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, LHS);
10145 auto RHSNegative =
10146 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, RHS, Zero);
10147 MIRBuilder.buildXor(Dst1, RHSNegative, ResultLowerThanLHS);
10148 } else {
10149 // For subtraction, overflow occurs when the signed comparison of operands
10150 // doesn't match the sign of the result.
10151 auto LHSLessThanRHS =
10152 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS, RHS);
10153 auto ResultNegative =
10154 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, NewDst0, Zero);
10155 MIRBuilder.buildXor(Dst1, LHSLessThanRHS, ResultNegative);
10156 }
10157
10158 MIRBuilder.buildCopy(Dst0, NewDst0);
10159 MI.eraseFromParent();
10160
10161 return Legalized;
10162}
10163
10165 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10166 const LLT Ty = MRI.getType(Res);
10167
10168 // sum = LHS + RHS + zext(CarryIn)
10169 auto Tmp = MIRBuilder.buildAdd(Ty, LHS, RHS);
10170 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10171 auto Sum = MIRBuilder.buildAdd(Ty, Tmp, CarryZ);
10172 MIRBuilder.buildCopy(Res, Sum);
10173
10174 // OvOut = icmp slt ((sum ^ lhs) & (sum ^ rhs)), 0
10175 auto AX = MIRBuilder.buildXor(Ty, Sum, LHS);
10176 auto BX = MIRBuilder.buildXor(Ty, Sum, RHS);
10177 auto T = MIRBuilder.buildAnd(Ty, AX, BX);
10178
10179 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10180 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10181
10182 MI.eraseFromParent();
10183 return Legalized;
10184}
10185
10187 auto [Res, OvOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
10188 const LLT Ty = MRI.getType(Res);
10189
10190 // Diff = LHS - (RHS + zext(CarryIn))
10191 auto CarryZ = MIRBuilder.buildZExt(Ty, CarryIn);
10192 auto RHSPlusCI = MIRBuilder.buildAdd(Ty, RHS, CarryZ);
10193 auto Diff = MIRBuilder.buildSub(Ty, LHS, RHSPlusCI);
10194 MIRBuilder.buildCopy(Res, Diff);
10195
10196 // ov = msb((LHS ^ RHS) & (LHS ^ Diff))
10197 auto X1 = MIRBuilder.buildXor(Ty, LHS, RHS);
10198 auto X2 = MIRBuilder.buildXor(Ty, LHS, Diff);
10199 auto T = MIRBuilder.buildAnd(Ty, X1, X2);
10200 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10201 MIRBuilder.buildICmp(CmpInst::ICMP_SLT, OvOut, T, Zero);
10202
10203 MI.eraseFromParent();
10204 return Legalized;
10205}
10206
10209 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10210 LLT Ty = MRI.getType(Res);
10211 bool IsSigned;
10212 bool IsAdd;
10213 unsigned BaseOp;
10214 switch (MI.getOpcode()) {
10215 default:
10216 llvm_unreachable("unexpected addsat/subsat opcode");
10217 case TargetOpcode::G_UADDSAT:
10218 IsSigned = false;
10219 IsAdd = true;
10220 BaseOp = TargetOpcode::G_ADD;
10221 break;
10222 case TargetOpcode::G_SADDSAT:
10223 IsSigned = true;
10224 IsAdd = true;
10225 BaseOp = TargetOpcode::G_ADD;
10226 break;
10227 case TargetOpcode::G_USUBSAT:
10228 IsSigned = false;
10229 IsAdd = false;
10230 BaseOp = TargetOpcode::G_SUB;
10231 break;
10232 case TargetOpcode::G_SSUBSAT:
10233 IsSigned = true;
10234 IsAdd = false;
10235 BaseOp = TargetOpcode::G_SUB;
10236 break;
10237 }
10238
10239 if (IsSigned) {
10240 // sadd.sat(a, b) ->
10241 // hi = 0x7fffffff - smax(a, 0)
10242 // lo = 0x80000000 - smin(a, 0)
10243 // a + smin(smax(lo, b), hi)
10244 // ssub.sat(a, b) ->
10245 // lo = smax(a, -1) - 0x7fffffff
10246 // hi = smin(a, -1) - 0x80000000
10247 // a - smin(smax(lo, b), hi)
10248 // TODO: AMDGPU can use a "median of 3" instruction here:
10249 // a +/- med3(lo, b, hi)
10250 uint64_t NumBits = Ty.getScalarSizeInBits();
10251 auto MaxVal =
10252 MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(NumBits));
10253 auto MinVal =
10254 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10256 if (IsAdd) {
10257 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10258 Hi = MIRBuilder.buildSub(Ty, MaxVal, MIRBuilder.buildSMax(Ty, LHS, Zero));
10259 Lo = MIRBuilder.buildSub(Ty, MinVal, MIRBuilder.buildSMin(Ty, LHS, Zero));
10260 } else {
10261 auto NegOne = MIRBuilder.buildConstant(Ty, -1);
10262 Lo = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMax(Ty, LHS, NegOne),
10263 MaxVal);
10264 Hi = MIRBuilder.buildSub(Ty, MIRBuilder.buildSMin(Ty, LHS, NegOne),
10265 MinVal);
10266 }
10267 auto RHSClamped =
10268 MIRBuilder.buildSMin(Ty, MIRBuilder.buildSMax(Ty, Lo, RHS), Hi);
10269 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, RHSClamped});
10270 } else {
10271 // uadd.sat(a, b) -> a + umin(~a, b)
10272 // usub.sat(a, b) -> a - umin(a, b)
10273 Register Not = IsAdd ? MIRBuilder.buildNot(Ty, LHS).getReg(0) : LHS;
10274 auto Min = MIRBuilder.buildUMin(Ty, Not, RHS);
10275 MIRBuilder.buildInstr(BaseOp, {Res}, {LHS, Min});
10276 }
10277
10278 MI.eraseFromParent();
10279 return Legalized;
10280}
10281
10284 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10285 LLT Ty = MRI.getType(Res);
10286 LLT BoolTy = Ty.changeElementSize(1);
10287 bool IsSigned;
10288 bool IsAdd;
10289 unsigned OverflowOp;
10290 switch (MI.getOpcode()) {
10291 default:
10292 llvm_unreachable("unexpected addsat/subsat opcode");
10293 case TargetOpcode::G_UADDSAT:
10294 IsSigned = false;
10295 IsAdd = true;
10296 OverflowOp = TargetOpcode::G_UADDO;
10297 break;
10298 case TargetOpcode::G_SADDSAT:
10299 IsSigned = true;
10300 IsAdd = true;
10301 OverflowOp = TargetOpcode::G_SADDO;
10302 break;
10303 case TargetOpcode::G_USUBSAT:
10304 IsSigned = false;
10305 IsAdd = false;
10306 OverflowOp = TargetOpcode::G_USUBO;
10307 break;
10308 case TargetOpcode::G_SSUBSAT:
10309 IsSigned = true;
10310 IsAdd = false;
10311 OverflowOp = TargetOpcode::G_SSUBO;
10312 break;
10313 }
10314
10315 auto OverflowRes =
10316 MIRBuilder.buildInstr(OverflowOp, {Ty, BoolTy}, {LHS, RHS});
10317 Register Tmp = OverflowRes.getReg(0);
10318 Register Ov = OverflowRes.getReg(1);
10319 MachineInstrBuilder Clamp;
10320 if (IsSigned) {
10321 // sadd.sat(a, b) ->
10322 // {tmp, ov} = saddo(a, b)
10323 // ov ? (tmp >>s 31) + 0x80000000 : r
10324 // ssub.sat(a, b) ->
10325 // {tmp, ov} = ssubo(a, b)
10326 // ov ? (tmp >>s 31) + 0x80000000 : r
10327 uint64_t NumBits = Ty.getScalarSizeInBits();
10328 auto ShiftAmount = MIRBuilder.buildConstant(Ty, NumBits - 1);
10329 auto Sign = MIRBuilder.buildAShr(Ty, Tmp, ShiftAmount);
10330 auto MinVal =
10331 MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(NumBits));
10332 Clamp = MIRBuilder.buildAdd(Ty, Sign, MinVal);
10333 } else {
10334 // uadd.sat(a, b) ->
10335 // {tmp, ov} = uaddo(a, b)
10336 // ov ? 0xffffffff : tmp
10337 // usub.sat(a, b) ->
10338 // {tmp, ov} = usubo(a, b)
10339 // ov ? 0 : tmp
10340 Clamp = MIRBuilder.buildConstant(Ty, IsAdd ? -1 : 0);
10341 }
10342 MIRBuilder.buildSelect(Res, Ov, Clamp, Tmp);
10343
10344 MI.eraseFromParent();
10345 return Legalized;
10346}
10347
10350 assert((MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
10351 MI.getOpcode() == TargetOpcode::G_USHLSAT) &&
10352 "Expected shlsat opcode!");
10353 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SSHLSAT;
10354 auto [Res, LHS, RHS] = MI.getFirst3Regs();
10355 LLT Ty = MRI.getType(Res);
10356 LLT BoolTy = Ty.changeElementSize(1);
10357
10358 unsigned BW = Ty.getScalarSizeInBits();
10359 auto Result = MIRBuilder.buildShl(Ty, LHS, RHS);
10360 auto Orig = IsSigned ? MIRBuilder.buildAShr(Ty, Result, RHS)
10361 : MIRBuilder.buildLShr(Ty, Result, RHS);
10362
10363 MachineInstrBuilder SatVal;
10364 if (IsSigned) {
10365 auto SatMin = MIRBuilder.buildConstant(Ty, APInt::getSignedMinValue(BW));
10366 auto SatMax = MIRBuilder.buildConstant(Ty, APInt::getSignedMaxValue(BW));
10367 auto Cmp = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, BoolTy, LHS,
10368 MIRBuilder.buildConstant(Ty, 0));
10369 SatVal = MIRBuilder.buildSelect(Ty, Cmp, SatMin, SatMax);
10370 } else {
10371 SatVal = MIRBuilder.buildConstant(Ty, APInt::getMaxValue(BW));
10372 }
10373 auto Ov = MIRBuilder.buildICmp(CmpInst::ICMP_NE, BoolTy, LHS, Orig);
10374 MIRBuilder.buildSelect(Res, Ov, SatVal, Result);
10375
10376 MI.eraseFromParent();
10377 return Legalized;
10378}
10379
10382 unsigned Opc = MI.getOpcode();
10383 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
10384 unsigned DstSize = DstTy.getScalarSizeInBits();
10385 unsigned SrcSize = SrcTy.getScalarSizeInBits();
10386
10387 if (Opc == TargetOpcode::G_TRUNC_SSAT_S) {
10388 auto Max = MIRBuilder.buildConstant(
10389 SrcTy, APInt::getSignedMaxValue(DstSize).sext(SrcSize));
10390 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10391 auto Min = MIRBuilder.buildConstant(
10392 SrcTy, APInt::getSignedMinValue(DstSize).sext(SrcSize));
10393 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10394 } else if (Opc == TargetOpcode::G_TRUNC_USAT_U) {
10395 auto Max = MIRBuilder.buildConstant(
10396 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10397 Src = MIRBuilder.buildUMin(SrcTy, Src, Max).getReg(0);
10398 } else if (Opc == TargetOpcode::G_TRUNC_SSAT_U) {
10399 auto Max = MIRBuilder.buildConstant(
10400 SrcTy, APInt::getAllOnes(DstSize).zext(SrcSize));
10401 Src = MIRBuilder.buildSMin(SrcTy, Src, Max).getReg(0);
10402 auto Min = MIRBuilder.buildConstant(SrcTy, APInt::getZero(SrcSize));
10403 Src = MIRBuilder.buildSMax(SrcTy, Src, Min).getReg(0);
10404 } else {
10405 llvm_unreachable("Expected truncsat opcode!");
10406 }
10407
10408 MIRBuilder.buildTrunc(Dst, Src);
10409 MI.eraseFromParent();
10410 return Legalized;
10411}
10412
10414 auto [Dst, Src] = MI.getFirst2Regs();
10415 const LLT Ty = MRI.getType(Src);
10416 unsigned SizeInBytes = (Ty.getScalarSizeInBits() + 7) / 8;
10417 unsigned BaseShiftAmt = (SizeInBytes - 1) * 8;
10418
10419 // Swap most and least significant byte, set remaining bytes in Res to zero.
10420 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt);
10421 auto LSByteShiftedLeft = MIRBuilder.buildShl(Ty, Src, ShiftAmt);
10422 auto MSByteShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10423 auto Res = MIRBuilder.buildOr(Ty, MSByteShiftedRight, LSByteShiftedLeft);
10424
10425 // Set i-th high/low byte in Res to i-th low/high byte from Src.
10426 for (unsigned i = 1; i < SizeInBytes / 2; ++i) {
10427 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
10428 APInt APMask = APInt::getBitsSet(SizeInBytes * 8, i * 8, i * 8 + 8);
10429 auto Mask = MIRBuilder.buildConstant(Ty, APMask);
10430 auto ShiftAmt = MIRBuilder.buildConstant(Ty, BaseShiftAmt - 16 * i);
10431 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
10432 auto LoByte = MIRBuilder.buildAnd(Ty, Src, Mask);
10433 auto LoShiftedLeft = MIRBuilder.buildShl(Ty, LoByte, ShiftAmt);
10434 Res = MIRBuilder.buildOr(Ty, Res, LoShiftedLeft);
10435 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
10436 auto SrcShiftedRight = MIRBuilder.buildLShr(Ty, Src, ShiftAmt);
10437 auto HiShiftedRight = MIRBuilder.buildAnd(Ty, SrcShiftedRight, Mask);
10438 Res = MIRBuilder.buildOr(Ty, Res, HiShiftedRight);
10439 }
10440 Res.getInstr()->getOperand(0).setReg(Dst);
10441
10442 MI.eraseFromParent();
10443 return Legalized;
10444}
10445
10446//{ (Src & Mask) >> N } | { (Src << N) & Mask }
10448 MachineInstrBuilder Src, const APInt &Mask) {
10449 const LLT Ty = Dst.getLLTTy(*B.getMRI());
10450 MachineInstrBuilder C_N = B.buildConstant(Ty, N);
10451 MachineInstrBuilder MaskLoNTo0 = B.buildConstant(Ty, Mask);
10452 auto LHS = B.buildLShr(Ty, B.buildAnd(Ty, Src, MaskLoNTo0), C_N);
10453 auto RHS = B.buildAnd(Ty, B.buildShl(Ty, Src, C_N), MaskLoNTo0);
10454 return B.buildOr(Dst, LHS, RHS);
10455}
10456
10459 auto [Dst, Src] = MI.getFirst2Regs();
10460 const LLT SrcTy = MRI.getType(Src);
10461 unsigned Size = SrcTy.getScalarSizeInBits();
10462 unsigned VSize = SrcTy.getSizeInBits();
10463
10464 if (Size >= 8) {
10465 if (SrcTy.isVector() && (VSize % 8 == 0) &&
10466 (LI.isLegal({TargetOpcode::G_BITREVERSE,
10467 {LLT::fixed_vector(VSize / 8, LLT::integer(8)),
10468 LLT::fixed_vector(VSize / 8, LLT::integer(8))}}))) {
10469 // If bitreverse is legal for i8 vector of the same size, then cast
10470 // to i8 vector type.
10471 // e.g. v4s32 -> v16s8
10472 LLT VTy = LLT::fixed_vector(VSize / 8, LLT::integer(8));
10473 auto BSWAP = MIRBuilder.buildBSwap(SrcTy, Src);
10474 auto Cast = MIRBuilder.buildBitcast(VTy, BSWAP);
10475 auto RBIT = MIRBuilder.buildBitReverse(VTy, Cast);
10476 MIRBuilder.buildBitcast(Dst, RBIT);
10477 } else {
10478 MachineInstrBuilder BSWAP =
10479 MIRBuilder.buildInstr(TargetOpcode::G_BSWAP, {SrcTy}, {Src});
10480
10481 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
10482 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
10483 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
10484 MachineInstrBuilder Swap4 = SwapN(4, SrcTy, MIRBuilder, BSWAP,
10485 APInt::getSplat(Size, APInt(8, 0xF0)));
10486
10487 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
10488 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
10489 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
10490 MachineInstrBuilder Swap2 = SwapN(2, SrcTy, MIRBuilder, Swap4,
10491 APInt::getSplat(Size, APInt(8, 0xCC)));
10492
10493 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
10494 // 6|7
10495 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
10496 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
10497 SwapN(1, Dst, MIRBuilder, Swap2, APInt::getSplat(Size, APInt(8, 0xAA)));
10498 }
10499 } else {
10500 // Expand bitreverse for types smaller than 8 bits.
10502 for (unsigned I = 0, J = Size - 1; I < Size; ++I, --J) {
10504 if (I < J) {
10505 auto ShAmt = MIRBuilder.buildConstant(SrcTy, J - I);
10506 Tmp2 = MIRBuilder.buildShl(SrcTy, Src, ShAmt);
10507 } else {
10508 auto ShAmt = MIRBuilder.buildConstant(SrcTy, I - J);
10509 Tmp2 = MIRBuilder.buildLShr(SrcTy, Src, ShAmt);
10510 }
10511
10512 auto Mask = MIRBuilder.buildConstant(SrcTy, 1ULL << J);
10513 Tmp2 = MIRBuilder.buildAnd(SrcTy, Tmp2, Mask);
10514 if (I == 0)
10515 Tmp = Tmp2;
10516 else
10517 Tmp = MIRBuilder.buildOr(SrcTy, Tmp, Tmp2);
10518 }
10519 MIRBuilder.buildCopy(Dst, Tmp);
10520 }
10521
10522 MI.eraseFromParent();
10523 return Legalized;
10524}
10525
10528 MachineFunction &MF = MIRBuilder.getMF();
10529
10530 bool IsRead = MI.getOpcode() == TargetOpcode::G_READ_REGISTER;
10531 int NameOpIdx = IsRead ? 1 : 0;
10532 int ValRegIndex = IsRead ? 0 : 1;
10533
10534 Register ValReg = MI.getOperand(ValRegIndex).getReg();
10535 const LLT Ty = MRI.getType(ValReg);
10536 const MDString *RegStr = cast<MDString>(
10537 cast<MDNode>(MI.getOperand(NameOpIdx).getMetadata())->getOperand(0));
10538
10539 Register PhysReg = TLI.getRegisterByName(RegStr->getString().data(), Ty, MF);
10540 if (!PhysReg) {
10541 const Function &Fn = MF.getFunction();
10543 "invalid register \"" + Twine(RegStr->getString().data()) + "\" for " +
10544 (IsRead ? "llvm.read_register" : "llvm.write_register"),
10545 Fn, MI.getDebugLoc()));
10546 if (IsRead)
10547 MIRBuilder.buildUndef(ValReg);
10548
10549 MI.eraseFromParent();
10550 return Legalized;
10551 }
10552
10553 if (IsRead)
10554 MIRBuilder.buildCopy(ValReg, PhysReg);
10555 else
10556 MIRBuilder.buildCopy(PhysReg, ValReg);
10557
10558 MI.eraseFromParent();
10559 return Legalized;
10560}
10561
10564 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULH;
10565 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
10566 Register Result = MI.getOperand(0).getReg();
10567 LLT OrigTy = MRI.getType(Result);
10568 auto SizeInBits = OrigTy.getScalarSizeInBits();
10569 LLT WideTy = OrigTy.changeElementSize(SizeInBits * 2);
10570
10571 auto LHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(1)});
10572 auto RHS = MIRBuilder.buildInstr(ExtOp, {WideTy}, {MI.getOperand(2)});
10573 auto Mul = MIRBuilder.buildMul(WideTy, LHS, RHS);
10574 unsigned ShiftOp = IsSigned ? TargetOpcode::G_ASHR : TargetOpcode::G_LSHR;
10575
10576 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, SizeInBits);
10577 auto Shifted = MIRBuilder.buildInstr(ShiftOp, {WideTy}, {Mul, ShiftAmt});
10578 MIRBuilder.buildTrunc(Result, Shifted);
10579
10580 MI.eraseFromParent();
10581 return Legalized;
10582}
10583
10586 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10587 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
10588
10589 if (Mask == fcNone) {
10590 MIRBuilder.buildConstant(DstReg, 0);
10591 MI.eraseFromParent();
10592 return Legalized;
10593 }
10594 if (Mask == fcAllFlags) {
10595 MIRBuilder.buildConstant(DstReg, 1);
10596 MI.eraseFromParent();
10597 return Legalized;
10598 }
10599
10600 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
10601 // version
10602
10603 unsigned BitSize = SrcTy.getScalarSizeInBits();
10604 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
10605
10606 LLT IntTy = SrcTy.changeElementType(LLT::integer(BitSize));
10607 auto AsInt = SrcTy == IntTy ? MIRBuilder.buildCopy(IntTy, SrcReg)
10608 : MIRBuilder.buildBitcast(IntTy, SrcReg);
10609
10610 // Various masks.
10611 APInt SignBit = APInt::getSignMask(BitSize);
10612 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
10613 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
10614 APInt ExpMask = Inf;
10615 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
10616 APInt QNaNBitMask =
10617 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
10618 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
10619
10620 auto SignBitC = MIRBuilder.buildConstant(IntTy, SignBit);
10621 auto ValueMaskC = MIRBuilder.buildConstant(IntTy, ValueMask);
10622 auto InfC = MIRBuilder.buildConstant(IntTy, Inf);
10623 auto ExpMaskC = MIRBuilder.buildConstant(IntTy, ExpMask);
10624 auto ZeroC = MIRBuilder.buildConstant(IntTy, 0);
10625
10626 auto Abs = MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC);
10627 auto Sign =
10628 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs);
10629
10630 auto Res = MIRBuilder.buildConstant(DstTy, 0);
10631 // Clang doesn't support capture of structured bindings:
10632 LLT DstTyCopy = DstTy;
10633 const auto appendToRes = [&](MachineInstrBuilder ToAppend) {
10634 Res = MIRBuilder.buildOr(DstTyCopy, Res, ToAppend);
10635 };
10636
10637 // Tests that involve more than one class should be processed first.
10638 if ((Mask & fcFinite) == fcFinite) {
10639 // finite(V) ==> abs(V) u< exp_mask
10640 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10641 ExpMaskC));
10642 Mask &= ~fcFinite;
10643 } else if ((Mask & fcFinite) == fcPosFinite) {
10644 // finite(V) && V > 0 ==> V u< exp_mask
10645 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
10646 ExpMaskC));
10647 Mask &= ~fcPosFinite;
10648 } else if ((Mask & fcFinite) == fcNegFinite) {
10649 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
10650 auto Cmp = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
10651 ExpMaskC);
10652 auto And = MIRBuilder.buildAnd(DstTy, Cmp, Sign);
10653 appendToRes(And);
10654 Mask &= ~fcNegFinite;
10655 }
10656
10657 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
10658 // fcZero | fcSubnormal => test all exponent bits are 0
10659 // TODO: Handle sign bit specific cases
10660 // TODO: Handle inverted case
10661 if (PartialCheck == (fcZero | fcSubnormal)) {
10662 auto ExpBits = MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC);
10663 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10664 ExpBits, ZeroC));
10665 Mask &= ~PartialCheck;
10666 }
10667 }
10668
10669 // Check for individual classes.
10670 if (FPClassTest PartialCheck = Mask & fcZero) {
10671 if (PartialCheck == fcPosZero)
10672 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10673 AsInt, ZeroC));
10674 else if (PartialCheck == fcZero)
10675 appendToRes(
10676 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
10677 else // fcNegZero
10678 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10679 AsInt, SignBitC));
10680 }
10681
10682 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
10683 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
10684 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
10685 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
10686 auto OneC = MIRBuilder.buildConstant(IntTy, 1);
10687 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
10688 auto SubnormalRes =
10689 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
10690 MIRBuilder.buildConstant(IntTy, AllOneMantissa));
10691 if (PartialCheck == fcNegSubnormal)
10692 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
10693 appendToRes(SubnormalRes);
10694 }
10695
10696 if (FPClassTest PartialCheck = Mask & fcInf) {
10697 if (PartialCheck == fcPosInf)
10698 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10699 AsInt, InfC));
10700 else if (PartialCheck == fcInf)
10701 appendToRes(
10702 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
10703 else { // fcNegInf
10704 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
10705 auto NegInfC = MIRBuilder.buildConstant(IntTy, NegInf);
10706 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
10707 AsInt, NegInfC));
10708 }
10709 }
10710
10711 if (FPClassTest PartialCheck = Mask & fcNan) {
10712 auto InfWithQnanBitC = MIRBuilder.buildConstant(IntTy, Inf | QNaNBitMask);
10713 if (PartialCheck == fcNan) {
10714 // isnan(V) ==> abs(V) u> int(inf)
10715 appendToRes(
10716 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
10717 } else if (PartialCheck == fcQNan) {
10718 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
10719 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
10720 InfWithQnanBitC));
10721 } else { // fcSNan
10722 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
10723 // abs(V) u< (unsigned(Inf) | quiet_bit)
10724 auto IsNan =
10725 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC);
10726 auto IsNotQnan = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy,
10727 Abs, InfWithQnanBitC);
10728 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
10729 }
10730 }
10731
10732 if (FPClassTest PartialCheck = Mask & fcNormal) {
10733 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
10734 // (max_exp-1))
10735 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
10736 auto ExpMinusOne = MIRBuilder.buildSub(
10737 IntTy, Abs, MIRBuilder.buildConstant(IntTy, ExpLSB));
10738 APInt MaxExpMinusOne = ExpMask - ExpLSB;
10739 auto NormalRes =
10740 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
10741 MIRBuilder.buildConstant(IntTy, MaxExpMinusOne));
10742 if (PartialCheck == fcNegNormal)
10743 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
10744 else if (PartialCheck == fcPosNormal) {
10745 auto PosSign = MIRBuilder.buildXor(
10746 DstTy, Sign, MIRBuilder.buildConstant(DstTy, InversionMask));
10747 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
10748 }
10749 appendToRes(NormalRes);
10750 }
10751
10752 MIRBuilder.buildCopy(DstReg, Res);
10753 MI.eraseFromParent();
10754 return Legalized;
10755}
10756
10758 // Implement G_SELECT in terms of XOR, AND, OR.
10759 auto [DstReg, DstTy, MaskReg, MaskTy, Op1Reg, Op1Ty, Op2Reg, Op2Ty] =
10760 MI.getFirst4RegLLTs();
10761
10762 LLT Op1TyInt =
10763 Op1Ty.changeElementType(LLT::integer(Op1Ty.getScalarSizeInBits()));
10764
10765 bool IsEltPtr = DstTy.isPointerOrPointerVector();
10766 if (IsEltPtr) {
10767 LLT ScalarPtrTy = LLT::integer(DstTy.getScalarSizeInBits());
10768 LLT NewTy = DstTy.changeElementType(ScalarPtrTy);
10769 Op1Reg = MIRBuilder.buildPtrToInt(NewTy, Op1Reg).getReg(0);
10770 Op1Ty = MRI.getType(Op1Reg);
10771 Op2Reg = MIRBuilder.buildPtrToInt(NewTy, Op2Reg).getReg(0);
10772 Op2Ty = MRI.getType(Op2Reg);
10773 DstTy = NewTy;
10774 }
10775
10776 if (MaskTy.isScalar()) {
10777 // Turn the scalar condition into a vector condition mask if needed.
10778
10779 Register MaskElt = MaskReg;
10780
10781 // The condition was potentially zero extended before, but we want a sign
10782 // extended boolean.
10783 if (MaskTy != LLT::scalar(1))
10784 MaskElt = MIRBuilder.buildSExtInReg(MaskTy, MaskElt, 1).getReg(0);
10785
10786 // Continue the sign extension (or truncate) to match the data type.
10787 MaskTy = DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10788 MaskElt =
10789 MIRBuilder.buildSExtOrTrunc(MaskTy.getScalarType(), MaskElt).getReg(0);
10790
10791 if (DstTy.isVector()) {
10792 // Generate a vector splat idiom.
10793 auto ShufSplat = MIRBuilder.buildShuffleSplat(MaskTy, MaskElt);
10794 MaskReg = ShufSplat.getReg(0);
10795 } else {
10796 MaskReg = MaskElt;
10797 }
10798 } else if (!DstTy.isVector()) {
10799 // Cannot handle the case that mask is a vector and dst is a scalar.
10800 return UnableToLegalize;
10801 }
10802
10803 if (MaskTy.getSizeInBits() != DstTy.getSizeInBits()) {
10804 return UnableToLegalize;
10805 }
10806
10807 if (!Op1Ty.getScalarType().isAnyScalar() &&
10808 !Op1Ty.getScalarType().isInteger())
10809 Op1Reg = MIRBuilder.buildBitcast(Op1TyInt, Op1Reg).getReg(0);
10810
10811 if (!Op2Ty.getScalarType().isAnyScalar() &&
10812 !Op2Ty.getScalarType().isInteger()) {
10813 auto Op2TyInt =
10814 Op2Ty.changeElementType(LLT::integer(Op2Ty.getScalarSizeInBits()));
10815 Op2Reg = MIRBuilder.buildBitcast(Op2TyInt, Op2Reg).getReg(0);
10816 }
10817
10818 auto NotMask = MIRBuilder.buildNot(MaskTy, MaskReg);
10819 auto NewOp1 = MIRBuilder.buildAnd(MaskTy, Op1Reg, MaskReg);
10820 auto NewOp2 = MIRBuilder.buildAnd(MaskTy, Op2Reg, NotMask);
10821 if (IsEltPtr) {
10822 auto Or = MIRBuilder.buildOr(DstTy, NewOp1, NewOp2);
10823 MIRBuilder.buildIntToPtr(DstReg, Or);
10824 } else {
10825 if (DstTy == Op1TyInt)
10826 MIRBuilder.buildOr(DstReg, NewOp1, NewOp2);
10827 else {
10828 auto Or = MIRBuilder.buildOr(Op1TyInt, NewOp1, NewOp2);
10829 MIRBuilder.buildBitcast(DstReg, Or.getReg(0));
10830 }
10831 }
10832 MI.eraseFromParent();
10833 return Legalized;
10834}
10835
10837 // Split DIVREM into individual instructions.
10838 unsigned Opcode = MI.getOpcode();
10839
10840 MIRBuilder.buildInstr(
10841 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SDIV
10842 : TargetOpcode::G_UDIV,
10843 {MI.getOperand(0).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10844 MIRBuilder.buildInstr(
10845 Opcode == TargetOpcode::G_SDIVREM ? TargetOpcode::G_SREM
10846 : TargetOpcode::G_UREM,
10847 {MI.getOperand(1).getReg()}, {MI.getOperand(2), MI.getOperand(3)});
10848 MI.eraseFromParent();
10849 return Legalized;
10850}
10851
10854 // Expand %res = G_ABS %a into:
10855 // %v1 = G_ASHR %a, scalar_size-1
10856 // %v2 = G_ADD %a, %v1
10857 // %res = G_XOR %v2, %v1
10858 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
10859 Register OpReg = MI.getOperand(1).getReg();
10860 auto ShiftAmt =
10861 MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - 1);
10862 auto Shift = MIRBuilder.buildAShr(DstTy, OpReg, ShiftAmt);
10863 auto Add = MIRBuilder.buildAdd(DstTy, OpReg, Shift);
10864 MIRBuilder.buildXor(MI.getOperand(0).getReg(), Add, Shift);
10865 MI.eraseFromParent();
10866 return Legalized;
10867}
10868
10871 // Expand %res = G_ABS %a into:
10872 // %v1 = G_CONSTANT 0
10873 // %v2 = G_SUB %v1, %a
10874 // %res = G_SMAX %a, %v2
10875 Register SrcReg = MI.getOperand(1).getReg();
10876 LLT Ty = MRI.getType(SrcReg);
10877 auto Zero = MIRBuilder.buildConstant(Ty, 0);
10878 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg);
10879 MIRBuilder.buildSMax(MI.getOperand(0), SrcReg, Sub);
10880 MI.eraseFromParent();
10881 return Legalized;
10882}
10883
10886 Register SrcReg = MI.getOperand(1).getReg();
10887 Register DestReg = MI.getOperand(0).getReg();
10888 LLT Ty = MRI.getType(SrcReg), IType = LLT::integer(1);
10889 auto Zero = MIRBuilder.buildConstant(Ty, 0).getReg(0);
10890 auto Sub = MIRBuilder.buildSub(Ty, Zero, SrcReg).getReg(0);
10891 auto ICmp = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, IType, SrcReg, Zero);
10892 MIRBuilder.buildSelect(DestReg, ICmp, SrcReg, Sub);
10893 MI.eraseFromParent();
10894 return Legalized;
10895}
10896
10899 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10900 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10901 "Expected G_ABDS or G_ABDU instruction");
10902
10903 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10904 LLT Ty = MRI.getType(LHS);
10905
10906 // abds(lhs, rhs) -> select(sgt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10907 // abdu(lhs, rhs) -> select(ugt(lhs,rhs), sub(lhs,rhs), sub(rhs,lhs))
10908 Register LHSSub = MIRBuilder.buildSub(Ty, LHS, RHS).getReg(0);
10909 Register RHSSub = MIRBuilder.buildSub(Ty, RHS, LHS).getReg(0);
10910 CmpInst::Predicate Pred = (MI.getOpcode() == TargetOpcode::G_ABDS)
10913 auto ICmp = MIRBuilder.buildICmp(Pred, LLT::scalar(1), LHS, RHS);
10914 MIRBuilder.buildSelect(DstReg, ICmp, LHSSub, RHSSub);
10915
10916 MI.eraseFromParent();
10917 return Legalized;
10918}
10919
10922 assert((MI.getOpcode() == TargetOpcode::G_ABDS ||
10923 MI.getOpcode() == TargetOpcode::G_ABDU) &&
10924 "Expected G_ABDS or G_ABDU instruction");
10925
10926 auto [DstReg, LHS, RHS] = MI.getFirst3Regs();
10927 LLT Ty = MRI.getType(LHS);
10928
10929 // abds(lhs, rhs) -→ sub(smax(lhs, rhs), smin(lhs, rhs))
10930 // abdu(lhs, rhs) -→ sub(umax(lhs, rhs), umin(lhs, rhs))
10931 Register MaxReg, MinReg;
10932 if (MI.getOpcode() == TargetOpcode::G_ABDS) {
10933 MaxReg = MIRBuilder.buildSMax(Ty, LHS, RHS).getReg(0);
10934 MinReg = MIRBuilder.buildSMin(Ty, LHS, RHS).getReg(0);
10935 } else {
10936 MaxReg = MIRBuilder.buildUMax(Ty, LHS, RHS).getReg(0);
10937 MinReg = MIRBuilder.buildUMin(Ty, LHS, RHS).getReg(0);
10938 }
10939 MIRBuilder.buildSub(DstReg, MaxReg, MinReg);
10940
10941 MI.eraseFromParent();
10942 return Legalized;
10943}
10944
10946 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
10947 LLT TyInt =
10948 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
10949 Register CastedSrc = SrcReg;
10950
10951 if (!(SrcTy.getScalarType().isAnyScalar() ||
10952 SrcTy.getScalarType().isInteger())) {
10953 auto SrcTyInt =
10954 SrcTy.changeElementType(LLT::integer(SrcTy.getScalarSizeInBits()));
10955 CastedSrc = MIRBuilder.buildBitcast(SrcTyInt, SrcReg).getReg(0);
10956 }
10957
10958 if (MRI.getType(DstReg) != TyInt) {
10959 // Reset sign bit
10960 Register NewDst =
10962 .buildAnd(TyInt, CastedSrc,
10963 MIRBuilder.buildConstant(
10965 DstTy.getScalarSizeInBits())))
10966 .getReg(0);
10967
10968 MIRBuilder.buildBitcast(DstReg, NewDst);
10969 } else
10971 .buildAnd(
10972 DstReg, CastedSrc,
10973 MIRBuilder.buildConstant(
10974 TyInt, APInt::getSignedMaxValue(DstTy.getScalarSizeInBits())))
10975 .getReg(0);
10976
10977 MI.eraseFromParent();
10978 return Legalized;
10979}
10980
10983 Register SrcReg = MI.getOperand(1).getReg();
10984 LLT SrcTy = MRI.getType(SrcReg);
10985 LLT DstTy = MRI.getType(SrcReg);
10986
10987 // The source could be a scalar if the IR type was <1 x sN>.
10988 if (SrcTy.isScalar()) {
10989 if (DstTy.getSizeInBits() > SrcTy.getSizeInBits())
10990 return UnableToLegalize; // FIXME: handle extension.
10991 // This can be just a plain copy.
10992 Observer.changingInstr(MI);
10993 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::COPY));
10994 Observer.changedInstr(MI);
10995 return Legalized;
10996 }
10997 return UnableToLegalize;
10998}
10999
11001 MachineFunction &MF = *MI.getMF();
11002 const DataLayout &DL = MIRBuilder.getDataLayout();
11003 LLVMContext &Ctx = MF.getFunction().getContext();
11004 Register ListPtr = MI.getOperand(1).getReg();
11005 LLT PtrTy = MRI.getType(ListPtr);
11006
11007 // LstPtr is a pointer to the head of the list. Get the address
11008 // of the head of the list.
11009 Align PtrAlignment = DL.getABITypeAlign(getTypeForLLT(PtrTy, Ctx));
11010 MachineMemOperand *PtrLoadMMO = MF.getMachineMemOperand(
11011 MachinePointerInfo(), MachineMemOperand::MOLoad, PtrTy, PtrAlignment);
11012 auto VAList = MIRBuilder.buildLoad(PtrTy, ListPtr, *PtrLoadMMO).getReg(0);
11013
11014 const Align A(MI.getOperand(2).getImm());
11015 LLT PtrTyAsScalarTy = LLT::scalar(PtrTy.getSizeInBits());
11016 if (A > TLI.getMinStackArgumentAlignment()) {
11017 Register AlignAmt =
11018 MIRBuilder.buildConstant(PtrTyAsScalarTy, A.value() - 1).getReg(0);
11019 auto AddDst = MIRBuilder.buildPtrAdd(PtrTy, VAList, AlignAmt);
11020 auto AndDst = MIRBuilder.buildMaskLowPtrBits(PtrTy, AddDst, Log2(A));
11021 VAList = AndDst.getReg(0);
11022 }
11023
11024 // Increment the pointer, VAList, to the next vaarg
11025 // The list should be bumped by the size of element in the current head of
11026 // list.
11027 Register Dst = MI.getOperand(0).getReg();
11028 LLT LLTTy = MRI.getType(Dst);
11029 Type *Ty = getTypeForLLT(LLTTy, Ctx);
11030 auto IncAmt =
11031 MIRBuilder.buildConstant(PtrTyAsScalarTy, DL.getTypeAllocSize(Ty));
11032 auto Succ = MIRBuilder.buildPtrAdd(PtrTy, VAList, IncAmt);
11033
11034 // Store the increment VAList to the legalized pointer
11036 MachinePointerInfo(), MachineMemOperand::MOStore, PtrTy, PtrAlignment);
11037 MIRBuilder.buildStore(Succ, ListPtr, *StoreMMO);
11038 // Load the actual argument out of the pointer VAList
11039 Align EltAlignment = DL.getABITypeAlign(Ty);
11040 MachineMemOperand *EltLoadMMO = MF.getMachineMemOperand(
11041 MachinePointerInfo(), MachineMemOperand::MOLoad, LLTTy, EltAlignment);
11042 MIRBuilder.buildLoad(Dst, VAList, *EltLoadMMO);
11043
11044 MI.eraseFromParent();
11045 return Legalized;
11046}
11047
11049 unsigned OpCode = MI.getOpcode();
11050 assert((OpCode == TargetOpcode::G_SMULFIX ||
11051 OpCode == TargetOpcode::G_UMULFIX ||
11052 OpCode == TargetOpcode::G_SMULFIXSAT ||
11053 OpCode == TargetOpcode::G_UMULFIXSAT) &&
11054 "Operator must be either G_SMULFIX[SAT] or G_UMULFIX[SAT]!");
11055 auto [Dst, LHS, RHS] = MI.getFirst3Regs();
11056 LLT Ty = MRI.getType(Dst);
11057 unsigned Scale = MI.getOperand(3).getImm();
11058
11059 bool Saturating = (OpCode == TargetOpcode::G_SMULFIXSAT ||
11060 OpCode == TargetOpcode::G_UMULFIXSAT);
11061 bool IsSigned = (OpCode == TargetOpcode::G_SMULFIX ||
11062 OpCode == TargetOpcode::G_SMULFIXSAT);
11063
11064 if (!Saturating && Scale == 0) {
11065 MIRBuilder.buildMul(Dst, LHS, RHS);
11066 MI.eraseFromParent();
11067 return Legalized;
11068 }
11069
11070 // TODO: Port other lowering paths from SelectionDAG.
11071 LLT WideTy = Ty.changeElementSize(Ty.getScalarSizeInBits() * 2);
11072 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Scale);
11073 MachineInstrBuilder ExtLHS{}, ExtRHS{}, Shift{};
11074 if (IsSigned) {
11075 ExtLHS = MIRBuilder.buildSExt(WideTy, LHS);
11076 ExtRHS = MIRBuilder.buildSExt(WideTy, RHS);
11077 } else {
11078 ExtLHS = MIRBuilder.buildZExt(WideTy, LHS);
11079 ExtRHS = MIRBuilder.buildZExt(WideTy, RHS);
11080 }
11081
11082 auto Mul = MIRBuilder.buildMul(WideTy, ExtLHS, ExtRHS);
11083 if (IsSigned)
11084 Shift = MIRBuilder.buildAShr(WideTy, Mul, ShiftAmt);
11085 else
11086 Shift = MIRBuilder.buildLShr(WideTy, Mul, ShiftAmt);
11087
11088 if (!Saturating)
11089 MIRBuilder.buildTrunc(Dst, Shift);
11090 else if (IsSigned)
11091 MIRBuilder.buildTruncSSatS(Dst, Shift);
11092 else
11093 MIRBuilder.buildTruncUSatU(Dst, Shift);
11094
11095 MI.eraseFromParent();
11096 return Legalized;
11097}
11098
11099// Get a vectorized representation of the memset value operand, GISel edition.
11101 MachineRegisterInfo &MRI = *MIB.getMRI();
11102 unsigned NumBits = Ty.getScalarSizeInBits();
11103 auto ValVRegAndVal = getIConstantVRegValWithLookThrough(Val, MRI);
11104 if (!Ty.isVector() && ValVRegAndVal) {
11105 APInt Scalar = ValVRegAndVal->Value.trunc(8);
11106 APInt SplatVal = APInt::getSplat(NumBits, Scalar);
11107 return MIB.buildConstant(Ty, SplatVal).getReg(0);
11108 }
11109
11110 // Extend the byte value to the larger type, and then multiply by a magic
11111 // value 0x010101... in order to replicate it across every byte.
11112 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
11113 if (ValVRegAndVal && ValVRegAndVal->Value == 0) {
11114 return MIB.buildConstant(Ty, 0).getReg(0);
11115 }
11116
11117 LLT ExtType = Ty.getScalarType();
11118 auto ZExt = MIB.buildZExtOrTrunc(ExtType, Val);
11119 if (NumBits > 8) {
11120 APInt Magic = APInt::getSplat(NumBits, APInt(8, 0x01));
11121 auto MagicMI = MIB.buildConstant(ExtType, Magic);
11122 Val = MIB.buildMul(ExtType, ZExt, MagicMI).getReg(0);
11123 }
11124
11125 // For vector types create a G_BUILD_VECTOR.
11126 if (Ty.isVector())
11127 Val = MIB.buildSplatBuildVector(Ty, Val).getReg(0);
11128
11129 return Val;
11130}
11131
11133LegalizerHelper::lowerMemset(MachineInstr &MI, Register Dst, Register Val,
11134 uint64_t KnownLen, Align Alignment,
11135 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11136 auto &MF = *MI.getParent()->getParent();
11137 const auto &TLI = *MF.getSubtarget().getTargetLowering();
11138 auto &DL = MF.getDataLayout();
11139 LLVMContext &C = MF.getFunction().getContext();
11140
11141 assert(KnownLen != 0 && "Have a zero length memset length!");
11142 assert(!MemOps.empty() && "Expected at least one memory op");
11143
11144 MachineFrameInfo &MFI = MF.getFrameInfo();
11145 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11146 const auto &DstMMO = **MI.memoperands_begin();
11147
11148 if (DstAlignCanChange) {
11149 // Get an estimate of the type from the LLT.
11150 Type *IRTy = getTypeForLLT(MemOps[0], C);
11151 Align NewAlign = DL.getABITypeAlign(IRTy);
11152 if (NewAlign > Alignment) {
11153 Alignment = NewAlign;
11154 unsigned FI = FIDef->getOperand(1).getIndex();
11155 // Give the stack frame object a larger alignment if needed.
11156 if (MFI.getObjectAlign(FI) < Alignment)
11157 MFI.setObjectAlignment(FI, Alignment);
11158 }
11159 }
11160
11161 MachineIRBuilder MIB(MI);
11162 // Find the largest store and generate the bit pattern for it.
11163 LLT LargestTy = MemOps[0];
11164 for (unsigned i = 1; i < MemOps.size(); i++)
11165 if (MemOps[i].getSizeInBits() > LargestTy.getSizeInBits())
11166 LargestTy = MemOps[i];
11167
11168 // The memset stored value is always defined as an s8, so in order to make it
11169 // work with larger store types we need to repeat the bit pattern across the
11170 // wider type.
11171 Register MemSetValue = getMemsetValue(Val, LargestTy, MIB);
11172
11173 if (!MemSetValue)
11174 return UnableToLegalize;
11175
11176 // Generate the stores. For each store type in the list, we generate the
11177 // matching store of that type to the destination address.
11178 LLT PtrTy = MRI.getType(Dst);
11179 unsigned DstOff = 0;
11180 unsigned Size = KnownLen;
11181 for (unsigned I = 0; I < MemOps.size(); I++) {
11182 LLT Ty = MemOps[I];
11183 unsigned TySize = Ty.getSizeInBytes();
11184
11185 if (TySize > Size) {
11186 // Issuing a load / store pair that overlaps with the previous pair.
11187 // Adjust the offset accordingly.
11188 assert(I == MemOps.size() - 1 && I != 0);
11189 DstOff -= TySize - Size;
11190 }
11191
11192 // If this store is smaller than the largest store see whether we can get
11193 // the smaller value for free with a truncate.
11194 Register Value = MemSetValue;
11195 if (Ty.getSizeInBits() < LargestTy.getSizeInBits()) {
11196 MVT VT = getMVTForLLT(Ty);
11197 MVT LargestVT = getMVTForLLT(LargestTy);
11198 if (!LargestTy.isVector() && !Ty.isVector() &&
11199 TLI.isTruncateFree(LargestVT, VT))
11200 Value = MIB.buildTrunc(Ty, MemSetValue).getReg(0);
11201 else
11202 Value = getMemsetValue(Val, Ty, MIB);
11203 if (!Value)
11204 return UnableToLegalize;
11205 }
11206
11207 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, DstOff, Ty);
11208
11209 Register Ptr = Dst;
11210 if (DstOff != 0) {
11211 auto Offset =
11212 MIB.buildConstant(LLT::integer(PtrTy.getSizeInBits()), DstOff);
11213 Ptr = MIB.buildObjectPtrOffset(PtrTy, Dst, Offset).getReg(0);
11214 }
11215
11216 MIB.buildStore(Value, Ptr, *StoreMMO);
11217 DstOff += Ty.getSizeInBytes();
11218 Size -= TySize;
11219 }
11220
11221 MI.eraseFromParent();
11222 return Legalized;
11223}
11224
11226LegalizerHelper::lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
11227 uint64_t KnownLen, Align Alignment,
11228 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11229 auto &MF = *MI.getParent()->getParent();
11230 auto &DL = MF.getDataLayout();
11231 LLVMContext &C = MF.getFunction().getContext();
11232
11233 assert(KnownLen != 0 && "Have a zero length memcpy length!");
11234 assert(!MemOps.empty() && "Expected at least one memory op");
11235
11236 MachineFrameInfo &MFI = MF.getFrameInfo();
11237 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11238
11239 // FIXME: infer better src pointer alignment like SelectionDAG does here.
11240 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
11241 // if the memcpy is in a tail call position.
11242
11243 const auto &DstMMO = **MI.memoperands_begin();
11244 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11245
11246 if (DstAlignCanChange) {
11247 // Get an estimate of the type from the LLT.
11248 Type *IRTy = getTypeForLLT(MemOps[0], C);
11249 Align NewAlign = DL.getABITypeAlign(IRTy);
11250
11251 // Don't promote to an alignment that would require dynamic stack
11252 // realignment.
11253 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11254 if (!TRI->hasStackRealignment(MF))
11255 if (MaybeAlign StackAlign = DL.getStackAlignment())
11256 NewAlign = std::min(NewAlign, *StackAlign);
11257
11258 if (NewAlign > Alignment) {
11259 Alignment = NewAlign;
11260 unsigned FI = FIDef->getOperand(1).getIndex();
11261 // Give the stack frame object a larger alignment if needed.
11262 if (MFI.getObjectAlign(FI) < Alignment)
11263 MFI.setObjectAlignment(FI, Alignment);
11264 }
11265 }
11266
11267 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI << " into loads & stores\n");
11268
11269 MachineIRBuilder MIB(MI);
11270 // Now we need to emit a pair of load and stores for each of the types we've
11271 // collected. I.e. for each type, generate a load from the source pointer of
11272 // that type width, and then generate a corresponding store to the dest buffer
11273 // of that value loaded. This can result in a sequence of loads and stores
11274 // mixed types, depending on what the target specifies as good types to use.
11275 LLT SrcTy = MRI.getType(Src);
11276 LLT DstTy = MRI.getType(Dst);
11277 unsigned SrcIndexSize = DL.getIndexSizeInBits(SrcTy.getAddressSpace());
11278 unsigned DstIndexSize = DL.getIndexSizeInBits(DstTy.getAddressSpace());
11279 unsigned CurrOffset = 0;
11280 unsigned Size = KnownLen;
11281 for (auto CopyTy : MemOps) {
11282 TypeSize TySize = CopyTy.getSizeInBytes();
11283
11284 // Issuing a load / store pair that overlaps with the previous pair. Adjust
11285 // the offset accordingly.
11286 if (TySize > Size) {
11287 unsigned Overlap = TySize - Size;
11288 assert(Overlap < CurrOffset &&
11289 "overlapping memcpy load/store spans the whole region or more");
11290 CurrOffset -= Overlap;
11291 }
11292
11293 // Construct MMOs for the accesses.
11294 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11295 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11296
11297 // Create the load.
11298 Register LoadPtr = Src;
11300 if (CurrOffset != 0) {
11301 Offset =
11302 MIB.buildConstant(LLT::integer(SrcIndexSize), CurrOffset).getReg(0);
11303 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11304 }
11305 auto LdVal = MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO);
11306
11307 // Create the store.
11308 Register StorePtr = Dst;
11309 if (CurrOffset != 0) {
11310 if (SrcIndexSize != DstIndexSize) {
11311 Offset =
11312 MIB.buildConstant(LLT::integer(DstIndexSize), CurrOffset).getReg(0);
11313 }
11314 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11315 }
11316 MIB.buildStore(LdVal, StorePtr, *StoreMMO);
11317 CurrOffset += TySize;
11318 Size -= TySize;
11319 }
11320
11321 MI.eraseFromParent();
11322 return Legalized;
11323}
11324
11326LegalizerHelper::lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
11327 uint64_t KnownLen, Align Alignment,
11328 bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11329 auto &MF = *MI.getParent()->getParent();
11330 auto &DL = MF.getDataLayout();
11331 LLVMContext &C = MF.getFunction().getContext();
11332
11333 assert(KnownLen != 0 && "Have a zero length memmove length!");
11334 assert(!MemOps.empty() && "Expected at least one memory op");
11335
11336 MachineFrameInfo &MFI = MF.getFrameInfo();
11337 MachineInstr *FIDef = getOpcodeDef(TargetOpcode::G_FRAME_INDEX, Dst, MRI);
11338 const auto &DstMMO = **MI.memoperands_begin();
11339 const auto &SrcMMO = **std::next(MI.memoperands_begin());
11340
11341 if (DstAlignCanChange) {
11342 // Get an estimate of the type from the LLT.
11343 Type *IRTy = getTypeForLLT(MemOps[0], C);
11344 Align NewAlign = DL.getABITypeAlign(IRTy);
11345
11346 // Don't promote to an alignment that would require dynamic stack
11347 // realignment.
11348 const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
11349 if (!TRI->hasStackRealignment(MF))
11350 if (MaybeAlign StackAlign = DL.getStackAlignment())
11351 NewAlign = std::min(NewAlign, *StackAlign);
11352
11353 if (NewAlign > Alignment) {
11354 Alignment = NewAlign;
11355 unsigned FI = FIDef->getOperand(1).getIndex();
11356 // Give the stack frame object a larger alignment if needed.
11357 if (MFI.getObjectAlign(FI) < Alignment)
11358 MFI.setObjectAlignment(FI, Alignment);
11359 }
11360 }
11361
11362 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI << " into loads & stores\n");
11363
11364 MachineIRBuilder MIB(MI);
11365 // Memmove requires that we perform the loads first before issuing the stores.
11366 // Apart from that, this loop is pretty much doing the same thing as the
11367 // memcpy codegen function.
11368 unsigned CurrOffset = 0;
11369 unsigned Size = KnownLen;
11370 SmallVector<Register, 16> LoadVals;
11371 for (auto CopyTy : MemOps) {
11372 TypeSize TySize = CopyTy.getSizeInBytes();
11373
11374 // Issuing a load that overlaps with the previous load. Adjust the offset
11375 // accordingly.
11376 if (TySize > Size) {
11377 unsigned Overlap = TySize - Size;
11378 assert(Overlap < CurrOffset &&
11379 "overlapping memmove load spans the whole region or more");
11380 CurrOffset -= Overlap;
11381 }
11382
11383 // Construct MMO for the load.
11384 auto *LoadMMO = MF.getMachineMemOperand(&SrcMMO, CurrOffset, TySize);
11385
11386 // Create the load.
11387 Register LoadPtr = Src;
11388 if (CurrOffset != 0) {
11389 LLT SrcTy = MRI.getType(Src);
11390 auto Offset =
11391 MIB.buildConstant(LLT::integer(SrcTy.getSizeInBits()), CurrOffset);
11392 LoadPtr = MIB.buildObjectPtrOffset(SrcTy, Src, Offset).getReg(0);
11393 }
11394 LoadVals.push_back(MIB.buildLoad(CopyTy, LoadPtr, *LoadMMO).getReg(0));
11395 CurrOffset += TySize;
11396 Size -= TySize;
11397 }
11398
11399 CurrOffset = 0;
11400 Size = KnownLen;
11401 for (unsigned I = 0; I < MemOps.size(); ++I) {
11402 LLT CopyTy = MemOps[I];
11403 TypeSize TySize = CopyTy.getSizeInBytes();
11404
11405 // Issuing a store that overlaps with the previous store. Adjust the offset
11406 // accordingly.
11407 if (TySize > Size) {
11408 unsigned Overlap = TySize - Size;
11409 assert(Overlap < CurrOffset &&
11410 "overlapping memmove store spans the whole region or more");
11411 CurrOffset -= Overlap;
11412 }
11413
11414 // Now store the values loaded.
11415 auto *StoreMMO = MF.getMachineMemOperand(&DstMMO, CurrOffset, TySize);
11416
11417 Register StorePtr = Dst;
11418 if (CurrOffset != 0) {
11419 LLT DstTy = MRI.getType(Dst);
11420 auto Offset =
11421 MIB.buildConstant(LLT::integer(DstTy.getSizeInBits()), CurrOffset);
11422 StorePtr = MIB.buildObjectPtrOffset(DstTy, Dst, Offset).getReg(0);
11423 }
11424 MIB.buildStore(LoadVals[I], StorePtr, *StoreMMO);
11425 CurrOffset += TySize;
11426 Size -= TySize;
11427 }
11428 MI.eraseFromParent();
11429 return Legalized;
11430}
11431
11433 MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen,
11434 Align Alignment, bool DstAlignCanChange, ArrayRef<LLT> MemOps) {
11435 const unsigned Opc = MI.getOpcode();
11436 assert((Opc == TargetOpcode::G_MEMCPY ||
11437 Opc == TargetOpcode::G_MEMCPY_INLINE ||
11438 Opc == TargetOpcode::G_MEMMOVE || Opc == TargetOpcode::G_MEMSET ||
11439 Opc == TargetOpcode::G_MEMSET_INLINE) &&
11440 "Expected memcpy like instruction");
11441
11442 if (KnownLen == 0) {
11443 MI.eraseFromParent();
11444 return Legalized;
11445 }
11446
11447 if (Opc == TargetOpcode::G_MEMCPY || Opc == TargetOpcode::G_MEMCPY_INLINE) {
11448 return lowerMemcpy(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11449 MemOps);
11450 }
11451 if (Opc == TargetOpcode::G_MEMMOVE)
11452 return lowerMemmove(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11453 MemOps);
11454 if (Opc == TargetOpcode::G_MEMSET || Opc == TargetOpcode::G_MEMSET_INLINE)
11455 return lowerMemset(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11456 MemOps);
11457 return UnableToLegalize;
11458}
11459
11462 Register Dst, Src;
11463 uint64_t KnownLen;
11464 Align Alignment;
11465 bool DstAlignCanChange;
11466 std::vector<LLT> MemOps;
11467 if (!canLowerMemCpyFamily(MI, MRI, MaxLen, Dst, Src, KnownLen, Alignment,
11468 DstAlignCanChange, MemOps))
11469 return UnableToLegalize;
11470 return lowerMemCpyFamily(MI, Dst, Src, KnownLen, Alignment, DstAlignCanChange,
11471 MemOps);
11472}
unsigned NumParts
const TargetLowering & TLI
SDValue Pred
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
uint64_t Imm
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:665
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file describes how to lower LLVM calls to machine code calls.
#define GISEL_VECREDUCE_CASES_NONSEQ
Definition Utils.h:79
static std::optional< bool > isBigEndian(const SmallDenseMap< int64_t, int64_t, 8 > &MemOffset2Idx, int64_t LowestIdx)
Given a map from byte offsets in memory to indices in a load/store, determine if that map corresponds...
This contains common code to allow clients to notify changes to machine instr.
Provides analysis for querying information about KnownBits during GISel passes.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred)
#define RTLIBCASE_INT(LibcallPrefix)
static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI)
static Register buildBitFieldInsert(MachineIRBuilder &B, Register TargetReg, Register InsertReg, Register OffsetBits)
Emit code to insert InsertReg into TargetRet at OffsetBits in TargetReg, while preserving other bits ...
static Register getMemsetValue(Register Val, LLT Ty, MachineIRBuilder &MIB)
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size)
static std::pair< RTLIB::Libcall, CmpInst::Predicate > getFCMPLibcallDesc(const CmpInst::Predicate Pred, unsigned Size)
Returns the corresponding libcall for the given Pred and the ICMP predicate that should be generated ...
static void broadcastSrcOp(SmallVectorImpl< SrcOp > &Ops, unsigned N, MachineOperand &Op)
Operand Op is used on N sub-instructions.
static bool isLibCallInTailPosition(const CallLowering::ArgInfo &Result, MachineInstr &MI, const TargetInstrInfo &TII, MachineRegisterInfo &MRI)
True if an instruction is in tail position in its caller.
static Register getBitcastWiderVectorElementOffset(MachineIRBuilder &B, Register Idx, unsigned NewEltSize, unsigned OldEltSize)
Figure out the bit offset into a register when coercing a vector index for the wide element type.
static void makeDstOps(SmallVectorImpl< DstOp > &DstOps, LLT Ty, unsigned NumElts)
Fill DstOps with DstOps that have same number of elements combined as the Ty.
#define LCALL5(A)
static MachineInstrBuilder SwapN(unsigned N, DstOp Dst, MachineIRBuilder &B, MachineInstrBuilder Src, const APInt &Mask)
static bool isNonZeroModBitWidth(const MachineRegisterInfo &MRI, Register Reg, unsigned BW)
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
SmallVector< MachineOperand, 4 > Cond
RISCVCC::CondCode CC
MachineRegisterInfo & MRI
Remove Loads Into Fake Uses
#define LLVM_DEBUG(...)
Definition Debug.h:119
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
Value * RHS
Value * LHS
BinaryOperator * Mul
The Input class is used to parse a yaml document into in-memory structs and vectors.
static const fltSemantics & IEEEsingle()
Definition APFloat.h:304
static constexpr roundingMode rmTowardZero
Definition APFloat.h:365
static const fltSemantics & IEEEdouble()
Definition APFloat.h:305
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:377
opStatus convertFromAPInt(const APInt &Input, bool IsSigned, roundingMode RM)
Definition APFloat.h:1451
APInt bitcastToAPInt() const
Definition APFloat.h:1475
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1242
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1202
static APFloat getNaN(const fltSemantics &Sem, bool Negative=false, uint64_t payload=0)
Factory for NaN values.
Definition APFloat.h:1213
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1057
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
uint64_t getZExtValue() const
Get zero extended value.
Definition APInt.h:1560
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
LLVM_ABI APInt trunc(unsigned width) const
Truncate to new width.
Definition APInt.cpp:970
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
Definition APInt.h:202
bool ugt(const APInt &RHS) const
Unsigned greater than comparison.
Definition APInt.h:1186
static APInt getBitsSet(unsigned numBits, unsigned loBit, unsigned hiBit)
Get a value with a block of bits set.
Definition APInt.h:254
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
Definition APInt.h:376
LLVM_ABI APInt urem(const APInt &RHS) const
Unsigned remainder operation.
Definition APInt.cpp:1695
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:205
static APInt getMinValue(unsigned numBits)
Gets minimum unsigned value of APInt for a specific bit width.
Definition APInt.h:212
void negate()
Negate this APInt in place.
Definition APInt.h:1488
static LLVM_ABI APInt getSplat(unsigned NewLen, const APInt &V)
Return a value containing V broadcasted over NewLen bits.
Definition APInt.cpp:648
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
Definition APInt.h:215
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1030
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:875
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Definition APInt.h:302
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:235
APInt lshr(unsigned shiftAmt) const
Logical right-shift function.
Definition APInt.h:853
static APInt getBitsSetWithWrap(unsigned numBits, unsigned loBit, unsigned hiBit)
Wrap version of getBitsSet.
Definition APInt.h:266
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
iterator end() const
Definition ArrayRef.h:130
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:754
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:752
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
Definition InstrTypes.h:749
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
Definition InstrTypes.h:750
bool isSigned() const
Definition InstrTypes.h:993
Predicate getInversePredicate() const
For example, EQ -> NE, UGT -> ULE, SLT -> SGE, OEQ -> UNE, UGT -> OLE, OLT -> UGE,...
Definition InstrTypes.h:852
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
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:44
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:856
LLT getLLTTy(const MachineRegisterInfo &MRI) const
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:306
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition TypeSize.h:312
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:329
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:352
Represents any generic load, including sign/zero extending variants.
Register getDstReg() const
Get the definition register of the loaded value.
Register getValueReg() const
Get the stored value register.
Abstract class that contains various methods for clients to notify about changes.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.
Represents a insert subvector.
Represents any type of generic load or store.
Register getPointerReg() const
Get the source register of the pointer value.
MachineMemOperand & getMMO() const
Get the MachineMemOperand on this instruction.
LocationSize getMemSize() const
Returns the size in bytes of the memory access.
bool isAtomic() const
Returns true if the attached MachineMemOperand has the atomic flag set.
Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
Represents a threeway compare.
Represents a G_STORE.
A base class for all GenericMachineInstrs.
Register getReg(unsigned Idx) const
Access the Idx'th operand as a register and return it.
static bool isEquality(Predicate P)
Return true if this predicate is either EQ or NE.
Predicate getUnsignedPredicate() const
For example, EQ->EQ, SLE->ULE, UGT->UGT, etc.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
bool isKnownNever(FPClassMask Mask) const
Return true if it's known this can never be one of the mask entries.
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
LLT changeToInteger() 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:76
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
LLVM_ABI LegalizeResult lowerShlSat(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerThreewayCompare(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI)
LLVM_ABI LegalizeResult equalizeVectorShuffleLengths(MachineInstr &MI)
Equalize source and destination vector sizes of G_SHUFFLE_VECTOR.
LLVM_ABI LegalizeResult bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_INSERT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerDynStackAlloc(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBitCount(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarMul(MachineInstr &MI, LLT Ty)
LLVM_ABI LegalizeResult lowerFMinNumMaxNum(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF64BitFloatOps(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSSUBE(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerIntrinsicRound(MachineInstr &MI)
LLVM_ABI void widenScalarSrc(MachineInstr &MI, LLT WideTy, unsigned OpIdx, unsigned ExtOpcode)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI LegalizeResult moreElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
LLVM_ABI LegalizeResult lowerSMULH_UMULH(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerLoad(GAnyLoad &MI)
LLVM_ABI LegalizeResult fewerElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerAbsToAddXor(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPEXT_BF16(MachineInstr &MI)
LLVM_ABI void moreElementsVectorDst(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Def by performing it with addition...
LLVM_ABI LegalizerHelper::LegalizeResult createAtomicLibcall(MachineInstr &MI) const
LLVM_ABI LegalizeResult lowerFConstant(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerBitreverse(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI)
Lower a vector extract or insert by writing the vector to a stack temporary and reloading the element...
LLVM_ABI LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
Legalize a vector instruction by increasing the number of vector elements involved and ignoring the a...
LLVM_ABI LegalizeResult lowerFunnelShiftWithInverse(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTOINT_SAT(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarCTLS(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStore(GStore &MI)
LLVM_ABI LegalizeResult lowerAbsToCNeg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPEXT(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastExtractSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
LLVM_ABI LegalizeResult narrowScalarShiftMultiway(MachineInstr &MI, LLT TargetTy)
Multi-way shift legalization: directly split wide shifts into target-sized parts in a single step,...
LLVM_ABI Register lowerRoundInexactToOdd(LLT ResultTy, Register Op)
LLVM_ABI LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMemCpyFamily(MachineInstr &MI, Register Dst, Register Src, uint64_t KnownLen, Align Alignment, bool DstAlignCanChange, ArrayRef< LLT > MemOps)
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
LLVM_ABI Register buildConstantShiftPart(unsigned Opcode, unsigned PartIdx, unsigned NumParts, ArrayRef< Register > SrcParts, const ShiftParams &Params, LLT TargetTy, LLT ShiftAmtTy)
Generates a single output part for constant shifts using direct indexing.
LLVM_ABI void narrowScalarSrc(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by truncating the operand's ty...
LLVM_ABI LegalizeResult fewerElementsVectorPhi(GenericMachineInstr &MI, unsigned NumElts)
LLVM_ABI LegalizeResult lowerFPTOUI(MachineInstr &MI)
const TargetLowering & getTargetLowering() const
LLVM_ABI LegalizeResult narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize an instruction by reducing the width of the underlying scalar type.
LLVM_ABI LegalizeResult narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult bitcastInsertSubvector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
LLVM_ABI LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer, MachineIRBuilder &B, const LibcallLoweringInfo *Libcalls=nullptr)
LLVM_ABI LegalizeResult lowerUnmergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcast(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by replacing the value type.
LLVM_ABI LegalizeResult scalarizeVectorBooleanStore(GStore &MI)
Given a store of a boolean vector, scalarize it.
LLVM_ABI LegalizeResult lowerBitcast(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerInsert(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerReadWriteRegister(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerExtract(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsBitcast(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt, LLT HalfTy, LLT ShiftAmtTy)
LLVM_ABI LegalizeResult lowerISFPCLASS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPOWI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPExtAndTruncMem(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFAbs(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerVectorReduction(MachineInstr &MI)
const LegalizerInfo & getLegalizerInfo() const
Expose LegalizerInfo so the clients can re-use.
LLVM_ABI LegalizeResult reduceLoadStoreWidth(GLoadStore &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult fewerElementsVectorMultiEltType(GenericMachineInstr &MI, unsigned NumElts, std::initializer_list< unsigned > NonVecOpIndices={})
Handles most opcodes.
LLVM_ABI LegalizeResult narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarShiftByConstantMultiway(MachineInstr &MI, const APInt &Amt, LLT TargetTy, LLT ShiftAmtTy)
Optimized path for constant shift amounts using static indexing.
LLVM_ABI void widenScalarSrcUsingFPExt(MachineInstr &MI, LLT WideTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by extending the operand's typ...
LLVM_ABI MachineInstrBuilder createStackStoreLoad(const DstOp &Res, const SrcOp &Val)
Create a store of Val to a stack temporary and return a load as the same type as Res.
LLVM_ABI LegalizeResult lowerVAArg(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMODF(MachineInstr &MI)
@ Legalized
Instruction has been legalized and the MachineFunction changed.
@ AlreadyLegal
Instruction was already legal and no change was made to the MachineFunction.
@ UnableToLegalize
Some kind of error has occurred and we could not legalize this instruction.
LLVM_ABI LegalizeResult moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx, LLT MoreTy)
LLVM_ABI LegalizeResult lowerFCopySign(MachineInstr &MI)
LLVM_ABI LegalizeResult bitcastConcatVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerRotateWithReverseRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSADDE(MachineInstr &MI)
LLVM_ABI LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
Legalize an instruction by splitting it into simpler parts, hopefully understood by the target.
LLVM_ABI LegalizeResult lowerFunnelShift(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F32_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
Legalize a vector instruction by splitting into multiple components, each acting on the same scalar t...
GISelChangeObserver & Observer
To keep track of changes made by the LegalizerHelper.
LLVM_ABI LegalizeResult conversionLibcall(MachineInstr &MI, Type *ToType, Type *FromType, LostDebugLocObserver &LocObserver, bool IsSigned=false) const
LLVM_ABI void bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a def by inserting a G_BITCAST from ...
LLVM_ABI LegalizeResult lowerFPTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFMad(MachineInstr &MI)
LLVM_ABI LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy)
Legalize an instruction by performing the operation on a wider scalar type (for example a 16-bit addi...
LLVM_ABI LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult lowerFFloor(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerFPTRUNC_F64_TO_BF16(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerAbsDiffToMinMax(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarExt(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult fewerElementsVectorSeqReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Register getDynStackAllocTargetPtr(Register SPReg, Register AllocSize, Align Alignment, LLT PtrTy)
LLVM_ABI LegalizeResult lowerFPTOSI(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerUITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerShuffleVector(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerMergeValues(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult createMemLibcall(MachineRegisterInfo &MRI, MachineInstr &MI, LostDebugLocObserver &LocObserver) const
Create a libcall to memcpy et al.
LLVM_ABI LegalizeResult lowerVECTOR_COMPRESS(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerMulfix(MachineInstr &MI)
LLVM_ABI void moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a Use by producing a vector with und...
LLVM_ABI LegalizeResult bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
Perform Bitcast legalize action on G_EXTRACT_VECTOR_ELT.
LLVM_ABI LegalizeResult lowerRotate(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerU64ToF32WithSITOFP(MachineInstr &MI)
LLVM_ABI LegalizeResult createLibcall(const char *Name, const CallLowering::ArgInfo &Result, ArrayRef< CallLowering::ArgInfo > Args, CallingConv::ID CC, LostDebugLocObserver &LocObserver, MachineInstr *MI=nullptr) const
Helper function that creates a libcall to the given Name using the given calling convention CC.
LLVM_ABI LegalizeResult bitcastShuffleVector(MachineInstr &MI, unsigned TypeIdx, LLT CastTy)
LLVM_ABI LegalizeResult lowerDIVREM(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerSelect(MachineInstr &MI)
LLVM_ABI LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI LegalizeResult narrowScalarFLDEXP(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI Register buildVariableShiftPart(unsigned Opcode, Register MainOperand, Register ShiftAmt, LLT TargetTy, Register CarryOperand=Register())
Generates a shift part with carry for variable shifts.
LLVM_ABI void bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx)
Legalize a single operand OpIdx of the machine instruction MI as a use by inserting a G_BITCAST to Ca...
LLVM_ABI void narrowScalarDst(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx, unsigned ExtOpcode)
LLVM_ABI LegalizeResult libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Legalize an instruction by emiting a runtime library call instead.
LLVM_ABI LegalizeResult lowerStackRestore(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorReductions(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult lowerTruncSat(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerStackSave(MachineInstr &MI)
LLVM_ABI LegalizeResult fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI LegalizeResult narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty)
LLVM_ABI void widenScalarDstUsingFPTrunc(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI LegalizeResult lowerTRUNC(MachineInstr &MI)
LLVM_ABI LegalizeResult lowerBswap(MachineInstr &MI)
LLVM_ABI Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index)
Get a pointer to vector element Index located in memory for a vector of type VecTy starting at a base...
LLVM_ABI LegalizeResult narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy)
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LLVM_ABI LegalizeResult lowerConstant(MachineInstr &MI)
LLVM_ABI Register coerceToInteger(Register Val)
Cast the given value to an LLT::integer with an equivalent size.
LLVM_ABI void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx=0, unsigned TruncOpcode=TargetOpcode::G_TRUNC)
Legalize a single operand OpIdx of the machine instruction MI as a Def by extending the operand's typ...
LLVM_ABI LegalizeResult simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType, LostDebugLocObserver &LocObserver) const
LLVM_ABI LegalizeResult legalizeInstrStep(MachineInstr &MI, LostDebugLocObserver &LocObserver)
Replace MI by a sequence of legal instructions that can implement the same operation.
LLVM_ABI LegalizeResult lowerFMinimumMaximum(MachineInstr &MI)
Tracks which library functions to use for a particular subtarget or function.
TypeSize getValue() const
void checkpoint(bool CheckDebugLocs=true)
Call this to indicate that it's a good point to assess whether locations have been lost.
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:89
A single uniqued string.
Definition Metadata.h:733
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:615
static LLVM_ABI MVT getVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
LLVM_ABI iterator getFirstTerminatorForward()
Finds the first terminator in a block by scanning forward.
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
LLVM_ABI unsigned getConstantPoolIndex(const Constant *C, Align Alignment)
getConstantPoolIndex - Create a new entry in the constant pool or return an existing one.
LLVM_ABI int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot, const AllocaInst *Alloca=nullptr, uint8_t ID=0)
Create a new statically sized stack object, returning a nonnegative identifier to represent it.
Align getObjectAlign(int ObjectIdx) const
Return the alignment of the specified stack object.
void setObjectAlignment(int ObjectIdx, Align Alignment)
setObjectAlignment - Change the alignment of the specified stack object.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineFrameInfo & getFrameInfo()
getFrameInfo - Return the frame info object for the current function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
MachineConstantPool * getConstantPool()
getConstantPool - Return the constant pool object for the current function.
MachineMemOperand * getMachineMemOperand(MachinePointerInfo PtrInfo, MachineMemOperand::Flags F, LLT MemTy, Align BaseAlignment, const MMOMetadata &Metadata=MMOMetadata(), SyncScope::ID SSID=SyncScope::System, AtomicOrdering Ordering=AtomicOrdering::NotAtomic, AtomicOrdering FailureOrdering=AtomicOrdering::NotAtomic)
getMachineMemOperand - Allocate a new MachineMemOperand.
Helper class to build MachineInstr.
MachineInstrBuilder buildConstantPool(const DstOp &Res, unsigned Idx)
Build and insert Res = G_CONSTANT_POOL Idx.
MachineInstrBuilder buildMul(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_MUL Op0, Op1.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
const TargetInstrInfo & getTII()
MachineInstrBuilder buildURem(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_UREM Op0, Op1.
MachineInstrBuilder buildLShr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildZExt(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_ZEXT Op.
MachineInstrBuilder buildConcatVectors(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_CONCAT_VECTORS Op0, ...
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)
Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.
MachineInstrBuilder buildIntToPtr(const DstOp &Dst, const SrcOp &Src)
Build and insert a G_INTTOPTR instruction.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildNeg(const DstOp &Dst, const SrcOp &Src0)
Build and insert integer negation Zero = G_CONSTANT 0 Res = G_SUB Zero, Op0.
MachineInstrBuilder buildMergeLikeInstr(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_MERGE_VALUES Op0, ... or Res = G_BUILD_VECTOR Op0, ... or Res = G_CONCAT_VEC...
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
virtual MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val)
Build and insert Res = G_FCONSTANT Val.
MachineInstrBuilder buildShl(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
MachineInstrBuilder buildUITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_UITOFP Src0.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineInstrBuilder buildSITOFP(const DstOp &Dst, const SrcOp &Src0)
Build and insert Res = G_SITOFP Src0.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_TRUNC Op.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildFPTrunc(const DstOp &Res, const SrcOp &Op, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_FPTRUNC Op.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
MachineInstrBuilder buildLoadInstr(unsigned Opcode, const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = <opcode> Addr, MMO.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
Register getReg(unsigned Idx) const
Get the register for the operand index.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
mmo_iterator memoperands_begin() const
Access to memory operands of the instruction.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
A description of a memory reference used in the backend.
void setType(LLT NewTy)
Reset the tracked memory type.
LLT getMemoryType() const
Return the memory type of the memory reference.
void clearRanges()
Unset the tracked range metadata.
@ MOLoad
The memory access reads data.
@ MOStore
The memory access writes data.
const MachinePointerInfo & getPointerInfo() const
LocationSize getSizeInBits() const
Return the size in bits of the memory reference.
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateES(const char *SymName, unsigned TargetFlags=0)
const ConstantInt * getCImm() const
LLVM_ABI void setReg(Register Reg)
Change the register this operand corresponds to.
void setCImm(const ConstantInt *CI)
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:887
Wrapper class representing virtual and physical registers.
Definition Register.h:20
constexpr bool isValid() const
Definition Register.h:112
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
constexpr bool isPhysical() const
Return true if the specified register number is in the physical register namespace.
Definition Register.h:83
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void resize(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLT getLLTTy(const MachineRegisterInfo &MRI) const
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr const char * data() const
Get a pointer to the start of the string (which may not be null terminated).
Definition StringRef.h:138
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:467
TargetInstrInfo - Interface to description of machine instruction set.
@ Bitcast
Build the immediate as a bitcast of an integer constant with the same bits.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
virtual const TargetFrameLowering * getFrameLowering() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
virtual const TargetLowering * getTargetLowering() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:352
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
static LLVM_ABI Type * getFP128Ty(LLVMContext &C)
Definition Type.cpp:281
static LLVM_ABI Type * getVoidTy(LLVMContext &C)
Definition Type.cpp:272
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Definition Type.cpp:303
static LLVM_ABI Type * getDoubleTy(LLVMContext &C)
Definition Type.cpp:277
static LLVM_ABI Type * getX86_FP80Ty(LLVMContext &C)
Definition Type.cpp:280
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
Definition Type.cpp:276
static LLVM_ABI Type * getHalfTy(LLVMContext &C)
Definition Type.cpp:274
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition TypeSize.h:181
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:166
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:253
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ FewerElements
The (vector) operation should be implemented by splitting it into sub-vectors where the operation is ...
@ Legal
The operation is expected to be selectable directly by the target, and no transformation is necessary...
@ Libcall
The operation should be implemented as a call to some kind of runtime support library.
@ WidenScalar
The operation should be implemented in terms of a wider scalar base-type.
@ Bitcast
Perform the operation on a different, but equivalently sized type.
@ NarrowScalar
The operation should be synthesized from multiple instructions acting on a narrower scalar base-type.
@ MoreElements
The (vector) operation should be implemented by widening the input vector and ignoring the lanes adde...
ConstantMatch< APInt > m_ICst(APInt &Cst)
ImplicitDefMatch m_GImplicitDef()
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
LLVM_ABI Libcall getSINTTOFP(EVT OpVT, EVT RetVT)
getSINTTOFP - Return the SINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getUINTTOFP(EVT OpVT, EVT RetVT)
getUINTTOFP - Return the UINTTOFP_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOUINT(EVT OpVT, EVT RetVT)
getFPTOUINT - Return the FPTOUINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPTOSINT(EVT OpVT, EVT RetVT)
getFPTOSINT - Return the FPTOSINT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPEXT(EVT OpVT, EVT RetVT)
getFPEXT - Return the FPEXT_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
LLVM_ABI Libcall getFPROUND(EVT OpVT, EVT RetVT)
getFPROUND - Return the FPROUND_*_* value for the given types, or UNKNOWN_LIBCALL if there is none.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
IterT next_nodbg(IterT It, IterT End, bool SkipPseudoOp=true)
Increment It, then continue incrementing it while it points to a debug instruction.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
LLVM_ABI std::optional< APInt > isConstantOrConstantSplatVector(Register Def, const MachineRegisterInfo &MRI)
Determines if Def defines a constant integer or a splat vector of constant integers.
Definition Utils.cpp:1537
@ Offset
Definition DWP.cpp:577
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h:846
LLVM_ABI Type * getTypeForLLT(LLT Ty, LLVMContext &C)
Get the type back from LLT.
Definition Utils.cpp:1998
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:675
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:297
@ Undef
Value of the register doesn't matter.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
constexpr int64_t minIntN(int64_t N)
Gets the minimum value for a N-bit signed integer.
Definition MathExtras.h:224
LLVM_ABI bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg, llvm::function_ref< bool(const Constant *ConstVal)> Match, bool AllowUndefs=false)
Attempt to match a unary predicate against a scalar/splat constant or every element of a constant G_B...
Definition Utils.cpp:1592
LLVM_ABI MVT getMVTForLLT(LLT Ty)
Get a rough equivalent of an MVT for a given LLT.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
Definition STLExtras.h:1167
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition MathExtras.h:380
LLVM_ABI LLVM_READNONE LLT getLCMType(LLT OrigTy, LLT TargetTy)
Return the least common multiple type of OrigTy and TargetTy, by changing the number of vector elemen...
Definition Utils.cpp:1160
unsigned M1(unsigned Val)
Definition VE.h:394
constexpr T MinAlign(U A, V B)
A and B are either alignments or offsets.
Definition MathExtras.h:352
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
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:530
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:2165
To bit_cast(const From &from) noexcept
Definition bit.h:90
@ Mul
Product of integers.
@ FSub
Subtraction of floats.
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
IntPtrTy
Definition InstrProf.h:82
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1901
constexpr int64_t maxIntN(int64_t N)
Gets the maximum value for a N-bit signed integer.
Definition MathExtras.h:233
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
Align assumeAligned(uint64_t Value)
Treats the value 0 as a 1, so Align is always at least 1.
Definition Alignment.h:105
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Next
Definition InstrProf.h:147
unsigned Log2(Align A)
Returns the log2 of the alignment.
Definition Alignment.h:202
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:1248
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:633
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition MathExtras.h:368
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.
Definition BitVector.h:880
#define N
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
SmallVector< ISD::ArgFlagsTy, 4 > Flags
CallingConv::ID CallConv
Calling convention to be used for the call.
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.