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