LLVM 24.0.0git
LegalizerHelper.cpp
Go to the documentation of this file.
1//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9/// \file This file implements the LegalizerHelper class to legalize
10/// individual instructions and the LegalizeMachineIR wrapper pass for the
11/// primary legalization.
12//
13//===----------------------------------------------------------------------===//
14
36#include "llvm/Support/Debug.h"
40#include <cassert>
41#include <numeric>
42#include <optional>
43
44#define DEBUG_TYPE "legalizer"
45
46using namespace llvm;
47using namespace LegalizeActions;
48using namespace MIPatternMatch;
49
50/// Try to break down \p OrigTy into \p NarrowTy sized pieces.
51///
52/// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
53/// with any leftover piece as type \p LeftoverTy
54///
55/// Returns -1 in the first element of the pair if the breakdown is not
56/// satisfiable.
57static std::pair<int, int>
58getNarrowTypeBreakDown(LLT OrigTy, LLT NarrowTy, LLT &LeftoverTy) {
59 assert(!LeftoverTy.isValid() && "this is an out argument");
60
61 unsigned Size = OrigTy.getSizeInBits();
62 unsigned NarrowSize = NarrowTy.getSizeInBits();
63 unsigned NumParts = Size / NarrowSize;
64 unsigned LeftoverSize = Size - NumParts * NarrowSize;
65 assert(Size > NarrowSize);
66
67 if (LeftoverSize == 0)
68 return {NumParts, 0};
69
70 if (NarrowTy.isVector()) {
71 unsigned EltSize = OrigTy.getScalarSizeInBits();
72 if (LeftoverSize % EltSize != 0)
73 return {-1, -1};
74 LeftoverTy = OrigTy.changeElementCount(
75 ElementCount::getFixed(LeftoverSize / EltSize));
76 } else {
77 LeftoverTy = LLT::integer(LeftoverSize);
78 }
79
80 int NumLeftover = LeftoverSize / LeftoverTy.getSizeInBits();
81 return std::make_pair(NumParts, NumLeftover);
82}
83
85
86 if (!Ty.isScalar())
87 return nullptr;
88
89 switch (Ty.getSizeInBits()) {
90 case 16:
91 return Type::getHalfTy(Ctx);
92 case 32:
93 return Type::getFloatTy(Ctx);
94 case 64:
95 return Type::getDoubleTy(Ctx);
96 case 80:
97 return Type::getX86_FP80Ty(Ctx);
98 case 128:
99 return Type::getFP128Ty(Ctx);
100 default:
101 return nullptr;
102 }
103}
104
107 MachineIRBuilder &Builder,
108 const LibcallLoweringInfo *Libcalls)
109 : MIRBuilder(Builder), Observer(Observer), MRI(MF.getRegInfo()),
110 LI(*MF.getSubtarget().getLegalizerInfo()),
111 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls) {}
112
116 const LibcallLoweringInfo *Libcalls,
118 : MIRBuilder(B), Observer(Observer), MRI(MF.getRegInfo()), LI(LI),
119 TLI(*MF.getSubtarget().getTargetLowering()), Libcalls(Libcalls), VT(VT) {}
120
123 LostDebugLocObserver &LocObserver) {
124 LLVM_DEBUG(dbgs() << "\nLegalizing: " << MI);
125
126 MIRBuilder.setInstrAndDebugLoc(MI);
127
128 if (isa<GIntrinsic>(MI))
129 return LI.legalizeIntrinsic(*this, MI) ? Legalized : UnableToLegalize;
130 auto Step = LI.getAction(MI, MRI);
131 switch (Step.Action) {
132 case Legal:
133 LLVM_DEBUG(dbgs() << ".. Already legal\n");
134 return AlreadyLegal;
135 case Libcall:
136 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
137 return libcall(MI, LocObserver);
138 case NarrowScalar:
139 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
140 return narrowScalar(MI, Step.TypeIdx, Step.NewType);
141 case WidenScalar:
142 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
143 return widenScalar(MI, Step.TypeIdx, Step.NewType);
144 case Bitcast:
145 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
146 return bitcast(MI, Step.TypeIdx, Step.NewType);
147 case Lower:
148 LLVM_DEBUG(dbgs() << ".. Lower\n");
149 return lower(MI, Step.TypeIdx, Step.NewType);
150 case FewerElements:
151 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
152 return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
153 case MoreElements:
154 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
155 return moreElementsVector(MI, Step.TypeIdx, Step.NewType);
156 case Custom:
157 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
158 return LI.legalizeCustom(*this, MI, LocObserver) ? Legalized
160 default:
161 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
162 return UnableToLegalize;
163 }
164}
165
166void LegalizerHelper::insertParts(Register DstReg,
167 LLT ResultTy, LLT PartTy,
168 ArrayRef<Register> PartRegs,
169 LLT LeftoverTy,
170 ArrayRef<Register> LeftoverRegs) {
171 if (!LeftoverTy.isValid()) {
172 assert(LeftoverRegs.empty());
173
174 if (!ResultTy.isVector()) {
175 MIRBuilder.buildMergeLikeInstr(DstReg, PartRegs);
176 return;
177 }
178
179 if (PartTy.isVector())
180 MIRBuilder.buildConcatVectors(DstReg, PartRegs);
181 else
182 MIRBuilder.buildBuildVector(DstReg, PartRegs);
183 return;
184 }
185
186 // Merge sub-vectors with different number of elements and insert into DstReg.
187 if (ResultTy.isVector()) {
188 assert(LeftoverRegs.size() == 1 && "Expected one leftover register");
189 SmallVector<Register, 8> AllRegs(PartRegs);
190 AllRegs.append(LeftoverRegs.begin(), LeftoverRegs.end());
191 return mergeMixedSubvectors(DstReg, AllRegs);
192 }
193
194 SmallVector<Register> GCDRegs;
195 LLT GCDTy = getGCDType(getGCDType(ResultTy, LeftoverTy), PartTy);
196 for (auto PartReg : concat<const Register>(PartRegs, LeftoverRegs))
197 extractGCDType(GCDRegs, GCDTy, PartReg);
198 LLT ResultLCMTy = buildLCMMergePieces(ResultTy, LeftoverTy, GCDTy, GCDRegs);
199 buildWidenedRemergeToDst(DstReg, ResultLCMTy, GCDRegs);
200}
201
202void LegalizerHelper::appendVectorElts(SmallVectorImpl<Register> &Elts,
203 Register Reg) {
204 LLT Ty = MRI.getType(Reg);
206 extractParts(Reg, Ty.getScalarType(), Ty.getNumElements(), RegElts,
207 MIRBuilder, MRI);
208 Elts.append(RegElts);
209}
210
211/// Merge \p PartRegs with different types into \p DstReg.
212void LegalizerHelper::mergeMixedSubvectors(Register DstReg,
213 ArrayRef<Register> PartRegs) {
215 for (unsigned i = 0; i < PartRegs.size() - 1; ++i)
216 appendVectorElts(AllElts, PartRegs[i]);
217
218 Register Leftover = PartRegs[PartRegs.size() - 1];
219 if (!MRI.getType(Leftover).isVector())
220 AllElts.push_back(Leftover);
221 else
222 appendVectorElts(AllElts, Leftover);
223
224 MIRBuilder.buildMergeLikeInstr(DstReg, AllElts);
225}
226
227/// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
229 const MachineInstr &MI) {
230 assert(MI.getOpcode() == TargetOpcode::G_UNMERGE_VALUES);
231
232 const int StartIdx = Regs.size();
233 const int NumResults = MI.getNumOperands() - 1;
234 Regs.resize(Regs.size() + NumResults);
235 for (int I = 0; I != NumResults; ++I)
236 Regs[StartIdx + I] = MI.getOperand(I).getReg();
237}
238
239void LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts,
240 LLT GCDTy, Register SrcReg) {
241 LLT SrcTy = MRI.getType(SrcReg);
242 if (SrcTy == GCDTy) {
243 // If the source already evenly divides the result type, we don't need to do
244 // anything.
245 Parts.push_back(SrcReg);
246 } else {
247 // Need to split into common type sized pieces.
248 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
249 getUnmergeResults(Parts, *Unmerge);
250 }
251}
252
253LLT LegalizerHelper::extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
254 LLT NarrowTy, Register SrcReg) {
255 LLT SrcTy = MRI.getType(SrcReg);
256 LLT GCDTy = getGCDType(getGCDType(SrcTy, NarrowTy), DstTy);
257 extractGCDType(Parts, GCDTy, SrcReg);
258 return GCDTy;
259}
260
261LLT LegalizerHelper::buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
263 unsigned PadStrategy) {
264 LLT LCMTy = getLCMType(DstTy, NarrowTy);
265
266 int NumParts = LCMTy.getSizeInBits() / NarrowTy.getSizeInBits();
267 int NumSubParts = NarrowTy.getSizeInBits() / GCDTy.getSizeInBits();
268 int NumOrigSrc = VRegs.size();
269
270 Register PadReg;
271
272 // Get a value we can use to pad the source value if the sources won't evenly
273 // cover the result type.
274 if (NumOrigSrc < NumParts * NumSubParts) {
275 if (PadStrategy == TargetOpcode::G_ZEXT)
276 PadReg = MIRBuilder.buildConstant(GCDTy, 0).getReg(0);
277 else if (PadStrategy == TargetOpcode::G_ANYEXT)
278 PadReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
279 else {
280 assert(PadStrategy == TargetOpcode::G_SEXT);
281
282 // Shift the sign bit of the low register through the high register.
283 auto ShiftAmt =
284 MIRBuilder.buildConstant(LLT::integer(64), GCDTy.getSizeInBits() - 1);
285 PadReg = MIRBuilder.buildAShr(GCDTy, VRegs.back(), ShiftAmt).getReg(0);
286 }
287 }
288
289 // Registers for the final merge to be produced.
290 SmallVector<Register, 4> Remerge(NumParts);
291
292 // Registers needed for intermediate merges, which will be merged into a
293 // source for Remerge.
294 SmallVector<Register, 4> SubMerge(NumSubParts);
295
296 // Once we've fully read off the end of the original source bits, we can reuse
297 // the same high bits for remaining padding elements.
298 Register AllPadReg;
299
300 // Build merges to the LCM type to cover the original result type.
301 for (int I = 0; I != NumParts; ++I) {
302 bool AllMergePartsArePadding = true;
303
304 // Build the requested merges to the requested type.
305 for (int J = 0; J != NumSubParts; ++J) {
306 int Idx = I * NumSubParts + J;
307 if (Idx >= NumOrigSrc) {
308 SubMerge[J] = PadReg;
309 continue;
310 }
311
312 SubMerge[J] = VRegs[Idx];
313
314 // There are meaningful bits here we can't reuse later.
315 AllMergePartsArePadding = false;
316 }
317
318 // If we've filled up a complete piece with padding bits, we can directly
319 // emit the natural sized constant if applicable, rather than a merge of
320 // smaller constants.
321 if (AllMergePartsArePadding && !AllPadReg) {
322 if (PadStrategy == TargetOpcode::G_ANYEXT)
323 AllPadReg = MIRBuilder.buildUndef(NarrowTy).getReg(0);
324 else if (PadStrategy == TargetOpcode::G_ZEXT)
325 AllPadReg = MIRBuilder.buildConstant(NarrowTy, 0).getReg(0);
326
327 // If this is a sign extension, we can't materialize a trivial constant
328 // with the right type and have to produce a merge.
329 }
330
331 if (AllPadReg) {
332 // Avoid creating additional instructions if we're just adding additional
333 // copies of padding bits.
334 Remerge[I] = AllPadReg;
335 continue;
336 }
337
338 if (NumSubParts == 1)
339 Remerge[I] = SubMerge[0];
340 else
341 Remerge[I] = MIRBuilder.buildMergeLikeInstr(NarrowTy, SubMerge).getReg(0);
342
343 // In the sign extend padding case, re-use the first all-signbit merge.
344 if (AllMergePartsArePadding && !AllPadReg)
345 AllPadReg = Remerge[I];
346 }
347
348 VRegs = std::move(Remerge);
349 return LCMTy;
350}
351
352void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
353 ArrayRef<Register> RemergeRegs) {
354 LLT DstTy = MRI.getType(DstReg);
355
356 // Create the merge to the widened source, and extract the relevant bits into
357 // the result.
358
359 if (DstTy == LCMTy) {
360 MIRBuilder.buildMergeLikeInstr(DstReg, RemergeRegs);
361 return;
362 }
363
364 auto Remerge = MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs);
365 if (DstTy.isScalar() && LCMTy.isScalar()) {
366 MIRBuilder.buildTrunc(DstReg, Remerge);
367 return;
368 }
369
370 if (LCMTy.isVector()) {
371 unsigned NumDefs = LCMTy.getSizeInBits() / DstTy.getSizeInBits();
372 SmallVector<Register, 8> UnmergeDefs(NumDefs);
373 UnmergeDefs[0] = DstReg;
374 for (unsigned I = 1; I != NumDefs; ++I)
375 UnmergeDefs[I] = MRI.createGenericVirtualRegister(DstTy);
376
377 MIRBuilder.buildUnmerge(UnmergeDefs,
378 MIRBuilder.buildMergeLikeInstr(LCMTy, RemergeRegs));
379 return;
380 }
381
382 llvm_unreachable("unhandled case");
383}
384
385static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
386#define RTLIBCASE_INT(LibcallPrefix) \
387 do { \
388 switch (Size) { \
389 case 32: \
390 return RTLIB::LibcallPrefix##32; \
391 case 64: \
392 return RTLIB::LibcallPrefix##64; \
393 case 128: \
394 return RTLIB::LibcallPrefix##128; \
395 default: \
396 llvm_unreachable("unexpected size"); \
397 } \
398 } while (0)
399
400#define RTLIBCASE(LibcallPrefix) \
401 do { \
402 switch (Size) { \
403 case 32: \
404 return RTLIB::LibcallPrefix##32; \
405 case 64: \
406 return RTLIB::LibcallPrefix##64; \
407 case 80: \
408 return RTLIB::LibcallPrefix##80; \
409 case 128: \
410 return RTLIB::LibcallPrefix##128; \
411 default: \
412 llvm_unreachable("unexpected size"); \
413 } \
414 } while (0)
415
416 switch (Opcode) {
417 case TargetOpcode::G_LROUND:
418 RTLIBCASE(LROUND_F);
419 case TargetOpcode::G_LLROUND:
420 RTLIBCASE(LLROUND_F);
421 case TargetOpcode::G_MUL:
422 RTLIBCASE_INT(MUL_I);
423 case TargetOpcode::G_SDIV:
424 RTLIBCASE_INT(SDIV_I);
425 case TargetOpcode::G_UDIV:
426 RTLIBCASE_INT(UDIV_I);
427 case TargetOpcode::G_SREM:
428 RTLIBCASE_INT(SREM_I);
429 case TargetOpcode::G_UREM:
430 RTLIBCASE_INT(UREM_I);
431 case TargetOpcode::G_CTLZ_ZERO_POISON:
432 RTLIBCASE_INT(CTLZ_I);
433 case TargetOpcode::G_FADD:
434 RTLIBCASE(ADD_F);
435 case TargetOpcode::G_FSUB:
436 RTLIBCASE(SUB_F);
437 case TargetOpcode::G_FMUL:
438 RTLIBCASE(MUL_F);
439 case TargetOpcode::G_FDIV:
440 RTLIBCASE(DIV_F);
441 case TargetOpcode::G_FEXP:
442 RTLIBCASE(EXP_F);
443 case TargetOpcode::G_FEXP2:
444 RTLIBCASE(EXP2_F);
445 case TargetOpcode::G_FEXP10:
446 RTLIBCASE(EXP10_F);
447 case TargetOpcode::G_FREM:
448 RTLIBCASE(REM_F);
449 case TargetOpcode::G_FPOW:
450 RTLIBCASE(POW_F);
451 case TargetOpcode::G_FPOWI:
452 RTLIBCASE(POWI_F);
453 case TargetOpcode::G_FMA:
454 RTLIBCASE(FMA_F);
455 case TargetOpcode::G_FSIN:
456 RTLIBCASE(SIN_F);
457 case TargetOpcode::G_FCOS:
458 RTLIBCASE(COS_F);
459 case TargetOpcode::G_FTAN:
460 RTLIBCASE(TAN_F);
461 case TargetOpcode::G_FASIN:
462 RTLIBCASE(ASIN_F);
463 case TargetOpcode::G_FACOS:
464 RTLIBCASE(ACOS_F);
465 case TargetOpcode::G_FATAN:
466 RTLIBCASE(ATAN_F);
467 case TargetOpcode::G_FATAN2:
468 RTLIBCASE(ATAN2_F);
469 case TargetOpcode::G_FSINH:
470 RTLIBCASE(SINH_F);
471 case TargetOpcode::G_FCOSH:
472 RTLIBCASE(COSH_F);
473 case TargetOpcode::G_FTANH:
474 RTLIBCASE(TANH_F);
475 case TargetOpcode::G_FSINCOS:
476 RTLIBCASE(SINCOS_F);
477 case TargetOpcode::G_FMODF:
478 RTLIBCASE(MODF_F);
479 case TargetOpcode::G_FLOG10:
480 RTLIBCASE(LOG10_F);
481 case TargetOpcode::G_FLOG:
482 RTLIBCASE(LOG_F);
483 case TargetOpcode::G_FLOG2:
484 RTLIBCASE(LOG2_F);
485 case TargetOpcode::G_FLDEXP:
486 RTLIBCASE(LDEXP_F);
487 case TargetOpcode::G_FCEIL:
488 RTLIBCASE(CEIL_F);
489 case TargetOpcode::G_FFLOOR:
490 RTLIBCASE(FLOOR_F);
491 case TargetOpcode::G_FMINNUM:
492 RTLIBCASE(FMIN_F);
493 case TargetOpcode::G_FMAXNUM:
494 RTLIBCASE(FMAX_F);
495 case TargetOpcode::G_FMINIMUMNUM:
496 RTLIBCASE(FMINIMUM_NUM_F);
497 case TargetOpcode::G_FMAXIMUMNUM:
498 RTLIBCASE(FMAXIMUM_NUM_F);
499 case TargetOpcode::G_FSQRT:
500 RTLIBCASE(SQRT_F);
501 case TargetOpcode::G_FRINT:
502 RTLIBCASE(RINT_F);
503 case TargetOpcode::G_FNEARBYINT:
504 RTLIBCASE(NEARBYINT_F);
505 case TargetOpcode::G_INTRINSIC_TRUNC:
506 RTLIBCASE(TRUNC_F);
507 case TargetOpcode::G_INTRINSIC_ROUND:
508 RTLIBCASE(ROUND_F);
509 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
510 RTLIBCASE(ROUNDEVEN_F);
511 case TargetOpcode::G_INTRINSIC_LRINT:
512 RTLIBCASE(LRINT_F);
513 case TargetOpcode::G_INTRINSIC_LLRINT:
514 RTLIBCASE(LLRINT_F);
515 }
516 llvm_unreachable("Unknown libcall function");
517#undef RTLIBCASE_INT
518#undef RTLIBCASE
519}
520
522 const TargetLowering &TLI = *MF.getSubtarget().getTargetLowering();
523 return TLI.supportSwiftError() &&
524 MF.getFunction().getAttributes().hasAttrSomewhere(
525 Attribute::SwiftError);
526}
527
528/// True if an instruction is in tail position in its caller. Intended for
529/// legalizing libcalls as tail calls when possible.
532 const TargetInstrInfo &TII,
533 MachineRegisterInfo &MRI) {
534 MachineBasicBlock &MBB = *MI.getParent();
535 const Function &F = MBB.getParent()->getFunction();
536
537 // Conservatively require the attributes of the call to match those of
538 // the return. Ignore NoAlias and NonNull because they don't affect the
539 // call sequence.
540 AttributeList CallerAttrs = F.getAttributes();
541 if (AttrBuilder(F.getContext(), CallerAttrs.getRetAttrs())
542 .removeAttribute(Attribute::NoAlias)
543 .removeAttribute(Attribute::NonNull)
544 .hasAttributes())
545 return false;
546
547 // It's not safe to eliminate the sign / zero extension of the return value.
548 if (CallerAttrs.hasRetAttr(Attribute::ZExt) ||
549 CallerAttrs.hasRetAttr(Attribute::SExt))
550 return false;
551
552 // Only tail call if the following instruction is a standard return or if we
553 // have a `thisreturn` callee, and a sequence like:
554 //
555 // G_MEMCPY %0, %1, %2
556 // $x0 = COPY %0
557 // RET_ReallyLR implicit $x0
558 auto Next = next_nodbg(MI.getIterator(), MBB.instr_end());
559 if (Next != MBB.instr_end() && Next->isCopy()) {
560 if (MI.getOpcode() == TargetOpcode::G_BZERO)
561 return false;
562
563 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
564 // mempy/etc routines return the same parameter. For other it will be the
565 // returned value.
566 Register VReg = MI.getOperand(0).getReg();
567 if (!VReg.isVirtual() || VReg != Next->getOperand(1).getReg())
568 return false;
569
570 Register PReg = Next->getOperand(0).getReg();
571 if (!PReg.isPhysical())
572 return false;
573
574 auto Ret = next_nodbg(Next, MBB.instr_end());
575 if (Ret == MBB.instr_end() || !Ret->isReturn())
576 return false;
577
578 if (Ret->getNumImplicitOperands() != 1)
579 return false;
580
581 if (!Ret->getOperand(0).isReg() || PReg != Ret->getOperand(0).getReg())
582 return false;
583
584 // Skip over the COPY that we just validated.
585 Next = Ret;
586 }
587
588 if (Next == MBB.instr_end() || TII.isTailCall(*Next) || !Next->isReturn())
589 return false;
590
591 return true;
592}
593
595 const char *Name, const CallLowering::ArgInfo &Result,
597 LostDebugLocObserver &LocObserver, MachineInstr *MI) const {
598 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
599
601 Info.CallConv = CC;
602 Info.Callee = MachineOperand::CreateES(Name);
603 Info.OrigRet = Result;
604 if (MI)
605 Info.IsTailCall =
606 (Result.Ty->isVoidTy() ||
607 Result.Ty == MIRBuilder.getMF().getFunction().getReturnType()) &&
608 isLibCallInTailPosition(Result, *MI, MIRBuilder.getTII(),
609 *MIRBuilder.getMRI()) &&
610 // Lowering doesn't support tail calling inside a function with
611 // a swifterror argument yet.
613
614 llvm::append_range(Info.OrigArgs, Args);
615 if (!CLI.lowerCall(MIRBuilder, Info))
617
618 if (MI && Info.LoweredTailCall) {
619 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
620
621 // Check debug locations before removing the return.
622 LocObserver.checkpoint(true);
623
624 // We must have a return following the call (or debug insts) to get past
625 // isLibCallInTailPosition.
626 do {
627 MachineInstr *Next = MI->getNextNode();
628 assert(Next &&
629 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
630 "Expected instr following MI to be return or debug inst?");
631 // We lowered a tail call, so the call is now the return from the block.
632 // Delete the old return.
633 Next->eraseFromParent();
634 } while (MI->getNextNode());
635
636 // We expect to lose the debug location from the return.
637 LocObserver.checkpoint(false);
638 }
640}
641
643 RTLIB::Libcall Libcall, const CallLowering::ArgInfo &Result,
645 MachineInstr *MI) const {
646 if (!Libcalls)
648
649 RTLIB::LibcallImpl LibcallImpl = Libcalls->getLibcallImpl(Libcall);
650 if (LibcallImpl == RTLIB::Unsupported)
652
654 const CallingConv::ID CC = Libcalls->getLibcallImplCallingConv(LibcallImpl);
655 return createLibcall(Name.data(), Result, Args, CC, LocObserver, MI);
656}
657
658// Useful for libcalls where all operands have the same type.
661 unsigned Size, Type *OpType,
662 LostDebugLocObserver &LocObserver) const {
663 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
664
665 // FIXME: What does the original arg index mean here?
667 for (const MachineOperand &MO : llvm::drop_begin(MI.operands()))
668 Args.push_back({MO.getReg(), OpType, 0});
669 return createLibcall(Libcall, {MI.getOperand(0).getReg(), OpType, 0}, Args,
670 LocObserver, &MI);
671}
672
673LegalizerHelper::LegalizeResult LegalizerHelper::emitSincosLibcall(
674 MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size, Type *OpType,
675 LostDebugLocObserver &LocObserver) {
676 MachineFunction &MF = *MI.getMF();
678
679 Register DstSin = MI.getOperand(0).getReg();
680 Register DstCos = MI.getOperand(1).getReg();
681 Register Src = MI.getOperand(2).getReg();
682 LLT DstTy = MRI.getType(DstSin);
683
684 int MemSize = DstTy.getSizeInBytes();
685 Align Alignment = getStackTemporaryAlignment(DstTy);
687 unsigned AddrSpace = DL.getAllocaAddrSpace();
688 MachinePointerInfo PtrInfo;
689
690 Register StackPtrSin =
691 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
692 .getReg(0);
693 Register StackPtrCos =
694 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
695 .getReg(0);
696
697 auto &Ctx = MF.getFunction().getContext();
698 auto LibcallResult = createLibcall(
699 getRTLibDesc(MI.getOpcode(), Size), {{0}, Type::getVoidTy(Ctx), 0},
700 {{Src, OpType, 0},
701 {StackPtrSin, PointerType::get(Ctx, AddrSpace), 1},
702 {StackPtrCos, PointerType::get(Ctx, AddrSpace), 2}},
703 LocObserver, &MI);
704
705 if (LibcallResult != LegalizeResult::Legalized)
707
709 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
711 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
712
713 MIRBuilder.buildLoad(DstSin, StackPtrSin, *LoadMMOSin);
714 MIRBuilder.buildLoad(DstCos, StackPtrCos, *LoadMMOCos);
715 MI.eraseFromParent();
716
718}
719
721LegalizerHelper::emitModfLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder,
722 unsigned Size, Type *OpType,
723 LostDebugLocObserver &LocObserver) {
724 MachineFunction &MF = MIRBuilder.getMF();
725 MachineRegisterInfo &MRI = MF.getRegInfo();
726
727 Register DstFrac = MI.getOperand(0).getReg();
728 Register DstInt = MI.getOperand(1).getReg();
729 Register Src = MI.getOperand(2).getReg();
730 LLT DstTy = MRI.getType(DstFrac);
731
732 int MemSize = DstTy.getSizeInBytes();
734 const DataLayout &DL = MIRBuilder.getDataLayout();
735 unsigned AddrSpace = DL.getAllocaAddrSpace();
736 MachinePointerInfo PtrInfo;
737
738 Register StackPtrInt =
739 createStackTemporary(TypeSize::getFixed(MemSize), Alignment, PtrInfo)
740 .getReg(0);
741
742 auto &Ctx = MF.getFunction().getContext();
743 auto LibcallResult = createLibcall(
744 getRTLibDesc(MI.getOpcode(), Size), {DstFrac, OpType, 0},
745 {{Src, OpType, 0}, {StackPtrInt, PointerType::get(Ctx, AddrSpace), 1}},
746 LocObserver, &MI);
747
748 if (LibcallResult != LegalizeResult::Legalized)
750
752 PtrInfo, MachineMemOperand::MOLoad, MemSize, Alignment);
753
754 MIRBuilder.buildLoad(DstInt, StackPtrInt, *LoadMMOInt);
755 MI.eraseFromParent();
756
758}
759
760static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
761 Type *FromType) {
762 auto ToMVT = MVT::getVT(ToType);
763 auto FromMVT = MVT::getVT(FromType);
764
765 switch (Opcode) {
766 case TargetOpcode::G_FPEXT:
767 return RTLIB::getFPEXT(FromMVT, ToMVT);
768 case TargetOpcode::G_FPTRUNC:
769 return RTLIB::getFPROUND(FromMVT, ToMVT);
770 case TargetOpcode::G_FPTOSI:
771 return RTLIB::getFPTOSINT(FromMVT, ToMVT);
772 case TargetOpcode::G_FPTOUI:
773 return RTLIB::getFPTOUINT(FromMVT, ToMVT);
774 case TargetOpcode::G_SITOFP:
775 return RTLIB::getSINTTOFP(FromMVT, ToMVT);
776 case TargetOpcode::G_UITOFP:
777 return RTLIB::getUINTTOFP(FromMVT, ToMVT);
778 }
779 llvm_unreachable("Unsupported libcall function");
780}
781
783 MachineInstr &MI, Type *ToType, Type *FromType,
784 LostDebugLocObserver &LocObserver, bool IsSigned) const {
785 CallLowering::ArgInfo Arg = {MI.getOperand(1).getReg(), FromType, 0};
786 if (FromType->isIntegerTy()) {
787 if (TLI.shouldSignExtendTypeInLibCall(FromType, IsSigned))
788 Arg.Flags[0].setSExt();
789 else
790 Arg.Flags[0].setZExt();
791 }
792
793 RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
794 return createLibcall(Libcall, {MI.getOperand(0).getReg(), ToType, 0}, Arg,
795 LocObserver, &MI);
796}
797
800 LostDebugLocObserver &LocObserver) const {
801 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
802
804 // Add all the args, except for the last which is an imm denoting 'tail'.
805 for (unsigned i = 0; i < MI.getNumOperands() - 1; ++i) {
806 Register Reg = MI.getOperand(i).getReg();
807
808 // Need derive an IR type for call lowering.
809 LLT OpLLT = MRI.getType(Reg);
810 Type *OpTy = nullptr;
811 if (OpLLT.isPointer())
812 OpTy = PointerType::get(Ctx, OpLLT.getAddressSpace());
813 else
814 OpTy = IntegerType::get(Ctx, OpLLT.getSizeInBits());
815 Args.push_back({Reg, OpTy, 0});
816 }
817
818 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
819 RTLIB::Libcall RTLibcall;
820 unsigned Opc = MI.getOpcode();
821 switch (Opc) {
822 case TargetOpcode::G_BZERO:
823 RTLibcall = RTLIB::BZERO;
824 break;
825 case TargetOpcode::G_MEMCPY:
826 RTLibcall = RTLIB::MEMCPY;
827 Args[0].Flags[0].setReturned();
828 break;
829 case TargetOpcode::G_MEMMOVE:
830 RTLibcall = RTLIB::MEMMOVE;
831 Args[0].Flags[0].setReturned();
832 break;
833 case TargetOpcode::G_MEMSET:
834 RTLibcall = RTLIB::MEMSET;
835 Args[0].Flags[0].setReturned();
836 break;
837 default:
838 llvm_unreachable("unsupported opcode");
839 }
840
841 if (!Libcalls) // FIXME: Should be mandatory
843
844 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
845
846 // Unsupported libcall on the target.
847 if (RTLibcallImpl == RTLIB::Unsupported) {
848 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
849 << MIRBuilder.getTII().getName(Opc) << "\n");
851 }
852
854 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
855
856 StringRef LibcallName =
858 Info.Callee = MachineOperand::CreateES(LibcallName.data());
859 Info.OrigRet = CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0);
860 Info.IsTailCall =
861 MI.getOperand(MI.getNumOperands() - 1).getImm() &&
862 isLibCallInTailPosition(Info.OrigRet, MI, MIRBuilder.getTII(), MRI) &&
863 // Lowering doesn't support tail calling inside a function with
864 // a swifterror argument yet.
866
867 llvm::append_range(Info.OrigArgs, Args);
868 if (!CLI.lowerCall(MIRBuilder, Info))
870
871 if (Info.LoweredTailCall) {
872 assert(Info.IsTailCall && "Lowered tail call when it wasn't a tail call?");
873
874 // Check debug locations before removing the return.
875 LocObserver.checkpoint(true);
876
877 // We must have a return following the call (or debug insts) to get past
878 // isLibCallInTailPosition.
879 do {
880 MachineInstr *Next = MI.getNextNode();
881 assert(Next &&
882 (Next->isCopy() || Next->isReturn() || Next->isDebugInstr()) &&
883 "Expected instr following MI to be return or debug inst?");
884 // We lowered a tail call, so the call is now the return from the block.
885 // Delete the old return.
886 Next->eraseFromParent();
887 } while (MI.getNextNode());
888
889 // We expect to lose the debug location from the return.
890 LocObserver.checkpoint(false);
891 }
892
894}
895
896static RTLIB::Libcall getOutlineAtomicLibcall(MachineInstr &MI) {
897 unsigned Opc = MI.getOpcode();
898 auto &AtomicMI = cast<GMemOperation>(MI);
899 auto &MMO = AtomicMI.getMMO();
900 auto Ordering = MMO.getMergedOrdering();
901 LLT MemType = MMO.getMemoryType();
902 uint64_t MemSize = MemType.getSizeInBytes();
903 if (MemType.isVector())
904 return RTLIB::UNKNOWN_LIBCALL;
905
906#define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
907#define LCALL5(A) \
908 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
909 switch (Opc) {
910 case TargetOpcode::G_ATOMIC_CMPXCHG:
911 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
912 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS)};
913 return getOutlineAtomicHelper(LC, Ordering, MemSize);
914 }
915 case TargetOpcode::G_ATOMICRMW_XCHG: {
916 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP)};
917 return getOutlineAtomicHelper(LC, Ordering, MemSize);
918 }
919 case TargetOpcode::G_ATOMICRMW_ADD:
920 case TargetOpcode::G_ATOMICRMW_SUB: {
921 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD)};
922 return getOutlineAtomicHelper(LC, Ordering, MemSize);
923 }
924 case TargetOpcode::G_ATOMICRMW_AND: {
925 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR)};
926 return getOutlineAtomicHelper(LC, Ordering, MemSize);
927 }
928 case TargetOpcode::G_ATOMICRMW_OR: {
929 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET)};
930 return getOutlineAtomicHelper(LC, Ordering, MemSize);
931 }
932 case TargetOpcode::G_ATOMICRMW_XOR: {
933 const RTLIB::Libcall LC[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR)};
934 return getOutlineAtomicHelper(LC, Ordering, MemSize);
935 }
936 default:
937 return RTLIB::UNKNOWN_LIBCALL;
938 }
939#undef LCALLS
940#undef LCALL5
941}
942
945 auto &Ctx = MIRBuilder.getContext();
946
947 Type *RetTy;
948 SmallVector<Register> RetRegs;
950 unsigned Opc = MI.getOpcode();
951 switch (Opc) {
952 case TargetOpcode::G_ATOMIC_CMPXCHG:
953 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
955 LLT SuccessLLT;
956 auto [Ret, RetLLT, Mem, MemLLT, Cmp, CmpLLT, New, NewLLT] =
957 MI.getFirst4RegLLTs();
958 RetRegs.push_back(Ret);
959 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
960 if (Opc == TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS) {
961 std::tie(Ret, RetLLT, Success, SuccessLLT, Mem, MemLLT, Cmp, CmpLLT, New,
962 NewLLT) = MI.getFirst5RegLLTs();
963 RetRegs.push_back(Success);
964 RetTy = StructType::get(
965 Ctx, {RetTy, IntegerType::get(Ctx, SuccessLLT.getSizeInBits())});
966 }
967 Args.push_back({Cmp, IntegerType::get(Ctx, CmpLLT.getSizeInBits()), 0});
968 Args.push_back({New, IntegerType::get(Ctx, NewLLT.getSizeInBits()), 0});
969 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
970 break;
971 }
972 case TargetOpcode::G_ATOMICRMW_XCHG:
973 case TargetOpcode::G_ATOMICRMW_ADD:
974 case TargetOpcode::G_ATOMICRMW_SUB:
975 case TargetOpcode::G_ATOMICRMW_AND:
976 case TargetOpcode::G_ATOMICRMW_OR:
977 case TargetOpcode::G_ATOMICRMW_XOR: {
978 auto [Ret, RetLLT, Mem, MemLLT, Val, ValLLT] = MI.getFirst3RegLLTs();
979 RetRegs.push_back(Ret);
980 RetTy = IntegerType::get(Ctx, RetLLT.getSizeInBits());
981 if (Opc == TargetOpcode::G_ATOMICRMW_AND)
982 Val =
983 MIRBuilder.buildXor(ValLLT, MIRBuilder.buildConstant(ValLLT, -1), Val)
984 .getReg(0);
985 else if (Opc == TargetOpcode::G_ATOMICRMW_SUB)
986 Val =
987 MIRBuilder.buildSub(ValLLT, MIRBuilder.buildConstant(ValLLT, 0), Val)
988 .getReg(0);
989 Args.push_back({Val, IntegerType::get(Ctx, ValLLT.getSizeInBits()), 0});
990 Args.push_back({Mem, PointerType::get(Ctx, MemLLT.getAddressSpace()), 0});
991 break;
992 }
993 default:
994 llvm_unreachable("unsupported opcode");
995 }
996
997 if (!Libcalls) // FIXME: Should be mandatory
999
1000 auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
1001 RTLIB::Libcall RTLibcall = getOutlineAtomicLibcall(MI);
1002 RTLIB::LibcallImpl RTLibcallImpl = Libcalls->getLibcallImpl(RTLibcall);
1003
1004 // Unsupported libcall on the target.
1005 if (RTLibcallImpl == RTLIB::Unsupported) {
1006 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
1007 << MIRBuilder.getTII().getName(Opc) << "\n");
1009 }
1010
1012 Info.CallConv = Libcalls->getLibcallImplCallingConv(RTLibcallImpl);
1013
1014 StringRef LibcallName =
1016 Info.Callee = MachineOperand::CreateES(LibcallName.data());
1017 Info.OrigRet = CallLowering::ArgInfo(RetRegs, RetTy, 0);
1018
1019 llvm::append_range(Info.OrigArgs, Args);
1020 if (!CLI.lowerCall(MIRBuilder, Info))
1022
1024}
1025
1026static RTLIB::Libcall
1028 RTLIB::Libcall RTLibcall;
1029 switch (MI.getOpcode()) {
1030 case TargetOpcode::G_GET_FPENV:
1031 RTLibcall = RTLIB::FEGETENV;
1032 break;
1033 case TargetOpcode::G_SET_FPENV:
1034 case TargetOpcode::G_RESET_FPENV:
1035 RTLibcall = RTLIB::FESETENV;
1036 break;
1037 case TargetOpcode::G_GET_FPMODE:
1038 RTLibcall = RTLIB::FEGETMODE;
1039 break;
1040 case TargetOpcode::G_SET_FPMODE:
1041 case TargetOpcode::G_RESET_FPMODE:
1042 RTLibcall = RTLIB::FESETMODE;
1043 break;
1044 default:
1045 llvm_unreachable("Unexpected opcode");
1046 }
1047 return RTLibcall;
1048}
1049
1050// Some library functions that read FP state (fegetmode, fegetenv) write the
1051// state into a region in memory. IR intrinsics that do the same operations
1052// (get_fpmode, get_fpenv) return the state as integer value. To implement these
1053// intrinsics via the library functions, we need to use temporary variable,
1054// for example:
1055//
1056// %0:_(s32) = G_GET_FPMODE
1057//
1058// is transformed to:
1059//
1060// %1:_(p0) = G_FRAME_INDEX %stack.0
1061// BL &fegetmode
1062// %0:_(s32) = G_LOAD % 1
1063//
1065LegalizerHelper::createGetStateLibcall(MachineInstr &MI,
1066 LostDebugLocObserver &LocObserver) {
1067 const DataLayout &DL = MIRBuilder.getDataLayout();
1068 auto &MF = MIRBuilder.getMF();
1069 auto &MRI = *MIRBuilder.getMRI();
1070 auto &Ctx = MF.getFunction().getContext();
1071
1072 // Create temporary, where library function will put the read state.
1073 Register Dst = MI.getOperand(0).getReg();
1074 LLT StateTy = MRI.getType(Dst);
1075 TypeSize StateSize = StateTy.getSizeInBytes();
1076 Align TempAlign = getStackTemporaryAlignment(StateTy);
1077 MachinePointerInfo TempPtrInfo;
1078 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1079
1080 // Create a call to library function, with the temporary as an argument.
1081 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1082 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1083 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1084 auto Res = createLibcall(
1085 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1086 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}), LocObserver,
1087 nullptr);
1088 if (Res != LegalizerHelper::Legalized)
1089 return Res;
1090
1091 // Create a load from the temporary.
1092 MachineMemOperand *MMO = MF.getMachineMemOperand(
1093 TempPtrInfo, MachineMemOperand::MOLoad, StateTy, TempAlign);
1094 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, Dst, Temp, *MMO);
1095
1097}
1098
1099// Similar to `createGetStateLibcall` the function calls a library function
1100// using transient space in stack. In this case the library function reads
1101// content of memory region.
1103LegalizerHelper::createSetStateLibcall(MachineInstr &MI,
1104 LostDebugLocObserver &LocObserver) {
1105 const DataLayout &DL = MIRBuilder.getDataLayout();
1106 auto &MF = MIRBuilder.getMF();
1107 auto &MRI = *MIRBuilder.getMRI();
1108 auto &Ctx = MF.getFunction().getContext();
1109
1110 // Create temporary, where library function will get the new state.
1111 Register Src = MI.getOperand(0).getReg();
1112 LLT StateTy = MRI.getType(Src);
1113 TypeSize StateSize = StateTy.getSizeInBytes();
1114 Align TempAlign = getStackTemporaryAlignment(StateTy);
1115 MachinePointerInfo TempPtrInfo;
1116 auto Temp = createStackTemporary(StateSize, TempAlign, TempPtrInfo);
1117
1118 // Put the new state into the temporary.
1119 MachineMemOperand *MMO = MF.getMachineMemOperand(
1120 TempPtrInfo, MachineMemOperand::MOStore, StateTy, TempAlign);
1121 MIRBuilder.buildStore(Src, Temp, *MMO);
1122
1123 // Create a call to library function, with the temporary as an argument.
1124 unsigned TempAddrSpace = DL.getAllocaAddrSpace();
1125 Type *StatePtrTy = PointerType::get(Ctx, TempAddrSpace);
1126 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1127 return createLibcall(RTLibcall,
1128 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1129 CallLowering::ArgInfo({Temp.getReg(0), StatePtrTy, 0}),
1130 LocObserver, nullptr);
1131}
1132
1133/// Returns the corresponding libcall for the given Pred and
1134/// the ICMP predicate that should be generated to compare with #0
1135/// after the libcall.
1136static std::pair<RTLIB::Libcall, CmpInst::Predicate>
1138#define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1139 do { \
1140 switch (Size) { \
1141 case 32: \
1142 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1143 case 64: \
1144 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1145 case 128: \
1146 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1147 default: \
1148 llvm_unreachable("unexpected size"); \
1149 } \
1150 } while (0)
1151
1152 // These use the three-way (-1/0/1) compare libcalls, whose result is tested
1153 // against 0 with a signed integer predicate. Unordered (UO) is a boolean.
1154 switch (Pred) {
1155 case CmpInst::FCMP_OEQ:
1156 RTLIBCASE_CMP(FCMP3_PRED_OEQ_F, CmpInst::ICMP_EQ);
1157 case CmpInst::FCMP_UNE:
1158 RTLIBCASE_CMP(FCMP3_PRED_UNE_F, CmpInst::ICMP_NE);
1159 case CmpInst::FCMP_OGE:
1160 RTLIBCASE_CMP(FCMP3_PRED_OGE_F, CmpInst::ICMP_SGE);
1161 case CmpInst::FCMP_OLT:
1162 RTLIBCASE_CMP(FCMP3_PRED_OLT_F, CmpInst::ICMP_SLT);
1163 case CmpInst::FCMP_OLE:
1164 RTLIBCASE_CMP(FCMP3_PRED_OLE_F, CmpInst::ICMP_SLE);
1165 case CmpInst::FCMP_OGT:
1166 RTLIBCASE_CMP(FCMP3_PRED_OGT_F, CmpInst::ICMP_SGT);
1167 case CmpInst::FCMP_UNO:
1169 default:
1170 return {RTLIB::UNKNOWN_LIBCALL, CmpInst::BAD_ICMP_PREDICATE};
1171 }
1172}
1173
1175LegalizerHelper::createFCMPLibcall(MachineInstr &MI,
1176 LostDebugLocObserver &LocObserver) {
1177 auto &MF = MIRBuilder.getMF();
1178 auto &Ctx = MF.getFunction().getContext();
1179 const GFCmp *Cmp = cast<GFCmp>(&MI);
1180
1181 LLT OpLLT = MRI.getType(Cmp->getLHSReg());
1182 unsigned Size = OpLLT.getSizeInBits();
1183 if ((Size != 32 && Size != 64 && Size != 128) ||
1184 OpLLT != MRI.getType(Cmp->getRHSReg()))
1185 return UnableToLegalize;
1186
1187 Type *OpType = getFloatTypeForLLT(Ctx, OpLLT);
1188
1189 // DstReg type is s32
1190 const Register DstReg = Cmp->getReg(0);
1191 LLT DstTy = MRI.getType(DstReg);
1192 const auto Cond = Cmp->getCond();
1193
1194 // Reference:
1195 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1196 // Generates a libcall followed by ICMP.
1197 const auto BuildLibcall = [&](const RTLIB::Libcall Libcall,
1198 const CmpInst::Predicate ICmpPred,
1199 const DstOp &Res) -> Register {
1200 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1201 LLT TempLLT = LLT::integer(32);
1202 Register Temp = MRI.createGenericVirtualRegister(TempLLT);
1203 // Generate libcall, holding result in Temp
1204 const auto Status = createLibcall(
1205 Libcall, {Temp, Type::getInt32Ty(Ctx), 0},
1206 {{Cmp->getLHSReg(), OpType, 0}, {Cmp->getRHSReg(), OpType, 1}},
1207 LocObserver, &MI);
1208 if (!Status)
1209 return {};
1210
1211 // Compare temp with #0 to get the final result.
1212 return MIRBuilder
1213 .buildICmp(ICmpPred, Res, Temp, MIRBuilder.buildConstant(TempLLT, 0))
1214 .getReg(0);
1215 };
1216
1217 // Simple case if we have a direct mapping from predicate to libcall
1218 if (const auto [Libcall, ICmpPred] = getFCMPLibcallDesc(Cond, Size);
1219 Libcall != RTLIB::UNKNOWN_LIBCALL &&
1220 ICmpPred != CmpInst::BAD_ICMP_PREDICATE) {
1221 if (BuildLibcall(Libcall, ICmpPred, DstReg)) {
1222 return Legalized;
1223 }
1224 return UnableToLegalize;
1225 }
1226
1227 // No direct mapping found, should be generated as combination of libcalls.
1228
1229 switch (Cond) {
1230 case CmpInst::FCMP_UEQ: {
1231 // FCMP_UEQ: unordered or equal
1232 // Convert into (FCMP_OEQ || FCMP_UNO).
1233
1234 const auto [OeqLibcall, OeqPred] =
1236 const auto Oeq = BuildLibcall(OeqLibcall, OeqPred, DstTy);
1237
1238 const auto [UnoLibcall, UnoPred] =
1240 const auto Uno = BuildLibcall(UnoLibcall, UnoPred, DstTy);
1241 if (Oeq && Uno)
1242 MIRBuilder.buildOr(DstReg, Oeq, Uno);
1243 else
1244 return UnableToLegalize;
1245
1246 break;
1247 }
1248 case CmpInst::FCMP_ONE: {
1249 // FCMP_ONE: ordered and operands are unequal
1250 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1251
1252 // We inverse the predicate instead of generating a NOT
1253 // to save one instruction.
1254 // On AArch64 isel can even select two cmp into a single ccmp.
1255 const auto [OeqLibcall, OeqPred] =
1257 const auto NotOeq =
1258 BuildLibcall(OeqLibcall, CmpInst::getInversePredicate(OeqPred), DstTy);
1259
1260 const auto [UnoLibcall, UnoPred] =
1262 const auto NotUno =
1263 BuildLibcall(UnoLibcall, CmpInst::getInversePredicate(UnoPred), DstTy);
1264
1265 if (NotOeq && NotUno)
1266 MIRBuilder.buildAnd(DstReg, NotOeq, NotUno);
1267 else
1268 return UnableToLegalize;
1269
1270 break;
1271 }
1272 case CmpInst::FCMP_ULT:
1273 case CmpInst::FCMP_UGE:
1274 case CmpInst::FCMP_UGT:
1275 case CmpInst::FCMP_ULE:
1276 case CmpInst::FCMP_ORD: {
1277 // Convert into: !(inverse(Pred))
1278 // E.g. FCMP_ULT becomes !FCMP_OGE
1279 // This is equivalent to the following, but saves some instructions.
1280 // MIRBuilder.buildNot(
1281 // PredTy,
1282 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1283 // Op1, Op2));
1284 const auto [InversedLibcall, InversedPred] =
1286 if (!BuildLibcall(InversedLibcall,
1287 CmpInst::getInversePredicate(InversedPred), DstReg))
1288 return UnableToLegalize;
1289 break;
1290 }
1291 default:
1292 return UnableToLegalize;
1293 }
1294
1295 return Legalized;
1296}
1297
1298// The function is used to legalize operations that set default environment
1299// state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1300// On most targets supported in glibc FE_DFL_MODE is defined as
1301// `((const femode_t *) -1)`. Such assumption is used here. If for some target
1302// it is not true, the target must provide custom lowering.
1304LegalizerHelper::createResetStateLibcall(MachineInstr &MI,
1305 LostDebugLocObserver &LocObserver) {
1306 const DataLayout &DL = MIRBuilder.getDataLayout();
1307 auto &MF = MIRBuilder.getMF();
1308 auto &Ctx = MF.getFunction().getContext();
1309
1310 // Create an argument for the library function.
1311 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
1312 Type *StatePtrTy = PointerType::get(Ctx, AddrSpace);
1313 unsigned PtrSize = DL.getPointerSizeInBits(AddrSpace);
1314 LLT MemTy = LLT::pointer(AddrSpace, PtrSize);
1315 auto DefValue = MIRBuilder.buildConstant(LLT::integer(PtrSize), -1LL);
1316 DstOp Dest(MRI.createGenericVirtualRegister(MemTy));
1317 MIRBuilder.buildIntToPtr(Dest, DefValue);
1318
1319 RTLIB::Libcall RTLibcall = getStateLibraryFunctionFor(MI, TLI);
1320 return createLibcall(
1321 RTLibcall, CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx), 0),
1322 CallLowering::ArgInfo({Dest.getReg(), StatePtrTy, 0}), LocObserver, &MI);
1323}
1324
1327 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
1328
1329 switch (MI.getOpcode()) {
1330 default:
1331 return UnableToLegalize;
1332 case TargetOpcode::G_MUL:
1333 case TargetOpcode::G_SDIV:
1334 case TargetOpcode::G_UDIV:
1335 case TargetOpcode::G_SREM:
1336 case TargetOpcode::G_UREM:
1337 case TargetOpcode::G_CTLZ_ZERO_POISON: {
1338 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1339 unsigned Size = LLTy.getSizeInBits();
1340 Type *HLTy = IntegerType::get(Ctx, Size);
1341 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1342 if (Status != Legalized)
1343 return Status;
1344 break;
1345 }
1346 case TargetOpcode::G_FADD:
1347 case TargetOpcode::G_FSUB:
1348 case TargetOpcode::G_FMUL:
1349 case TargetOpcode::G_FDIV:
1350 case TargetOpcode::G_FMA:
1351 case TargetOpcode::G_FPOW:
1352 case TargetOpcode::G_FREM:
1353 case TargetOpcode::G_FCOS:
1354 case TargetOpcode::G_FSIN:
1355 case TargetOpcode::G_FTAN:
1356 case TargetOpcode::G_FACOS:
1357 case TargetOpcode::G_FASIN:
1358 case TargetOpcode::G_FATAN:
1359 case TargetOpcode::G_FATAN2:
1360 case TargetOpcode::G_FCOSH:
1361 case TargetOpcode::G_FSINH:
1362 case TargetOpcode::G_FTANH:
1363 case TargetOpcode::G_FLOG10:
1364 case TargetOpcode::G_FLOG:
1365 case TargetOpcode::G_FLOG2:
1366 case TargetOpcode::G_FEXP:
1367 case TargetOpcode::G_FEXP2:
1368 case TargetOpcode::G_FEXP10:
1369 case TargetOpcode::G_FCEIL:
1370 case TargetOpcode::G_FFLOOR:
1371 case TargetOpcode::G_FMINNUM:
1372 case TargetOpcode::G_FMAXNUM:
1373 case TargetOpcode::G_FMINIMUMNUM:
1374 case TargetOpcode::G_FMAXIMUMNUM:
1375 case TargetOpcode::G_FSQRT:
1376 case TargetOpcode::G_FRINT:
1377 case TargetOpcode::G_FNEARBYINT:
1378 case TargetOpcode::G_INTRINSIC_TRUNC:
1379 case TargetOpcode::G_INTRINSIC_ROUND:
1380 case TargetOpcode::G_INTRINSIC_ROUNDEVEN: {
1381 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1382 unsigned Size = LLTy.getSizeInBits();
1383 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1384 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1385 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1386 return UnableToLegalize;
1387 }
1388 auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1389 if (Status != Legalized)
1390 return Status;
1391 break;
1392 }
1393 case TargetOpcode::G_FSINCOS: {
1394 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1395 unsigned Size = LLTy.getSizeInBits();
1396 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1397 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1398 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1399 return UnableToLegalize;
1400 }
1401 return emitSincosLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1402 }
1403 case TargetOpcode::G_FMODF: {
1404 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1405 unsigned Size = LLTy.getSizeInBits();
1406 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1407 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1408 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1409 return UnableToLegalize;
1410 }
1411 return emitModfLibcall(MI, MIRBuilder, Size, HLTy, LocObserver);
1412 }
1413 case TargetOpcode::G_LROUND:
1414 case TargetOpcode::G_LLROUND:
1415 case TargetOpcode::G_INTRINSIC_LRINT:
1416 case TargetOpcode::G_INTRINSIC_LLRINT: {
1417 LLT LLTy = MRI.getType(MI.getOperand(1).getReg());
1418 unsigned Size = LLTy.getSizeInBits();
1419 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1420 Type *ITy = IntegerType::get(
1421 Ctx, MRI.getType(MI.getOperand(0).getReg()).getSizeInBits());
1422 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1423 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1424 return UnableToLegalize;
1425 }
1426 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1428 createLibcall(Libcall, {MI.getOperand(0).getReg(), ITy, 0},
1429 {{MI.getOperand(1).getReg(), HLTy, 0}}, LocObserver, &MI);
1430 if (Status != Legalized)
1431 return Status;
1432 MI.eraseFromParent();
1433 return Legalized;
1434 }
1435 case TargetOpcode::G_FPOWI:
1436 case TargetOpcode::G_FLDEXP: {
1437 LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
1438 unsigned Size = LLTy.getSizeInBits();
1439 Type *HLTy = getFloatTypeForLLT(Ctx, LLTy);
1440 Type *ITy = IntegerType::get(
1441 Ctx, MRI.getType(MI.getOperand(2).getReg()).getSizeInBits());
1442 if (!HLTy || (Size != 32 && Size != 64 && Size != 80 && Size != 128)) {
1443 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy << ".\n");
1444 return UnableToLegalize;
1445 }
1446 auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
1448 {MI.getOperand(1).getReg(), HLTy, 0},
1449 {MI.getOperand(2).getReg(), ITy, 1}};
1450 Args[1].Flags[0].setSExt();
1452 Libcall, {MI.getOperand(0).getReg(), HLTy, 0}, Args, LocObserver, &MI);
1453 if (Status != Legalized)
1454 return Status;
1455 break;
1456 }
1457 case TargetOpcode::G_FPEXT:
1458 case TargetOpcode::G_FPTRUNC: {
1459 Type *FromTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1460 Type *ToTy = getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1461 if (!FromTy || !ToTy)
1462 return UnableToLegalize;
1463 LegalizeResult Status = conversionLibcall(MI, ToTy, FromTy, LocObserver);
1464 if (Status != Legalized)
1465 return Status;
1466 break;
1467 }
1468 case TargetOpcode::G_FCMP: {
1469 LegalizeResult Status = createFCMPLibcall(MI, LocObserver);
1470 if (Status != Legalized)
1471 return Status;
1472 MI.eraseFromParent();
1473 return Status;
1474 }
1475 case TargetOpcode::G_FPTOSI:
1476 case TargetOpcode::G_FPTOUI: {
1477 // FIXME: Support other types
1478 Type *FromTy =
1479 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(1).getReg()));
1480 unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1481 if ((ToSize != 32 && ToSize != 64 && ToSize != 128) || !FromTy)
1482 return UnableToLegalize;
1484 FromTy, LocObserver);
1485 if (Status != Legalized)
1486 return Status;
1487 break;
1488 }
1489 case TargetOpcode::G_SITOFP:
1490 case TargetOpcode::G_UITOFP: {
1491 unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1492 Type *ToTy =
1493 getFloatTypeForLLT(Ctx, MRI.getType(MI.getOperand(0).getReg()));
1494 if ((FromSize != 32 && FromSize != 64 && FromSize != 128) || !ToTy)
1495 return UnableToLegalize;
1496 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SITOFP;
1498 MI, ToTy, Type::getIntNTy(Ctx, FromSize), LocObserver, IsSigned);
1499 if (Status != Legalized)
1500 return Status;
1501 break;
1502 }
1503 case TargetOpcode::G_ATOMICRMW_XCHG:
1504 case TargetOpcode::G_ATOMICRMW_ADD:
1505 case TargetOpcode::G_ATOMICRMW_SUB:
1506 case TargetOpcode::G_ATOMICRMW_AND:
1507 case TargetOpcode::G_ATOMICRMW_OR:
1508 case TargetOpcode::G_ATOMICRMW_XOR:
1509 case TargetOpcode::G_ATOMIC_CMPXCHG:
1510 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
1512 if (Status != Legalized)
1513 return Status;
1514 break;
1515 }
1516 case TargetOpcode::G_BZERO:
1517 case TargetOpcode::G_MEMCPY:
1518 case TargetOpcode::G_MEMMOVE:
1519 case TargetOpcode::G_MEMSET: {
1520 LegalizeResult Result =
1521 createMemLibcall(*MIRBuilder.getMRI(), MI, LocObserver);
1522 if (Result != Legalized)
1523 return Result;
1524 MI.eraseFromParent();
1525 return Result;
1526 }
1527 case TargetOpcode::G_GET_FPENV:
1528 case TargetOpcode::G_GET_FPMODE: {
1529 LegalizeResult Result = createGetStateLibcall(MI, LocObserver);
1530 if (Result != Legalized)
1531 return Result;
1532 break;
1533 }
1534 case TargetOpcode::G_SET_FPENV:
1535 case TargetOpcode::G_SET_FPMODE: {
1536 LegalizeResult Result = createSetStateLibcall(MI, LocObserver);
1537 if (Result != Legalized)
1538 return Result;
1539 break;
1540 }
1541 case TargetOpcode::G_RESET_FPENV:
1542 case TargetOpcode::G_RESET_FPMODE: {
1543 LegalizeResult Result = createResetStateLibcall(MI, LocObserver);
1544 if (Result != Legalized)
1545 return Result;
1546 break;
1547 }
1548 }
1549
1550 MI.eraseFromParent();
1551 return Legalized;
1552}
1553
1555 unsigned TypeIdx,
1556 LLT NarrowTy) {
1557 uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
1558 uint64_t NarrowSize = NarrowTy.getSizeInBits();
1559
1560 switch (MI.getOpcode()) {
1561 default:
1562 return UnableToLegalize;
1563 case TargetOpcode::G_IMPLICIT_DEF: {
1564 Register DstReg = MI.getOperand(0).getReg();
1565 LLT DstTy = MRI.getType(DstReg);
1566
1567 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1568 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1569 // FIXME: Although this would also be legal for the general case, it causes
1570 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1571 // combines not being hit). This seems to be a problem related to the
1572 // artifact combiner.
1573 if (SizeOp0 % NarrowSize != 0) {
1574 LLT ImplicitTy = DstTy.changeElementType(NarrowTy);
1575 Register ImplicitReg = MIRBuilder.buildUndef(ImplicitTy).getReg(0);
1576 MIRBuilder.buildAnyExt(DstReg, ImplicitReg);
1577
1578 MI.eraseFromParent();
1579 return Legalized;
1580 }
1581
1582 int NumParts = SizeOp0 / NarrowSize;
1583
1585 for (int i = 0; i < NumParts; ++i)
1586 DstRegs.push_back(MIRBuilder.buildUndef(NarrowTy).getReg(0));
1587
1588 if (DstTy.isVector())
1589 MIRBuilder.buildBuildVector(DstReg, DstRegs);
1590 else
1591 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
1592 MI.eraseFromParent();
1593 return Legalized;
1594 }
1595 case TargetOpcode::G_CONSTANT: {
1596 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1597 const APInt &Val = MI.getOperand(1).getCImm()->getValue();
1598 unsigned TotalSize = Ty.getSizeInBits();
1599 unsigned NarrowSize = NarrowTy.getSizeInBits();
1600 int NumParts = TotalSize / NarrowSize;
1601
1602 SmallVector<Register, 4> PartRegs;
1603 for (int I = 0; I != NumParts; ++I) {
1604 unsigned Offset = I * NarrowSize;
1605 auto K = MIRBuilder.buildConstant(NarrowTy,
1606 Val.lshr(Offset).trunc(NarrowSize));
1607 PartRegs.push_back(K.getReg(0));
1608 }
1609
1610 LLT LeftoverTy;
1611 unsigned LeftoverBits = TotalSize - NumParts * NarrowSize;
1612 SmallVector<Register, 1> LeftoverRegs;
1613 if (LeftoverBits != 0) {
1614 LeftoverTy = LLT::scalar(LeftoverBits);
1615 auto K = MIRBuilder.buildConstant(
1616 LeftoverTy,
1617 Val.lshr(NumParts * NarrowSize).trunc(LeftoverBits));
1618 LeftoverRegs.push_back(K.getReg(0));
1619 }
1620
1621 insertParts(MI.getOperand(0).getReg(),
1622 Ty, NarrowTy, PartRegs, LeftoverTy, LeftoverRegs);
1623
1624 MI.eraseFromParent();
1625 return Legalized;
1626 }
1627 case TargetOpcode::G_SEXT:
1628 case TargetOpcode::G_ZEXT:
1629 case TargetOpcode::G_ANYEXT:
1630 return narrowScalarExt(MI, TypeIdx, NarrowTy);
1631 case TargetOpcode::G_TRUNC: {
1632 if (TypeIdx != 1)
1633 return UnableToLegalize;
1634
1635 uint64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
1636 if (NarrowTy.getSizeInBits() * 2 != SizeOp1) {
1637 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy << "\n");
1638 return UnableToLegalize;
1639 }
1640
1641 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
1642 MIRBuilder.buildCopy(MI.getOperand(0), Unmerge.getReg(0));
1643 MI.eraseFromParent();
1644 return Legalized;
1645 }
1646 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
1647 case TargetOpcode::G_FREEZE: {
1648 if (TypeIdx != 0)
1649 return UnableToLegalize;
1650
1651 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
1652 // Should widen scalar first
1653 if (Ty.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
1654 return UnableToLegalize;
1655
1656 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1).getReg());
1658 for (unsigned i = 0; i < Unmerge->getNumDefs(); ++i) {
1659 Parts.push_back(
1660 MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy}, {Unmerge.getReg(i)})
1661 .getReg(0));
1662 }
1663
1664 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), Parts);
1665 MI.eraseFromParent();
1666 return Legalized;
1667 }
1668 case TargetOpcode::G_ADD:
1669 case TargetOpcode::G_SUB:
1670 case TargetOpcode::G_SADDO:
1671 case TargetOpcode::G_SSUBO:
1672 case TargetOpcode::G_SADDE:
1673 case TargetOpcode::G_SSUBE:
1674 case TargetOpcode::G_UADDO:
1675 case TargetOpcode::G_USUBO:
1676 case TargetOpcode::G_UADDE:
1677 case TargetOpcode::G_USUBE:
1678 return narrowScalarAddSub(MI, TypeIdx, NarrowTy);
1679 case TargetOpcode::G_MUL:
1680 case TargetOpcode::G_UMULH:
1681 return narrowScalarMul(MI, NarrowTy);
1682 case TargetOpcode::G_EXTRACT:
1683 return narrowScalarExtract(MI, TypeIdx, NarrowTy);
1684 case TargetOpcode::G_INSERT:
1685 return narrowScalarInsert(MI, TypeIdx, NarrowTy);
1686 case TargetOpcode::G_LOAD: {
1687 auto &LoadMI = cast<GLoad>(MI);
1688 Register DstReg = LoadMI.getDstReg();
1689 LLT DstTy = MRI.getType(DstReg);
1690 if (DstTy.isVector())
1691 return UnableToLegalize;
1692
1693 if (8 * LoadMI.getMemSize().getValue() != DstTy.getSizeInBits()) {
1694 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1695 MIRBuilder.buildLoad(TmpReg, LoadMI.getPointerReg(), LoadMI.getMMO());
1696 MIRBuilder.buildAnyExt(DstReg, TmpReg);
1697 LoadMI.eraseFromParent();
1698 return Legalized;
1699 }
1700
1701 return reduceLoadStoreWidth(LoadMI, TypeIdx, NarrowTy);
1702 }
1703 case TargetOpcode::G_ZEXTLOAD:
1704 case TargetOpcode::G_SEXTLOAD:
1705 case TargetOpcode::G_FPEXTLOAD: {
1706 auto &LoadMI = cast<GExtLoad>(MI);
1707 Register DstReg = LoadMI.getDstReg();
1708 Register PtrReg = LoadMI.getPointerReg();
1709
1710 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1711 auto &MMO = LoadMI.getMMO();
1712 unsigned MemSize = MMO.getSizeInBits().getValue();
1713
1714 if (MemSize == NarrowSize) {
1715 MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
1716 } else if (MemSize < NarrowSize) {
1717 MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), TmpReg, PtrReg, MMO);
1718 } else if (MemSize > NarrowSize) {
1719 // FIXME: Need to split the load.
1720 return UnableToLegalize;
1721 }
1722
1723 if (isa<GZExtLoad>(LoadMI))
1724 MIRBuilder.buildZExt(DstReg, TmpReg);
1725 else if (isa<GSExtLoad>(LoadMI))
1726 MIRBuilder.buildSExt(DstReg, TmpReg);
1727 else
1728 MIRBuilder.buildFPExt(DstReg, TmpReg);
1729
1730 LoadMI.eraseFromParent();
1731 return Legalized;
1732 }
1733 case TargetOpcode::G_STORE: {
1734 auto &StoreMI = cast<GStore>(MI);
1735
1736 Register SrcReg = StoreMI.getValueReg();
1737 LLT SrcTy = MRI.getType(SrcReg);
1738 if (SrcTy.isVector())
1739 return UnableToLegalize;
1740
1741 int NumParts = SizeOp0 / NarrowSize;
1742 unsigned HandledSize = NumParts * NarrowTy.getSizeInBits();
1743 unsigned LeftoverBits = SrcTy.getSizeInBits() - HandledSize;
1744 if (SrcTy.isVector() && LeftoverBits != 0)
1745 return UnableToLegalize;
1746
1747 if (8 * StoreMI.getMemSize().getValue() != SrcTy.getSizeInBits()) {
1748 Register TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
1749 MIRBuilder.buildTrunc(TmpReg, SrcReg);
1750 MIRBuilder.buildStore(TmpReg, StoreMI.getPointerReg(), StoreMI.getMMO());
1751 StoreMI.eraseFromParent();
1752 return Legalized;
1753 }
1754
1755 return reduceLoadStoreWidth(StoreMI, 0, NarrowTy);
1756 }
1757 case TargetOpcode::G_FPTRUNCSTORE: {
1758 auto &StoreMI = cast<GFPTruncStore>(MI);
1759 Register SrcReg = StoreMI.getValueReg();
1760 Register PtrReg = StoreMI.getPointerReg();
1761
1762 auto &MMO = StoreMI.getMMO();
1763 unsigned MemSize = MMO.getSizeInBits().getValue();
1764 if (MemSize > NarrowSize) {
1765 return UnableToLegalize;
1766 }
1767
1768 auto TmpReg = MIRBuilder.buildFPTrunc(NarrowTy, SrcReg);
1769 if (MemSize == NarrowSize) {
1770 MIRBuilder.buildStore(TmpReg, PtrReg, MMO);
1771 } else if (MemSize < NarrowSize) {
1772 MIRBuilder.buildStoreInstr(TargetOpcode::G_FPTRUNCSTORE, TmpReg, PtrReg,
1773 MMO);
1774 }
1775
1776 StoreMI.eraseFromParent();
1777 return Legalized;
1778 }
1779 case TargetOpcode::G_SELECT:
1780 return narrowScalarSelect(MI, TypeIdx, NarrowTy);
1781 case TargetOpcode::G_AND:
1782 case TargetOpcode::G_OR:
1783 case TargetOpcode::G_XOR: {
1784 // Legalize bitwise operation:
1785 // A = BinOp<Ty> B, C
1786 // into:
1787 // B1, ..., BN = G_UNMERGE_VALUES B
1788 // C1, ..., CN = G_UNMERGE_VALUES C
1789 // A1 = BinOp<Ty/N> B1, C2
1790 // ...
1791 // AN = BinOp<Ty/N> BN, CN
1792 // A = G_MERGE_VALUES A1, ..., AN
1793 return narrowScalarBasic(MI, TypeIdx, NarrowTy);
1794 }
1795 case TargetOpcode::G_SHL:
1796 case TargetOpcode::G_LSHR:
1797 case TargetOpcode::G_ASHR:
1798 return narrowScalarShift(MI, TypeIdx, NarrowTy);
1799 case TargetOpcode::G_CTLZ:
1800 case TargetOpcode::G_CTLZ_ZERO_POISON:
1801 case TargetOpcode::G_CTTZ:
1802 case TargetOpcode::G_CTTZ_ZERO_POISON:
1803 case TargetOpcode::G_CTLS:
1804 case TargetOpcode::G_CTPOP:
1805 if (TypeIdx == 1)
1806 switch (MI.getOpcode()) {
1807 case TargetOpcode::G_CTLZ:
1808 case TargetOpcode::G_CTLZ_ZERO_POISON:
1809 return narrowScalarCTLZ(MI, TypeIdx, NarrowTy);
1810 case TargetOpcode::G_CTTZ:
1811 case TargetOpcode::G_CTTZ_ZERO_POISON:
1812 return narrowScalarCTTZ(MI, TypeIdx, NarrowTy);
1813 case TargetOpcode::G_CTPOP:
1814 return narrowScalarCTPOP(MI, TypeIdx, NarrowTy);
1815 case TargetOpcode::G_CTLS:
1816 return narrowScalarCTLS(MI, TypeIdx, NarrowTy);
1817 default:
1818 return UnableToLegalize;
1819 }
1820
1821 Observer.changingInstr(MI);
1822 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1823 Observer.changedInstr(MI);
1824 return Legalized;
1825 case TargetOpcode::G_INTTOPTR:
1826 if (TypeIdx != 1)
1827 return UnableToLegalize;
1828
1829 Observer.changingInstr(MI);
1830 narrowScalarSrc(MI, NarrowTy, 1);
1831 Observer.changedInstr(MI);
1832 return Legalized;
1833 case TargetOpcode::G_PTRTOINT:
1834 if (TypeIdx != 0)
1835 return UnableToLegalize;
1836
1837 Observer.changingInstr(MI);
1838 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
1839 Observer.changedInstr(MI);
1840 return Legalized;
1841 case TargetOpcode::G_PHI: {
1842 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1843 // NarrowSize.
1844 if (SizeOp0 % NarrowSize != 0)
1845 return UnableToLegalize;
1846
1847 unsigned NumParts = SizeOp0 / NarrowSize;
1848 SmallVector<Register, 2> DstRegs(NumParts);
1849 SmallVector<SmallVector<Register, 2>, 2> SrcRegs(MI.getNumOperands() / 2);
1850 Observer.changingInstr(MI);
1851 for (unsigned i = 1; i < MI.getNumOperands(); i += 2) {
1852 MachineBasicBlock &OpMBB = *MI.getOperand(i + 1).getMBB();
1853 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
1854 extractParts(MI.getOperand(i).getReg(), NarrowTy, NumParts,
1855 SrcRegs[i / 2], MIRBuilder, MRI);
1856 }
1857 MachineBasicBlock &MBB = *MI.getParent();
1858 MIRBuilder.setInsertPt(MBB, MI);
1859 for (unsigned i = 0; i < NumParts; ++i) {
1860 DstRegs[i] = MRI.createGenericVirtualRegister(NarrowTy);
1862 MIRBuilder.buildInstr(TargetOpcode::G_PHI).addDef(DstRegs[i]);
1863 for (unsigned j = 1; j < MI.getNumOperands(); j += 2)
1864 MIB.addUse(SrcRegs[j / 2][i]).add(MI.getOperand(j + 1));
1865 }
1866 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
1867 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
1868 Observer.changedInstr(MI);
1869 MI.eraseFromParent();
1870 return Legalized;
1871 }
1872 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
1873 case TargetOpcode::G_INSERT_VECTOR_ELT: {
1874 if (TypeIdx != 2)
1875 return UnableToLegalize;
1876
1877 int OpIdx = MI.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT ? 2 : 3;
1878 Observer.changingInstr(MI);
1879 narrowScalarSrc(MI, NarrowTy, OpIdx);
1880 Observer.changedInstr(MI);
1881 return Legalized;
1882 }
1883 case TargetOpcode::G_ICMP: {
1884 Register LHS = MI.getOperand(2).getReg();
1885 LLT SrcTy = MRI.getType(LHS);
1886 CmpInst::Predicate Pred =
1887 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
1888
1889 LLT LeftoverTy; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1890 SmallVector<Register, 4> LHSPartRegs, LHSLeftoverRegs;
1891 if (!extractParts(LHS, SrcTy, NarrowTy, LeftoverTy, LHSPartRegs,
1892 LHSLeftoverRegs, MIRBuilder, MRI))
1893 return UnableToLegalize;
1894
1895 LLT Unused; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1896 SmallVector<Register, 4> RHSPartRegs, RHSLeftoverRegs;
1897 if (!extractParts(MI.getOperand(3).getReg(), SrcTy, NarrowTy, Unused,
1898 RHSPartRegs, RHSLeftoverRegs, MIRBuilder, MRI))
1899 return UnableToLegalize;
1900
1901 // We now have the LHS and RHS of the compare split into narrow-type
1902 // registers, plus potentially some leftover type.
1903 Register Dst = MI.getOperand(0).getReg();
1904 LLT ResTy = MRI.getType(Dst);
1905 if (ICmpInst::isEquality(Pred)) {
1906 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1907 // them together. For each equal part, the result should be all 0s. For
1908 // each non-equal part, we'll get at least one 1.
1909 auto Zero = MIRBuilder.buildConstant(NarrowTy, 0);
1911 for (auto LHSAndRHS : zip(LHSPartRegs, RHSPartRegs)) {
1912 auto LHS = std::get<0>(LHSAndRHS);
1913 auto RHS = std::get<1>(LHSAndRHS);
1914 auto Xor = MIRBuilder.buildXor(NarrowTy, LHS, RHS).getReg(0);
1915 Xors.push_back(Xor);
1916 }
1917
1918 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1919 // to the desired narrow type so that we can OR them together later.
1920 SmallVector<Register, 4> WidenedXors;
1921 for (auto LHSAndRHS : zip(LHSLeftoverRegs, RHSLeftoverRegs)) {
1922 auto LHS = std::get<0>(LHSAndRHS);
1923 auto RHS = std::get<1>(LHSAndRHS);
1924 auto Xor = MIRBuilder.buildXor(LeftoverTy, LHS, RHS).getReg(0);
1925 LLT GCDTy = extractGCDType(WidenedXors, NarrowTy, LeftoverTy, Xor);
1926 buildLCMMergePieces(LeftoverTy, NarrowTy, GCDTy, WidenedXors,
1927 /* PadStrategy = */ TargetOpcode::G_ZEXT);
1928 llvm::append_range(Xors, WidenedXors);
1929 }
1930
1931 // Now, for each part we broke up, we know if they are equal/not equal
1932 // based off the G_XOR. We can OR these all together and compare against
1933 // 0 to get the result.
1934 assert(Xors.size() >= 2 && "Should have gotten at least two Xors?");
1935 auto Or = MIRBuilder.buildOr(NarrowTy, Xors[0], Xors[1]);
1936 for (unsigned I = 2, E = Xors.size(); I < E; ++I)
1937 Or = MIRBuilder.buildOr(NarrowTy, Or, Xors[I]);
1938 MIRBuilder.buildICmp(Pred, Dst, Or, Zero);
1939 } else {
1940 Register CmpIn;
1941 for (unsigned I = 0, E = LHSPartRegs.size(); I != E; ++I) {
1942 Register CmpOut;
1943 CmpInst::Predicate PartPred;
1944
1945 if (I == E - 1 && LHSLeftoverRegs.empty()) {
1946 PartPred = Pred;
1947 CmpOut = Dst;
1948 } else {
1949 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1950 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1951 }
1952
1953 if (!CmpIn) {
1954 MIRBuilder.buildICmp(PartPred, CmpOut, LHSPartRegs[I],
1955 RHSPartRegs[I]);
1956 } else {
1957 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSPartRegs[I],
1958 RHSPartRegs[I]);
1959 auto CmpEq = MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1960 LHSPartRegs[I], RHSPartRegs[I]);
1961 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1962 }
1963
1964 CmpIn = CmpOut;
1965 }
1966
1967 for (unsigned I = 0, E = LHSLeftoverRegs.size(); I != E; ++I) {
1968 Register CmpOut;
1969 CmpInst::Predicate PartPred;
1970
1971 if (I == E - 1) {
1972 PartPred = Pred;
1973 CmpOut = Dst;
1974 } else {
1975 PartPred = ICmpInst::getUnsignedPredicate(Pred);
1976 CmpOut = MRI.createGenericVirtualRegister(ResTy);
1977 }
1978
1979 if (!CmpIn) {
1980 MIRBuilder.buildICmp(PartPred, CmpOut, LHSLeftoverRegs[I],
1981 RHSLeftoverRegs[I]);
1982 } else {
1983 auto Cmp = MIRBuilder.buildICmp(PartPred, ResTy, LHSLeftoverRegs[I],
1984 RHSLeftoverRegs[I]);
1985 auto CmpEq =
1986 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, ResTy,
1987 LHSLeftoverRegs[I], RHSLeftoverRegs[I]);
1988 MIRBuilder.buildSelect(CmpOut, CmpEq, CmpIn, Cmp);
1989 }
1990
1991 CmpIn = CmpOut;
1992 }
1993 }
1994 MI.eraseFromParent();
1995 return Legalized;
1996 }
1997 case TargetOpcode::G_FCMP:
1998 if (TypeIdx != 0)
1999 return UnableToLegalize;
2000
2001 Observer.changingInstr(MI);
2002 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT);
2003 Observer.changedInstr(MI);
2004 return Legalized;
2005
2006 case TargetOpcode::G_SEXT_INREG: {
2007 if (TypeIdx != 0)
2008 return UnableToLegalize;
2009
2010 int64_t SizeInBits = MI.getOperand(2).getImm();
2011
2012 // So long as the new type has more bits than the bits we're extending we
2013 // don't need to break it apart.
2014 if (NarrowTy.getScalarSizeInBits() > SizeInBits) {
2015 Observer.changingInstr(MI);
2016 // We don't lose any non-extension bits by truncating the src and
2017 // sign-extending the dst.
2018 MachineOperand &MO1 = MI.getOperand(1);
2019 auto TruncMIB = MIRBuilder.buildTrunc(NarrowTy, MO1);
2020 MO1.setReg(TruncMIB.getReg(0));
2021
2022 MachineOperand &MO2 = MI.getOperand(0);
2023 Register DstExt = MRI.createGenericVirtualRegister(NarrowTy);
2024 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2025 MIRBuilder.buildSExt(MO2, DstExt);
2026 MO2.setReg(DstExt);
2027 Observer.changedInstr(MI);
2028 return Legalized;
2029 }
2030
2031 // Break it apart. Components below the extension point are unmodified. The
2032 // component containing the extension point becomes a narrower SEXT_INREG.
2033 // Components above it are ashr'd from the component containing the
2034 // extension point.
2035 if (SizeOp0 % NarrowSize != 0)
2036 return UnableToLegalize;
2037 int NumParts = SizeOp0 / NarrowSize;
2038
2039 // List the registers where the destination will be scattered.
2041 // List the registers where the source will be split.
2043
2044 // Create all the temporary registers.
2045 for (int i = 0; i < NumParts; ++i) {
2046 Register SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
2047
2048 SrcRegs.push_back(SrcReg);
2049 }
2050
2051 // Explode the big arguments into smaller chunks.
2052 MIRBuilder.buildUnmerge(SrcRegs, MI.getOperand(1));
2053
2054 Register AshrCstReg =
2055 MIRBuilder.buildConstant(NarrowTy, NarrowTy.getScalarSizeInBits() - 1)
2056 .getReg(0);
2057 Register FullExtensionReg;
2058 Register PartialExtensionReg;
2059
2060 // Do the operation on each small part.
2061 for (int i = 0; i < NumParts; ++i) {
2062 if ((i + 1) * NarrowTy.getScalarSizeInBits() <= SizeInBits) {
2063 DstRegs.push_back(SrcRegs[i]);
2064 PartialExtensionReg = DstRegs.back();
2065 } else if (i * NarrowTy.getScalarSizeInBits() >= SizeInBits) {
2066 assert(PartialExtensionReg &&
2067 "Expected to visit partial extension before full");
2068 if (FullExtensionReg) {
2069 DstRegs.push_back(FullExtensionReg);
2070 continue;
2071 }
2072 DstRegs.push_back(
2073 MIRBuilder.buildAShr(NarrowTy, PartialExtensionReg, AshrCstReg)
2074 .getReg(0));
2075 FullExtensionReg = DstRegs.back();
2076 } else {
2077 DstRegs.push_back(
2079 .buildInstr(
2080 TargetOpcode::G_SEXT_INREG, {NarrowTy},
2081 {SrcRegs[i], SizeInBits % NarrowTy.getScalarSizeInBits()})
2082 .getReg(0));
2083 PartialExtensionReg = DstRegs.back();
2084 }
2085 }
2086
2087 // Gather the destination registers into the final destination.
2088 Register DstReg = MI.getOperand(0).getReg();
2089 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
2090 MI.eraseFromParent();
2091 return Legalized;
2092 }
2093 case TargetOpcode::G_BSWAP:
2094 case TargetOpcode::G_BITREVERSE: {
2095 if (SizeOp0 % NarrowSize != 0)
2096 return UnableToLegalize;
2097
2098 Observer.changingInstr(MI);
2099 SmallVector<Register, 2> SrcRegs, DstRegs;
2100 unsigned NumParts = SizeOp0 / NarrowSize;
2101 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
2102 MIRBuilder, MRI);
2103
2104 for (unsigned i = 0; i < NumParts; ++i) {
2105 auto DstPart = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
2106 {SrcRegs[NumParts - 1 - i]});
2107 DstRegs.push_back(DstPart.getReg(0));
2108 }
2109
2110 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), DstRegs);
2111
2112 Observer.changedInstr(MI);
2113 MI.eraseFromParent();
2114 return Legalized;
2115 }
2116 case TargetOpcode::G_PTR_ADD:
2117 case TargetOpcode::G_PTRMASK: {
2118 if (TypeIdx != 1)
2119 return UnableToLegalize;
2120 Observer.changingInstr(MI);
2121 narrowScalarSrc(MI, NarrowTy, 2);
2122 Observer.changedInstr(MI);
2123 return Legalized;
2124 }
2125 case TargetOpcode::G_FPTOUI:
2126 case TargetOpcode::G_FPTOSI:
2127 case TargetOpcode::G_FPTOUI_SAT:
2128 case TargetOpcode::G_FPTOSI_SAT:
2129 return narrowScalarFPTOI(MI, TypeIdx, NarrowTy);
2130 case TargetOpcode::G_FPEXT:
2131 if (TypeIdx != 0)
2132 return UnableToLegalize;
2133 Observer.changingInstr(MI);
2134 narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_FPEXT);
2135 Observer.changedInstr(MI);
2136 return Legalized;
2137 case TargetOpcode::G_FLDEXP:
2138 case TargetOpcode::G_STRICT_FLDEXP:
2139 return narrowScalarFLDEXP(MI, TypeIdx, NarrowTy);
2140 case TargetOpcode::G_VSCALE: {
2141 Register Dst = MI.getOperand(0).getReg();
2142 LLT Ty = MRI.getType(Dst);
2143
2144 // Assume VSCALE(1) fits into a legal integer
2145 const APInt One(NarrowTy.getSizeInBits(), 1);
2146 auto VScaleBase = MIRBuilder.buildVScale(NarrowTy, One);
2147 auto ZExt = MIRBuilder.buildZExt(Ty, VScaleBase);
2148 auto C = MIRBuilder.buildConstant(Ty, *MI.getOperand(1).getCImm());
2149 MIRBuilder.buildMul(Dst, ZExt, C);
2150
2151 MI.eraseFromParent();
2152 return Legalized;
2153 }
2154 }
2155}
2156
2158 LLT Ty = MRI.getType(Val);
2159 if (Ty.isScalar() && !Ty.isFloat())
2160 return Val;
2161
2162 const DataLayout &DL = MIRBuilder.getDataLayout();
2163 LLT NewTy = LLT::integer(Ty.getSizeInBits());
2164
2165 if (Ty.isFloat())
2166 return MIRBuilder.buildBitcast(NewTy, Val).getReg(0);
2167
2168 if (Ty.isPointer()) {
2169 if (DL.isNonIntegralAddressSpace(Ty.getAddressSpace()))
2170 return Register();
2171 return MIRBuilder.buildPtrToInt(NewTy, Val).getReg(0);
2172 }
2173
2174 Register NewVal = Val;
2175
2176 assert(Ty.isVector());
2177 if (Ty.isPointerVector())
2178 NewVal = MIRBuilder.buildPtrToInt(NewTy, NewVal).getReg(0);
2179 return MIRBuilder.buildBitcast(NewTy, NewVal).getReg(0);
2180}
2181
2183 unsigned OpIdx, unsigned ExtOpcode) {
2184 MachineOperand &MO = MI.getOperand(OpIdx);
2185 auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO});
2186 MO.setReg(ExtB.getReg(0));
2187}
2188
2190 unsigned OpIdx) {
2191 MachineOperand &MO = MI.getOperand(OpIdx);
2192 auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, {WideTy}, {MO},
2193 MI.getFlags());
2194 MO.setReg(ExtB.getReg(0));
2195}
2196
2198 unsigned OpIdx) {
2199 MachineOperand &MO = MI.getOperand(OpIdx);
2200 auto ExtB = MIRBuilder.buildTrunc(NarrowTy, MO);
2201 MO.setReg(ExtB.getReg(0));
2202}
2203
2205 unsigned OpIdx, unsigned TruncOpcode) {
2206 MachineOperand &MO = MI.getOperand(OpIdx);
2207 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2208 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2209 MIRBuilder.buildInstr(TruncOpcode, {MO}, {DstExt});
2210 MO.setReg(DstExt);
2211}
2212
2214 unsigned OpIdx) {
2215 MachineOperand &MO = MI.getOperand(OpIdx);
2216 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2217 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2218 MIRBuilder.buildInstr(TargetOpcode::G_FPTRUNC, {MO}, {DstExt}, MI.getFlags());
2219 MO.setReg(DstExt);
2220}
2221
2223 unsigned OpIdx, unsigned ExtOpcode) {
2224 MachineOperand &MO = MI.getOperand(OpIdx);
2225 Register DstTrunc = MRI.createGenericVirtualRegister(NarrowTy);
2226 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2227 MIRBuilder.buildInstr(ExtOpcode, {MO}, {DstTrunc});
2228 MO.setReg(DstTrunc);
2229}
2230
2232 unsigned OpIdx) {
2233 MachineOperand &MO = MI.getOperand(OpIdx);
2234 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2235 Register Dst = MO.getReg();
2236 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2237 MO.setReg(DstExt);
2238 MIRBuilder.buildDeleteTrailingVectorElements(Dst, DstExt);
2239}
2240
2242 unsigned OpIdx) {
2243 MachineOperand &MO = MI.getOperand(OpIdx);
2244 MO.setReg(MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO).getReg(0));
2245}
2246
2247void LegalizerHelper::bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2248 MachineOperand &Op = MI.getOperand(OpIdx);
2249 Op.setReg(MIRBuilder.buildBitcast(CastTy, Op).getReg(0));
2250}
2251
2252void LegalizerHelper::bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx) {
2253 MachineOperand &MO = MI.getOperand(OpIdx);
2254 Register CastDst = MRI.createGenericVirtualRegister(CastTy);
2255 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2256 MIRBuilder.buildBitcast(MO, CastDst);
2257 MO.setReg(CastDst);
2258}
2259
2261LegalizerHelper::widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx,
2262 LLT WideTy) {
2263 if (TypeIdx != 1)
2264 return UnableToLegalize;
2265
2266 auto [DstReg, DstTy, Src1Reg, Src1Ty] = MI.getFirst2RegLLTs();
2267 if (DstTy.isVector())
2268 return UnableToLegalize;
2269
2270 LLT SrcTy = MRI.getType(Src1Reg);
2271 const int DstSize = DstTy.getSizeInBits();
2272 const int SrcSize = SrcTy.getSizeInBits();
2273 const int WideSize = WideTy.getSizeInBits();
2274 const int NumMerge = (DstSize + WideSize - 1) / WideSize;
2275
2276 unsigned NumOps = MI.getNumOperands();
2277 unsigned NumSrc = MI.getNumOperands() - 1;
2278 unsigned PartSize = DstTy.getSizeInBits() / NumSrc;
2279
2280 if (WideSize >= DstSize) {
2281 // Directly pack the bits in the target type.
2282 Register ResultReg = MIRBuilder.buildZExt(WideTy, Src1Reg).getReg(0);
2283
2284 for (unsigned I = 2; I != NumOps; ++I) {
2285 const unsigned Offset = (I - 1) * PartSize;
2286
2287 Register SrcReg = MI.getOperand(I).getReg();
2288 assert(MRI.getType(SrcReg) == LLT::scalar(PartSize));
2289
2290 auto ZextInput = MIRBuilder.buildZExt(WideTy, SrcReg);
2291
2292 Register NextResult = I + 1 == NumOps && WideTy == DstTy ? DstReg :
2293 MRI.createGenericVirtualRegister(WideTy);
2294
2295 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, Offset);
2296 auto Shl = MIRBuilder.buildShl(WideTy, ZextInput, ShiftAmt);
2297 MIRBuilder.buildOr(NextResult, ResultReg, Shl);
2298 ResultReg = NextResult;
2299 }
2300
2301 if (WideSize > DstSize)
2302 MIRBuilder.buildTrunc(DstReg, ResultReg);
2303 else if (DstTy.isPointer())
2304 MIRBuilder.buildIntToPtr(DstReg, ResultReg);
2305 else if (DstTy != WideTy)
2306 MIRBuilder.buildBitcast(DstReg, ResultReg);
2307
2308 MI.eraseFromParent();
2309 return Legalized;
2310 }
2311
2312 // Unmerge the original values to the GCD type, and recombine to the next
2313 // multiple greater than the original type.
2314 //
2315 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2316 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2317 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2318 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2319 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2320 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2321 // %12:_(s12) = G_MERGE_VALUES %10, %11
2322 //
2323 // Padding with undef if necessary:
2324 //
2325 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2326 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2327 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2328 // %7:_(s2) = G_IMPLICIT_DEF
2329 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2330 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2331 // %10:_(s12) = G_MERGE_VALUES %8, %9
2332
2333 const int GCD = std::gcd(SrcSize, WideSize);
2334 LLT GCDTy = WideTy.changeElementSize(GCD);
2335
2336 SmallVector<Register, 8> NewMergeRegs;
2337 SmallVector<Register, 8> Unmerges;
2338 LLT WideDstTy = WideTy.changeElementSize(NumMerge * WideSize);
2339
2340 // Decompose the original operands if they don't evenly divide.
2341 for (const MachineOperand &MO : llvm::drop_begin(MI.operands())) {
2342 Register SrcReg = MO.getReg();
2343 if (GCD == SrcSize) {
2344 Unmerges.push_back(SrcReg);
2345 } else {
2346 auto Unmerge = MIRBuilder.buildUnmerge(GCDTy, SrcReg);
2347 for (int J = 0, JE = Unmerge->getNumOperands() - 1; J != JE; ++J)
2348 Unmerges.push_back(Unmerge.getReg(J));
2349 }
2350 }
2351
2352 // Pad with undef to the next size that is a multiple of the requested size.
2353 if (static_cast<int>(Unmerges.size()) != NumMerge * WideSize) {
2354 Register UndefReg = MIRBuilder.buildUndef(GCDTy).getReg(0);
2355 for (int I = Unmerges.size(); I != NumMerge * WideSize; ++I)
2356 Unmerges.push_back(UndefReg);
2357 }
2358
2359 const int PartsPerGCD = WideSize / GCD;
2360
2361 // Build merges of each piece.
2362 ArrayRef<Register> Slicer(Unmerges);
2363 for (int I = 0; I != NumMerge; ++I, Slicer = Slicer.drop_front(PartsPerGCD)) {
2364 auto Merge =
2365 MIRBuilder.buildMergeLikeInstr(WideTy, Slicer.take_front(PartsPerGCD));
2366 NewMergeRegs.push_back(Merge.getReg(0));
2367 }
2368
2369 // A truncate may be necessary if the requested type doesn't evenly divide the
2370 // original result type.
2371 if (DstTy.getSizeInBits() == WideDstTy.getSizeInBits()) {
2372 MIRBuilder.buildMergeLikeInstr(DstReg, NewMergeRegs);
2373 } else {
2374 auto FinalMerge = MIRBuilder.buildMergeLikeInstr(WideDstTy, NewMergeRegs);
2375 MIRBuilder.buildTrunc(DstReg, FinalMerge.getReg(0));
2376 }
2377
2378 MI.eraseFromParent();
2379 return Legalized;
2380}
2381
2383LegalizerHelper::widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx,
2384 LLT WideTy) {
2385 if (TypeIdx != 0)
2386 return UnableToLegalize;
2387
2388 int NumDst = MI.getNumOperands() - 1;
2389 Register SrcReg = MI.getOperand(NumDst).getReg();
2390 LLT SrcTy = MRI.getType(SrcReg);
2391 if (SrcTy.isVector())
2392 return UnableToLegalize;
2393
2394 Register Dst0Reg = MI.getOperand(0).getReg();
2395 LLT DstTy = MRI.getType(Dst0Reg);
2396 if (!DstTy.isScalar())
2397 return UnableToLegalize;
2398
2399 if (WideTy.getSizeInBits() >= SrcTy.getSizeInBits()) {
2400 if (SrcTy.isPointer()) {
2401 const DataLayout &DL = MIRBuilder.getDataLayout();
2402 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace())) {
2403 LLVM_DEBUG(
2404 dbgs() << "Not casting non-integral address space integer\n");
2405 return UnableToLegalize;
2406 }
2407
2408 SrcTy = LLT::scalar(SrcTy.getSizeInBits());
2409 SrcReg = MIRBuilder.buildPtrToInt(SrcTy, SrcReg).getReg(0);
2410 }
2411
2412 // Widen SrcTy to WideTy. This does not affect the result, but since the
2413 // user requested this size, it is probably better handled than SrcTy and
2414 // should reduce the total number of legalization artifacts.
2415 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2416 SrcTy = WideTy;
2417 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
2418 }
2419
2420 // Theres no unmerge type to target. Directly extract the bits from the
2421 // source type
2422 unsigned DstSize = DstTy.getSizeInBits();
2423
2424 if (SrcTy.isFloat()) {
2425 SrcReg = coerceToInteger(SrcReg);
2426 SrcTy = MRI.getType(SrcReg);
2427 }
2428
2429 MIRBuilder.buildTrunc(Dst0Reg, SrcReg);
2430 for (int I = 1; I != NumDst; ++I) {
2431 auto ShiftAmt = MIRBuilder.buildConstant(SrcTy, DstSize * I);
2432 auto Shr = MIRBuilder.buildLShr(SrcTy, SrcReg, ShiftAmt);
2433 MIRBuilder.buildTrunc(MI.getOperand(I), Shr);
2434 }
2435
2436 MI.eraseFromParent();
2437 return Legalized;
2438 }
2439
2440 // Extend the source to a wider type.
2441 LLT LCMTy = getLCMType(SrcTy, WideTy);
2442
2443 Register WideSrc = SrcReg;
2444 if (LCMTy.getSizeInBits() != SrcTy.getSizeInBits()) {
2445 // TODO: If this is an integral address space, cast to integer and anyext.
2446 if (SrcTy.isPointer()) {
2447 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2448 return UnableToLegalize;
2449 }
2450
2451 WideSrc = MIRBuilder.buildAnyExt(LCMTy, WideSrc).getReg(0);
2452 }
2453
2454 auto Unmerge = MIRBuilder.buildUnmerge(WideTy, WideSrc);
2455
2456 // Create a sequence of unmerges and merges to the original results. Since we
2457 // may have widened the source, we will need to pad the results with dead defs
2458 // to cover the source register.
2459 // e.g. widen s48 to s64:
2460 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2461 //
2462 // =>
2463 // %4:_(s192) = G_ANYEXT %0:_(s96)
2464 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2465 // ; unpack to GCD type, with extra dead defs
2466 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2467 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2468 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2469 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2470 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2471 const LLT GCDTy = getGCDType(WideTy, DstTy);
2472 const int NumUnmerge = Unmerge->getNumOperands() - 1;
2473 const int PartsPerRemerge = DstTy.getSizeInBits() / GCDTy.getSizeInBits();
2474
2475 // Directly unmerge to the destination without going through a GCD type
2476 // if possible
2477 if (PartsPerRemerge == 1) {
2478 const int PartsPerUnmerge = WideTy.getSizeInBits() / DstTy.getSizeInBits();
2479
2480 for (int I = 0; I != NumUnmerge; ++I) {
2481 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
2482
2483 for (int J = 0; J != PartsPerUnmerge; ++J) {
2484 int Idx = I * PartsPerUnmerge + J;
2485 if (Idx < NumDst)
2486 MIB.addDef(MI.getOperand(Idx).getReg());
2487 else {
2488 // Create dead def for excess components.
2489 MIB.addDef(MRI.createGenericVirtualRegister(DstTy));
2490 }
2491 }
2492
2493 MIB.addUse(Unmerge.getReg(I));
2494 }
2495 } else {
2496 SmallVector<Register, 16> Parts;
2497 for (int J = 0; J != NumUnmerge; ++J)
2498 extractGCDType(Parts, GCDTy, Unmerge.getReg(J));
2499
2500 SmallVector<Register, 8> RemergeParts;
2501 for (int I = 0; I != NumDst; ++I) {
2502 for (int J = 0; J < PartsPerRemerge; ++J) {
2503 const int Idx = I * PartsPerRemerge + J;
2504 RemergeParts.emplace_back(Parts[Idx]);
2505 }
2506
2507 MIRBuilder.buildMergeLikeInstr(MI.getOperand(I).getReg(), RemergeParts);
2508 RemergeParts.clear();
2509 }
2510 }
2511
2512 MI.eraseFromParent();
2513 return Legalized;
2514}
2515
2517LegalizerHelper::widenScalarExtract(MachineInstr &MI, unsigned TypeIdx,
2518 LLT WideTy) {
2519 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
2520 unsigned Offset = MI.getOperand(2).getImm();
2521
2522 if (TypeIdx == 0) {
2523 if (SrcTy.isVector() || DstTy.isVector())
2524 return UnableToLegalize;
2525
2526 SrcOp Src(SrcReg);
2527 if (SrcTy.isPointer()) {
2528 // Extracts from pointers can be handled only if they are really just
2529 // simple integers.
2530 const DataLayout &DL = MIRBuilder.getDataLayout();
2531 if (DL.isNonIntegralAddressSpace(SrcTy.getAddressSpace()))
2532 return UnableToLegalize;
2533
2534 LLT SrcAsIntTy = LLT::scalar(SrcTy.getSizeInBits());
2535 Src = MIRBuilder.buildPtrToInt(SrcAsIntTy, Src);
2536 SrcTy = SrcAsIntTy;
2537 }
2538
2539 if (DstTy.isPointer())
2540 return UnableToLegalize;
2541
2542 if (Offset == 0) {
2543 // Avoid a shift in the degenerate case.
2544 MIRBuilder.buildTrunc(DstReg,
2545 MIRBuilder.buildAnyExtOrTrunc(WideTy, Src));
2546 MI.eraseFromParent();
2547 return Legalized;
2548 }
2549
2550 // Do a shift in the source type.
2551 LLT ShiftTy = SrcTy;
2552 if (WideTy.getSizeInBits() > SrcTy.getSizeInBits()) {
2553 Src = MIRBuilder.buildAnyExt(WideTy, Src);
2554 ShiftTy = WideTy;
2555 }
2556
2557 auto LShr = MIRBuilder.buildLShr(
2558 ShiftTy, Src, MIRBuilder.buildConstant(ShiftTy, Offset));
2559 MIRBuilder.buildTrunc(DstReg, LShr);
2560 MI.eraseFromParent();
2561 return Legalized;
2562 }
2563
2564 if (SrcTy.isScalar()) {
2565 Observer.changingInstr(MI);
2566 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2567 Observer.changedInstr(MI);
2568 return Legalized;
2569 }
2570
2571 if (!SrcTy.isVector())
2572 return UnableToLegalize;
2573
2574 if (DstTy != SrcTy.getElementType())
2575 return UnableToLegalize;
2576
2577 if (Offset % SrcTy.getScalarSizeInBits() != 0)
2578 return UnableToLegalize;
2579
2580 Observer.changingInstr(MI);
2581 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2582
2583 MI.getOperand(2).setImm((WideTy.getSizeInBits() / SrcTy.getSizeInBits()) *
2584 Offset);
2585 widenScalarDst(MI, WideTy.getScalarType(), 0);
2586 Observer.changedInstr(MI);
2587 return Legalized;
2588}
2589
2591LegalizerHelper::widenScalarInsert(MachineInstr &MI, unsigned TypeIdx,
2592 LLT WideTy) {
2593 if (TypeIdx != 0 || WideTy.isVector())
2594 return UnableToLegalize;
2595 Observer.changingInstr(MI);
2596 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2597 widenScalarDst(MI, WideTy);
2598 Observer.changedInstr(MI);
2599 return Legalized;
2600}
2601
2603LegalizerHelper::widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
2604 LLT WideTy) {
2605 unsigned Opcode;
2606 unsigned ExtOpcode;
2607 std::optional<Register> CarryIn;
2608 switch (MI.getOpcode()) {
2609 default:
2610 llvm_unreachable("Unexpected opcode!");
2611 case TargetOpcode::G_SADDO:
2612 Opcode = TargetOpcode::G_ADD;
2613 ExtOpcode = TargetOpcode::G_SEXT;
2614 break;
2615 case TargetOpcode::G_SSUBO:
2616 Opcode = TargetOpcode::G_SUB;
2617 ExtOpcode = TargetOpcode::G_SEXT;
2618 break;
2619 case TargetOpcode::G_UADDO:
2620 Opcode = TargetOpcode::G_ADD;
2621 ExtOpcode = TargetOpcode::G_ZEXT;
2622 break;
2623 case TargetOpcode::G_USUBO:
2624 Opcode = TargetOpcode::G_SUB;
2625 ExtOpcode = TargetOpcode::G_ZEXT;
2626 break;
2627 case TargetOpcode::G_SADDE:
2628 Opcode = TargetOpcode::G_UADDE;
2629 ExtOpcode = TargetOpcode::G_SEXT;
2630 CarryIn = MI.getOperand(4).getReg();
2631 break;
2632 case TargetOpcode::G_SSUBE:
2633 Opcode = TargetOpcode::G_USUBE;
2634 ExtOpcode = TargetOpcode::G_SEXT;
2635 CarryIn = MI.getOperand(4).getReg();
2636 break;
2637 case TargetOpcode::G_UADDE:
2638 Opcode = TargetOpcode::G_UADDE;
2639 ExtOpcode = TargetOpcode::G_ZEXT;
2640 CarryIn = MI.getOperand(4).getReg();
2641 break;
2642 case TargetOpcode::G_USUBE:
2643 Opcode = TargetOpcode::G_USUBE;
2644 ExtOpcode = TargetOpcode::G_ZEXT;
2645 CarryIn = MI.getOperand(4).getReg();
2646 break;
2647 }
2648
2649 if (TypeIdx == 1) {
2650 unsigned BoolExtOp = MIRBuilder.getBoolExtOp(WideTy.isVector(), false);
2651
2652 Observer.changingInstr(MI);
2653 if (CarryIn)
2654 widenScalarSrc(MI, WideTy, 4, BoolExtOp);
2655 widenScalarDst(MI, WideTy, 1);
2656
2657 Observer.changedInstr(MI);
2658 return Legalized;
2659 }
2660
2661 auto LHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(2)});
2662 auto RHSExt = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MI.getOperand(3)});
2663 // Do the arithmetic in the larger type.
2664 Register NewOp;
2665 if (CarryIn) {
2666 LLT CarryOutTy = MRI.getType(MI.getOperand(1).getReg());
2667 NewOp = MIRBuilder
2668 .buildInstr(Opcode, {WideTy, CarryOutTy},
2669 {LHSExt, RHSExt, *CarryIn})
2670 .getReg(0);
2671 } else {
2672 NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSExt, RHSExt}).getReg(0);
2673 }
2674 LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
2675 auto TruncOp = MIRBuilder.buildTrunc(OrigTy, NewOp);
2676 auto ExtOp = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {TruncOp});
2677 // There is no overflow if the ExtOp is the same as NewOp.
2678 MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1), NewOp, ExtOp);
2679 // Now trunc the NewOp to the original result.
2680 MIRBuilder.buildTrunc(MI.getOperand(0), NewOp);
2681 MI.eraseFromParent();
2682 return Legalized;
2683}
2684
2686LegalizerHelper::widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
2687 LLT WideTy) {
2688 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SADDSAT ||
2689 MI.getOpcode() == TargetOpcode::G_SSUBSAT ||
2690 MI.getOpcode() == TargetOpcode::G_SSHLSAT;
2691 bool IsShift = MI.getOpcode() == TargetOpcode::G_SSHLSAT ||
2692 MI.getOpcode() == TargetOpcode::G_USHLSAT;
2693 // We can convert this to:
2694 // 1. Any extend iN to iM
2695 // 2. SHL by M-N
2696 // 3. [US][ADD|SUB|SHL]SAT
2697 // 4. L/ASHR by M-N
2698 //
2699 // It may be more efficient to lower this to a min and a max operation in
2700 // the higher precision arithmetic if the promoted operation isn't legal,
2701 // but this decision is up to the target's lowering request.
2702 Register DstReg = MI.getOperand(0).getReg();
2703
2704 unsigned NewBits = WideTy.getScalarSizeInBits();
2705 unsigned SHLAmount = NewBits - MRI.getType(DstReg).getScalarSizeInBits();
2706
2707 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2708 // must not left shift the RHS to preserve the shift amount.
2709 auto LHS = MIRBuilder.buildAnyExt(WideTy, MI.getOperand(1));
2710 auto RHS = IsShift ? MIRBuilder.buildZExt(WideTy, MI.getOperand(2))
2711 : MIRBuilder.buildAnyExt(WideTy, MI.getOperand(2));
2712 auto ShiftK = MIRBuilder.buildConstant(WideTy, SHLAmount);
2713 auto ShiftL = MIRBuilder.buildShl(WideTy, LHS, ShiftK);
2714 auto ShiftR = IsShift ? RHS : MIRBuilder.buildShl(WideTy, RHS, ShiftK);
2715
2716 auto WideInst = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy},
2717 {ShiftL, ShiftR}, MI.getFlags());
2718
2719 // Use a shift that will preserve the number of sign bits when the trunc is
2720 // folded away.
2721 auto Result = IsSigned ? MIRBuilder.buildAShr(WideTy, WideInst, ShiftK)
2722 : MIRBuilder.buildLShr(WideTy, WideInst, ShiftK);
2723
2724 MIRBuilder.buildTrunc(DstReg, Result);
2725 MI.eraseFromParent();
2726 return Legalized;
2727}
2728
2730LegalizerHelper::widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
2731 LLT WideTy) {
2732 if (TypeIdx == 1) {
2733 Observer.changingInstr(MI);
2734 widenScalarDst(MI, WideTy, 1);
2735 Observer.changedInstr(MI);
2736 return Legalized;
2737 }
2738
2739 bool IsSigned = MI.getOpcode() == TargetOpcode::G_SMULO;
2740 auto [Result, OriginalOverflow, LHS, RHS] = MI.getFirst4Regs();
2741 LLT SrcTy = MRI.getType(LHS);
2742 LLT OverflowTy = MRI.getType(OriginalOverflow);
2743 unsigned SrcBitWidth = SrcTy.getScalarSizeInBits();
2744
2745 // To determine if the result overflowed in the larger type, we extend the
2746 // input to the larger type, do the multiply (checking if it overflows),
2747 // then also check the high bits of the result to see if overflow happened
2748 // there.
2749 unsigned ExtOp = IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
2750 auto LeftOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {LHS});
2751 auto RightOperand = MIRBuilder.buildInstr(ExtOp, {WideTy}, {RHS});
2752
2753 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2754 // so we don't need to check the overflow result of larger type Mulo.
2755 bool WideMulCanOverflow = WideTy.getScalarSizeInBits() < 2 * SrcBitWidth;
2756
2757 unsigned MulOpc =
2758 WideMulCanOverflow ? MI.getOpcode() : (unsigned)TargetOpcode::G_MUL;
2759
2760 MachineInstrBuilder Mulo;
2761 if (WideMulCanOverflow)
2762 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy, OverflowTy},
2763 {LeftOperand, RightOperand});
2764 else
2765 Mulo = MIRBuilder.buildInstr(MulOpc, {WideTy}, {LeftOperand, RightOperand});
2766
2767 auto Mul = Mulo->getOperand(0);
2768 MIRBuilder.buildTrunc(Result, Mul);
2769
2770 MachineInstrBuilder ExtResult;
2771 // Overflow occurred if it occurred in the larger type, or if the high part
2772 // of the result does not zero/sign-extend the low part. Check this second
2773 // possibility first.
2774 if (IsSigned) {
2775 // For signed, overflow occurred when the high part does not sign-extend
2776 // the low part.
2777 ExtResult = MIRBuilder.buildSExtInReg(WideTy, Mul, SrcBitWidth);
2778 } else {
2779 // Unsigned overflow occurred when the high part does not zero-extend the
2780 // low part.
2781 ExtResult = MIRBuilder.buildZExtInReg(WideTy, Mul, SrcBitWidth);
2782 }
2783
2784 if (WideMulCanOverflow) {
2785 auto Overflow =
2786 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OverflowTy, Mul, ExtResult);
2787 // Finally check if the multiplication in the larger type itself overflowed.
2788 MIRBuilder.buildOr(OriginalOverflow, Mulo->getOperand(1), Overflow);
2789 } else {
2790 MIRBuilder.buildICmp(CmpInst::ICMP_NE, OriginalOverflow, Mul, ExtResult);
2791 }
2792 MI.eraseFromParent();
2793 return Legalized;
2794}
2795
2798 unsigned Opcode = MI.getOpcode();
2799 switch (Opcode) {
2800 default:
2801 return UnableToLegalize;
2802 case TargetOpcode::G_ATOMICRMW_XCHG:
2803 case TargetOpcode::G_ATOMICRMW_ADD:
2804 case TargetOpcode::G_ATOMICRMW_SUB:
2805 case TargetOpcode::G_ATOMICRMW_AND:
2806 case TargetOpcode::G_ATOMICRMW_OR:
2807 case TargetOpcode::G_ATOMICRMW_XOR:
2808 case TargetOpcode::G_ATOMICRMW_MIN:
2809 case TargetOpcode::G_ATOMICRMW_MAX:
2810 case TargetOpcode::G_ATOMICRMW_UMIN:
2811 case TargetOpcode::G_ATOMICRMW_UMAX:
2812 assert(TypeIdx == 0 && "atomicrmw with second scalar type");
2813 Observer.changingInstr(MI);
2814 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2815 widenScalarDst(MI, WideTy, 0);
2816 Observer.changedInstr(MI);
2817 return Legalized;
2818 case TargetOpcode::G_ATOMIC_CMPXCHG:
2819 assert(TypeIdx == 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2820 Observer.changingInstr(MI);
2821 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
2822 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2823 widenScalarDst(MI, WideTy, 0);
2824 Observer.changedInstr(MI);
2825 return Legalized;
2826 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS:
2827 if (TypeIdx == 0) {
2828 Observer.changingInstr(MI);
2829 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
2830 widenScalarSrc(MI, WideTy, 4, TargetOpcode::G_ANYEXT);
2831 widenScalarDst(MI, WideTy, 0);
2832 Observer.changedInstr(MI);
2833 return Legalized;
2834 }
2835 assert(TypeIdx == 1 &&
2836 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2837 Observer.changingInstr(MI);
2838 widenScalarDst(MI, WideTy, 1);
2839 Observer.changedInstr(MI);
2840 return Legalized;
2841 case TargetOpcode::G_EXTRACT:
2842 return widenScalarExtract(MI, TypeIdx, WideTy);
2843 case TargetOpcode::G_INSERT:
2844 return widenScalarInsert(MI, TypeIdx, WideTy);
2845 case TargetOpcode::G_MERGE_VALUES:
2846 return widenScalarMergeValues(MI, TypeIdx, WideTy);
2847 case TargetOpcode::G_UNMERGE_VALUES:
2848 return widenScalarUnmergeValues(MI, TypeIdx, WideTy);
2849 case TargetOpcode::G_SADDO:
2850 case TargetOpcode::G_SSUBO:
2851 case TargetOpcode::G_UADDO:
2852 case TargetOpcode::G_USUBO:
2853 case TargetOpcode::G_SADDE:
2854 case TargetOpcode::G_SSUBE:
2855 case TargetOpcode::G_UADDE:
2856 case TargetOpcode::G_USUBE:
2857 return widenScalarAddSubOverflow(MI, TypeIdx, WideTy);
2858 case TargetOpcode::G_UMULO:
2859 case TargetOpcode::G_SMULO:
2860 return widenScalarMulo(MI, TypeIdx, WideTy);
2861 case TargetOpcode::G_SADDSAT:
2862 case TargetOpcode::G_SSUBSAT:
2863 case TargetOpcode::G_SSHLSAT:
2864 case TargetOpcode::G_UADDSAT:
2865 case TargetOpcode::G_USUBSAT:
2866 case TargetOpcode::G_USHLSAT:
2867 return widenScalarAddSubShlSat(MI, TypeIdx, WideTy);
2868 case TargetOpcode::G_CTTZ:
2869 case TargetOpcode::G_CTTZ_ZERO_POISON:
2870 case TargetOpcode::G_CTLZ:
2871 case TargetOpcode::G_CTLZ_ZERO_POISON:
2872 case TargetOpcode::G_CTLS:
2873 case TargetOpcode::G_CTPOP: {
2874 if (TypeIdx == 0) {
2875 Observer.changingInstr(MI);
2876 widenScalarDst(MI, WideTy, 0);
2877 Observer.changedInstr(MI);
2878 return Legalized;
2879 }
2880
2881 Register SrcReg = MI.getOperand(1).getReg();
2882
2883 // First extend the input.
2884 unsigned ExtOpc;
2885 switch (Opcode) {
2886 case TargetOpcode::G_CTTZ:
2887 case TargetOpcode::G_CTTZ_ZERO_POISON:
2888 case TargetOpcode::G_CTLZ_ZERO_POISON: // poison shifted out below
2889 ExtOpc = TargetOpcode::G_ANYEXT;
2890 break;
2891 case TargetOpcode::G_CTLS:
2892 ExtOpc = TargetOpcode::G_SEXT;
2893 break;
2894 default:
2895 ExtOpc = TargetOpcode::G_ZEXT;
2896 }
2897
2898 auto MIBSrc = MIRBuilder.buildInstr(ExtOpc, {WideTy}, {SrcReg});
2899 LLT CurTy = MRI.getType(SrcReg);
2900 unsigned NewOpc = Opcode;
2901 if (NewOpc == TargetOpcode::G_CTTZ) {
2902 // The count is the same in the larger type except if the original
2903 // value was zero. This can be handled by setting the bit just off
2904 // the top of the original type.
2905 auto TopBit = APInt::getOneBitSet(WideTy.getScalarSizeInBits(),
2906 CurTy.getScalarSizeInBits());
2907 MIBSrc = MIRBuilder.buildOr(
2908 WideTy, MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit));
2909 // Now we know the operand is non-zero, use the more relaxed opcode.
2910 NewOpc = TargetOpcode::G_CTTZ_ZERO_POISON;
2911 }
2912
2913 unsigned SizeDiff =
2914 WideTy.getScalarSizeInBits() - CurTy.getScalarSizeInBits();
2915
2916 if (Opcode == TargetOpcode::G_CTLZ_ZERO_POISON) {
2917 // An optimization where the result is the CTLZ after the left shift by
2918 // (Difference in widety and current ty), that is,
2919 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2920 // Result = ctlz MIBSrc
2921 MIBSrc = MIRBuilder.buildShl(WideTy, MIBSrc,
2922 MIRBuilder.buildConstant(WideTy, SizeDiff));
2923 }
2924
2925 // Perform the operation at the larger size.
2926 auto MIBNewOp = MIRBuilder.buildInstr(NewOpc, {WideTy}, {MIBSrc});
2927 // This is already the correct result for CTPOP and CTTZs
2928 if (Opcode == TargetOpcode::G_CTLZ || Opcode == TargetOpcode::G_CTLS) {
2929 // The correct result is NewOp - (Difference in widety and current ty).
2930 // At this stage SUB is guaranteed to be positive no-wrap,
2931 // that to be used in further KnownBits optimizations for CTLZ.
2932 MIBNewOp = MIRBuilder.buildSub(
2933 WideTy, MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff),
2934 Opcode == TargetOpcode::G_CTLZ
2935 ? std::optional<unsigned>(MachineInstr::NoUWrap)
2936 : std::nullopt);
2937 }
2938
2939 MIRBuilder.buildZExtOrTrunc(MI.getOperand(0), MIBNewOp);
2940 MI.eraseFromParent();
2941 return Legalized;
2942 }
2943 case TargetOpcode::G_BSWAP: {
2944 Observer.changingInstr(MI);
2945 Register DstReg = MI.getOperand(0).getReg();
2946
2947 Register ShrReg = MRI.createGenericVirtualRegister(WideTy);
2948 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2949 Register ShiftAmtReg = MRI.createGenericVirtualRegister(WideTy);
2950 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2951
2952 MI.getOperand(0).setReg(DstExt);
2953
2954 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2955
2956 LLT Ty = MRI.getType(DstReg);
2957 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2958 MIRBuilder.buildConstant(ShiftAmtReg, DiffBits);
2959 MIRBuilder.buildLShr(ShrReg, DstExt, ShiftAmtReg);
2960
2961 MIRBuilder.buildTrunc(DstReg, ShrReg);
2962 Observer.changedInstr(MI);
2963 return Legalized;
2964 }
2965 case TargetOpcode::G_BITREVERSE: {
2966 Observer.changingInstr(MI);
2967
2968 Register DstReg = MI.getOperand(0).getReg();
2969 LLT Ty = MRI.getType(DstReg);
2970 unsigned DiffBits = WideTy.getScalarSizeInBits() - Ty.getScalarSizeInBits();
2971
2972 Register DstExt = MRI.createGenericVirtualRegister(WideTy);
2973 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2974 MI.getOperand(0).setReg(DstExt);
2975 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
2976
2977 auto ShiftAmt = MIRBuilder.buildConstant(WideTy, DiffBits);
2978 auto Shift = MIRBuilder.buildLShr(WideTy, DstExt, ShiftAmt);
2979 MIRBuilder.buildTrunc(DstReg, Shift);
2980 Observer.changedInstr(MI);
2981 return Legalized;
2982 }
2983 case TargetOpcode::G_FREEZE:
2984 case TargetOpcode::G_CONSTANT_FOLD_BARRIER:
2985 Observer.changingInstr(MI);
2986 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
2987 widenScalarDst(MI, WideTy);
2988 Observer.changedInstr(MI);
2989 return Legalized;
2990
2991 case TargetOpcode::G_ABS:
2992 Observer.changingInstr(MI);
2993 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
2994 widenScalarDst(MI, WideTy);
2995 Observer.changedInstr(MI);
2996 return Legalized;
2997
2998 case TargetOpcode::G_ADD:
2999 case TargetOpcode::G_AND:
3000 case TargetOpcode::G_MUL:
3001 case TargetOpcode::G_OR:
3002 case TargetOpcode::G_XOR:
3003 case TargetOpcode::G_SUB:
3004 case TargetOpcode::G_SHUFFLE_VECTOR:
3005 // Perform operation at larger width (any extension is fines here, high bits
3006 // don't affect the result) and then truncate the result back to the
3007 // original type.
3008 Observer.changingInstr(MI);
3009 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3010 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3011 widenScalarDst(MI, WideTy);
3012 Observer.changedInstr(MI);
3013 return Legalized;
3014
3015 case TargetOpcode::G_SBFX:
3016 case TargetOpcode::G_UBFX:
3017 Observer.changingInstr(MI);
3018
3019 if (TypeIdx == 0) {
3020 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3021 widenScalarDst(MI, WideTy);
3022 } else {
3023 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3024 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3025 }
3026
3027 Observer.changedInstr(MI);
3028 return Legalized;
3029
3030 case TargetOpcode::G_SHL:
3031 Observer.changingInstr(MI);
3032
3033 if (TypeIdx == 0) {
3034 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3035 widenScalarDst(MI, WideTy);
3036 } else {
3037 assert(TypeIdx == 1);
3038 // The "number of bits to shift" operand must preserve its value as an
3039 // unsigned integer:
3040 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3041 }
3042
3043 Observer.changedInstr(MI);
3044 return Legalized;
3045
3046 case TargetOpcode::G_ROTR:
3047 case TargetOpcode::G_ROTL:
3048 if (TypeIdx != 1)
3049 return UnableToLegalize;
3050
3051 Observer.changingInstr(MI);
3052 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3053 Observer.changedInstr(MI);
3054 return Legalized;
3055
3056 case TargetOpcode::G_SDIV:
3057 case TargetOpcode::G_SREM:
3058 case TargetOpcode::G_SMIN:
3059 case TargetOpcode::G_SMAX:
3060 case TargetOpcode::G_ABDS:
3061 Observer.changingInstr(MI);
3062 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3063 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3064 widenScalarDst(MI, WideTy);
3065 Observer.changedInstr(MI);
3066 return Legalized;
3067
3068 case TargetOpcode::G_SDIVREM:
3069 Observer.changingInstr(MI);
3070 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3071 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_SEXT);
3072 widenScalarDst(MI, WideTy);
3073 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3074 widenScalarDst(MI, WideTy, 1);
3075 Observer.changedInstr(MI);
3076 return Legalized;
3077
3078 case TargetOpcode::G_ASHR:
3079 case TargetOpcode::G_LSHR:
3080 Observer.changingInstr(MI);
3081
3082 if (TypeIdx == 0) {
3083 unsigned CvtOp = Opcode == TargetOpcode::G_ASHR ? TargetOpcode::G_SEXT
3084 : TargetOpcode::G_ZEXT;
3085
3086 widenScalarSrc(MI, WideTy, 1, CvtOp);
3087 widenScalarDst(MI, WideTy);
3088 } else {
3089 assert(TypeIdx == 1);
3090 // The "number of bits to shift" operand must preserve its value as an
3091 // unsigned integer:
3092 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3093 }
3094
3095 Observer.changedInstr(MI);
3096 return Legalized;
3097 case TargetOpcode::G_UDIV:
3098 case TargetOpcode::G_UREM:
3099 case TargetOpcode::G_ABDU:
3100 Observer.changingInstr(MI);
3101 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3102 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3103 widenScalarDst(MI, WideTy);
3104 Observer.changedInstr(MI);
3105 return Legalized;
3106 case TargetOpcode::G_UDIVREM:
3107 Observer.changingInstr(MI);
3108 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3109 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3110 widenScalarDst(MI, WideTy);
3111 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3112 widenScalarDst(MI, WideTy, 1);
3113 Observer.changedInstr(MI);
3114 return Legalized;
3115 case TargetOpcode::G_UMIN:
3116 case TargetOpcode::G_UMAX: {
3117 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3118
3119 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3120 unsigned ExtOpc =
3121 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty, Ctx),
3122 getApproximateEVTForLLT(WideTy, Ctx))
3123 ? TargetOpcode::G_SEXT
3124 : TargetOpcode::G_ZEXT;
3125
3126 Observer.changingInstr(MI);
3127 widenScalarSrc(MI, WideTy, 1, ExtOpc);
3128 widenScalarSrc(MI, WideTy, 2, ExtOpc);
3129 widenScalarDst(MI, WideTy);
3130 Observer.changedInstr(MI);
3131 return Legalized;
3132 }
3133
3134 case TargetOpcode::G_SELECT:
3135 Observer.changingInstr(MI);
3136 if (TypeIdx == 0) {
3137 // Perform operation at larger width (any extension is fine here, high
3138 // bits don't affect the result) and then truncate the result back to the
3139 // original type.
3140 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3141 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
3142 widenScalarDst(MI, WideTy);
3143 } else {
3144 bool IsVec = MRI.getType(MI.getOperand(1).getReg()).isVector();
3145 // Explicit extension is required here since high bits affect the result.
3146 widenScalarSrc(MI, WideTy, 1, MIRBuilder.getBoolExtOp(IsVec, false));
3147 }
3148 Observer.changedInstr(MI);
3149 return Legalized;
3150
3151 case TargetOpcode::G_FPEXT:
3152 if (TypeIdx != 1)
3153 return UnableToLegalize;
3154
3155 Observer.changingInstr(MI);
3156 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3157 Observer.changedInstr(MI);
3158 return Legalized;
3159 case TargetOpcode::G_FPTOSI:
3160 case TargetOpcode::G_FPTOUI:
3161 case TargetOpcode::G_INTRINSIC_LRINT:
3162 case TargetOpcode::G_INTRINSIC_LLRINT:
3163 case TargetOpcode::G_IS_FPCLASS:
3164 Observer.changingInstr(MI);
3165
3166 if (TypeIdx == 0)
3167 widenScalarDst(MI, WideTy);
3168 else
3169 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3170
3171 Observer.changedInstr(MI);
3172 return Legalized;
3173 case TargetOpcode::G_SITOFP:
3174 Observer.changingInstr(MI);
3175
3176 if (TypeIdx == 0)
3177 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3178 else
3179 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
3180
3181 Observer.changedInstr(MI);
3182 return Legalized;
3183 case TargetOpcode::G_UITOFP:
3184 Observer.changingInstr(MI);
3185
3186 if (TypeIdx == 0)
3187 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3188 else
3189 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3190
3191 Observer.changedInstr(MI);
3192 return Legalized;
3193 case TargetOpcode::G_FPTOSI_SAT:
3194 case TargetOpcode::G_FPTOUI_SAT:
3195 Observer.changingInstr(MI);
3196
3197 if (TypeIdx == 0) {
3198 Register OldDst = MI.getOperand(0).getReg();
3199 LLT Ty = MRI.getType(OldDst);
3200 Register ExtReg = MRI.createGenericVirtualRegister(WideTy);
3201 Register NewDst;
3202 MI.getOperand(0).setReg(ExtReg);
3203 uint64_t ShortBits = Ty.getScalarSizeInBits();
3204 uint64_t WideBits = WideTy.getScalarSizeInBits();
3205 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
3206 if (Opcode == TargetOpcode::G_FPTOSI_SAT) {
3207 // z = i16 fptosi_sat(a)
3208 // ->
3209 // x = i32 fptosi_sat(a)
3210 // y = smin(x, 32767)
3211 // z = smax(y, -32768)
3212 auto MaxVal = MIRBuilder.buildConstant(
3213 WideTy, APInt::getSignedMaxValue(ShortBits).sext(WideBits));
3214 auto MinVal = MIRBuilder.buildConstant(
3215 WideTy, APInt::getSignedMinValue(ShortBits).sext(WideBits));
3216 Register MidReg =
3217 MIRBuilder.buildSMin(WideTy, ExtReg, MaxVal).getReg(0);
3218 NewDst = MIRBuilder.buildSMax(WideTy, MidReg, MinVal).getReg(0);
3219 } else {
3220 // z = i16 fptoui_sat(a)
3221 // ->
3222 // x = i32 fptoui_sat(a)
3223 // y = smin(x, 65535)
3224 auto MaxVal = MIRBuilder.buildConstant(
3225 WideTy, APInt::getAllOnes(ShortBits).zext(WideBits));
3226 NewDst = MIRBuilder.buildUMin(WideTy, ExtReg, MaxVal).getReg(0);
3227 }
3228 MIRBuilder.buildTrunc(OldDst, NewDst);
3229 } else
3230 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3231
3232 Observer.changedInstr(MI);
3233 return Legalized;
3234 case TargetOpcode::G_LOAD:
3235 case TargetOpcode::G_SEXTLOAD:
3236 case TargetOpcode::G_ZEXTLOAD:
3237 case TargetOpcode::G_FPEXTLOAD:
3238 Observer.changingInstr(MI);
3239 widenScalarDst(MI, WideTy);
3240 Observer.changedInstr(MI);
3241 return Legalized;
3242
3243 case TargetOpcode::G_STORE: {
3244 if (TypeIdx != 0)
3245 return UnableToLegalize;
3246
3247 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
3248 assert(!Ty.isPointerOrPointerVector() && "Can't widen type");
3249 if (!Ty.isScalar()) {
3250 // We need to widen the vector element type.
3251 Observer.changingInstr(MI);
3252 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
3253 // We also need to adjust the MMO to turn this into a truncating store.
3254 MachineMemOperand &MMO = **MI.memoperands_begin();
3255 MachineFunction &MF = MIRBuilder.getMF();
3256 auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), Ty);
3257 MI.setMemRefs(MF, {NewMMO});
3258 Observer.changedInstr(MI);
3259 return Legalized;
3260 }
3261
3262 Observer.changingInstr(MI);
3263
3264 unsigned ExtType = Ty.getScalarSizeInBits() == 1 ?
3265 TargetOpcode::G_ZEXT : TargetOpcode::G_ANYEXT;
3266 widenScalarSrc(MI, WideTy, 0, ExtType);
3267
3268 Observer.changedInstr(MI);
3269 return Legalized;
3270 }
3271 case TargetOpcode::G_FPTRUNCSTORE:
3272 if (TypeIdx != 0)
3273 return UnableToLegalize;
3274 Observer.changingInstr(MI);
3275 widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_FPEXT);
3276 Observer.changedInstr(MI);
3277 return Legalized;
3278 case TargetOpcode::G_CONSTANT: {
3279 MachineOperand &SrcMO = MI.getOperand(1);
3280 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3281 unsigned ExtOpc = LI.getExtOpcodeForWideningConstant(
3282 MRI.getType(MI.getOperand(0).getReg()));
3283 assert((ExtOpc == TargetOpcode::G_ZEXT || ExtOpc == TargetOpcode::G_SEXT ||
3284 ExtOpc == TargetOpcode::G_ANYEXT) &&
3285 "Illegal Extend");
3286 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3287 const APInt &Val = (ExtOpc == TargetOpcode::G_SEXT)
3288 ? SrcVal.sext(WideTy.getSizeInBits())
3289 : SrcVal.zext(WideTy.getSizeInBits());
3290 Observer.changingInstr(MI);
3291 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3292
3293 widenScalarDst(MI, WideTy);
3294 Observer.changedInstr(MI);
3295 return Legalized;
3296 }
3297 case TargetOpcode::G_FCONSTANT: {
3298 // To avoid changing the bits of the constant due to extension to a larger
3299 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3300 MachineOperand &SrcMO = MI.getOperand(1);
3301 APInt Val = SrcMO.getFPImm()->getValueAPF().bitcastToAPInt();
3302 MIRBuilder.setInstrAndDebugLoc(MI);
3303 auto IntCst = MIRBuilder.buildConstant(MI.getOperand(0).getReg(), Val);
3304 widenScalarDst(*IntCst, WideTy, 0, TargetOpcode::G_TRUNC);
3305 MI.eraseFromParent();
3306 return Legalized;
3307 }
3308 case TargetOpcode::G_IMPLICIT_DEF: {
3309 Observer.changingInstr(MI);
3310 widenScalarDst(MI, WideTy);
3311 Observer.changedInstr(MI);
3312 return Legalized;
3313 }
3314 case TargetOpcode::G_BRCOND:
3315 Observer.changingInstr(MI);
3316 widenScalarSrc(MI, WideTy, 0, MIRBuilder.getBoolExtOp(false, false));
3317 Observer.changedInstr(MI);
3318 return Legalized;
3319
3320 case TargetOpcode::G_FCMP:
3321 Observer.changingInstr(MI);
3322 if (TypeIdx == 0)
3323 widenScalarDst(MI, WideTy);
3324 else {
3325 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3326 widenScalarSrcUsingFPExt(MI, WideTy, 3);
3327 }
3328 Observer.changedInstr(MI);
3329 return Legalized;
3330
3331 case TargetOpcode::G_ICMP:
3332 Observer.changingInstr(MI);
3333 if (TypeIdx == 0)
3334 widenScalarDst(MI, WideTy);
3335 else {
3336 LLT SrcTy = MRI.getType(MI.getOperand(2).getReg());
3337 CmpInst::Predicate Pred =
3338 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
3339
3340 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
3341 unsigned ExtOpcode =
3342 (CmpInst::isSigned(Pred) ||
3343 TLI.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy, Ctx),
3344 getApproximateEVTForLLT(WideTy, Ctx)))
3345 ? TargetOpcode::G_SEXT
3346 : TargetOpcode::G_ZEXT;
3347 widenScalarSrc(MI, WideTy, 2, ExtOpcode);
3348 widenScalarSrc(MI, WideTy, 3, ExtOpcode);
3349 }
3350 Observer.changedInstr(MI);
3351 return Legalized;
3352
3353 case TargetOpcode::G_PTR_ADD:
3354 assert(TypeIdx == 1 && "unable to legalize pointer of G_PTR_ADD");
3355 Observer.changingInstr(MI);
3356 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3357 Observer.changedInstr(MI);
3358 return Legalized;
3359
3360 case TargetOpcode::G_PHI: {
3361 assert(TypeIdx == 0 && "Expecting only Idx 0");
3362
3363 Observer.changingInstr(MI);
3364 for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
3365 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
3366 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
3367 widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
3368 }
3369
3370 MachineBasicBlock &MBB = *MI.getParent();
3371 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
3372 widenScalarDst(MI, WideTy);
3373 Observer.changedInstr(MI);
3374 return Legalized;
3375 }
3376 case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
3377 if (TypeIdx == 0) {
3378 Register VecReg = MI.getOperand(1).getReg();
3379 LLT VecTy = MRI.getType(VecReg);
3380 Observer.changingInstr(MI);
3381
3382 widenScalarSrc(MI, LLT::vector(VecTy.getElementCount(), WideTy), 1,
3383 TargetOpcode::G_ANYEXT);
3384
3385 widenScalarDst(MI, WideTy, 0);
3386 Observer.changedInstr(MI);
3387 return Legalized;
3388 }
3389
3390 if (TypeIdx != 2)
3391 return UnableToLegalize;
3392 Observer.changingInstr(MI);
3393 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3394 Observer.changedInstr(MI);
3395 return Legalized;
3396 }
3397 case TargetOpcode::G_INSERT_VECTOR_ELT: {
3398 if (TypeIdx == 0) {
3399 Observer.changingInstr(MI);
3400 const LLT WideEltTy = WideTy.getElementType();
3401
3402 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3403 widenScalarSrc(MI, WideEltTy, 2, TargetOpcode::G_ANYEXT);
3404 widenScalarDst(MI, WideTy, 0);
3405 Observer.changedInstr(MI);
3406 return Legalized;
3407 }
3408
3409 if (TypeIdx == 1) {
3410 Observer.changingInstr(MI);
3411
3412 Register VecReg = MI.getOperand(1).getReg();
3413 LLT VecTy = MRI.getType(VecReg);
3414 LLT WideVecTy = VecTy.changeVectorElementType(WideTy);
3415
3416 widenScalarSrc(MI, WideVecTy, 1, TargetOpcode::G_ANYEXT);
3417 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
3418 widenScalarDst(MI, WideVecTy, 0);
3419 Observer.changedInstr(MI);
3420 return Legalized;
3421 }
3422
3423 if (TypeIdx == 2) {
3424 Observer.changingInstr(MI);
3425 widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ZEXT);
3426 Observer.changedInstr(MI);
3427 return Legalized;
3428 }
3429
3430 return UnableToLegalize;
3431 }
3432 case TargetOpcode::G_FADD:
3433 case TargetOpcode::G_FMUL:
3434 case TargetOpcode::G_FSUB:
3435 case TargetOpcode::G_FMA:
3436 case TargetOpcode::G_FMAD:
3437 case TargetOpcode::G_FNEG:
3438 case TargetOpcode::G_FABS:
3439 case TargetOpcode::G_FCANONICALIZE:
3440 case TargetOpcode::G_FMINNUM:
3441 case TargetOpcode::G_FMAXNUM:
3442 case TargetOpcode::G_FMINNUM_IEEE:
3443 case TargetOpcode::G_FMAXNUM_IEEE:
3444 case TargetOpcode::G_FMINIMUM:
3445 case TargetOpcode::G_FMAXIMUM:
3446 case TargetOpcode::G_FMINIMUMNUM:
3447 case TargetOpcode::G_FMAXIMUMNUM:
3448 case TargetOpcode::G_FDIV:
3449 case TargetOpcode::G_FREM:
3450 case TargetOpcode::G_FCEIL:
3451 case TargetOpcode::G_FFLOOR:
3452 case TargetOpcode::G_FCOS:
3453 case TargetOpcode::G_FSIN:
3454 case TargetOpcode::G_FTAN:
3455 case TargetOpcode::G_FACOS:
3456 case TargetOpcode::G_FASIN:
3457 case TargetOpcode::G_FATAN:
3458 case TargetOpcode::G_FATAN2:
3459 case TargetOpcode::G_FCOSH:
3460 case TargetOpcode::G_FSINH:
3461 case TargetOpcode::G_FTANH:
3462 case TargetOpcode::G_FLOG10:
3463 case TargetOpcode::G_FLOG:
3464 case TargetOpcode::G_FLOG2:
3465 case TargetOpcode::G_FRINT:
3466 case TargetOpcode::G_FNEARBYINT:
3467 case TargetOpcode::G_FSQRT:
3468 case TargetOpcode::G_FEXP:
3469 case TargetOpcode::G_FEXP2:
3470 case TargetOpcode::G_FEXP10:
3471 case TargetOpcode::G_FPOW:
3472 case TargetOpcode::G_INTRINSIC_TRUNC:
3473 case TargetOpcode::G_INTRINSIC_ROUND:
3474 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
3475 assert(TypeIdx == 0);
3476 Observer.changingInstr(MI);
3477
3478 for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
3479 widenScalarSrcUsingFPExt(MI, WideTy, I);
3480
3481 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3482 Observer.changedInstr(MI);
3483 return Legalized;
3484 case TargetOpcode::G_FMODF: {
3485 Observer.changingInstr(MI);
3486 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3487
3488 widenScalarDstUsingFPTrunc(MI, WideTy, 1);
3489 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), --MIRBuilder.getInsertPt());
3490 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3491 Observer.changedInstr(MI);
3492 return Legalized;
3493 }
3494 case TargetOpcode::G_FPOWI:
3495 case TargetOpcode::G_FLDEXP:
3496 case TargetOpcode::G_STRICT_FLDEXP: {
3497 if (TypeIdx == 0) {
3498 if (Opcode == TargetOpcode::G_STRICT_FLDEXP)
3499 return UnableToLegalize;
3500
3501 Observer.changingInstr(MI);
3502 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3503 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3504 Observer.changedInstr(MI);
3505 return Legalized;
3506 }
3507
3508 if (TypeIdx == 1) {
3509 // For some reason SelectionDAG tries to promote to a libcall without
3510 // actually changing the integer type for promotion.
3511 Observer.changingInstr(MI);
3512 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
3513 Observer.changedInstr(MI);
3514 return Legalized;
3515 }
3516
3517 return UnableToLegalize;
3518 }
3519 case TargetOpcode::G_FFREXP: {
3520 Observer.changingInstr(MI);
3521
3522 if (TypeIdx == 0) {
3523 widenScalarSrcUsingFPExt(MI, WideTy, 2);
3524 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3525 } else {
3526 widenScalarDst(MI, WideTy, 1);
3527 }
3528
3529 Observer.changedInstr(MI);
3530 return Legalized;
3531 }
3532 case TargetOpcode::G_LROUND:
3533 case TargetOpcode::G_LLROUND:
3534 Observer.changingInstr(MI);
3535
3536 if (TypeIdx == 0)
3537 widenScalarDst(MI, WideTy);
3538 else
3539 widenScalarSrcUsingFPExt(MI, WideTy, 1);
3540
3541 Observer.changedInstr(MI);
3542 return Legalized;
3543
3544 case TargetOpcode::G_INTTOPTR:
3545 if (TypeIdx != 1)
3546 return UnableToLegalize;
3547
3548 Observer.changingInstr(MI);
3549 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
3550 Observer.changedInstr(MI);
3551 return Legalized;
3552 case TargetOpcode::G_PTRTOINT:
3553 if (TypeIdx != 0)
3554 return UnableToLegalize;
3555
3556 Observer.changingInstr(MI);
3557 widenScalarDst(MI, WideTy, 0);
3558 Observer.changedInstr(MI);
3559 return Legalized;
3560 case TargetOpcode::G_BUILD_VECTOR: {
3561 Observer.changingInstr(MI);
3562
3563 const LLT WideEltTy = TypeIdx == 1 ? WideTy : WideTy.getElementType();
3564 for (int I = 1, E = MI.getNumOperands(); I != E; ++I)
3565 widenScalarSrc(MI, WideEltTy, I, TargetOpcode::G_ANYEXT);
3566
3567 // Avoid changing the result vector type if the source element type was
3568 // requested.
3569 if (TypeIdx == 1) {
3570 MI.setDesc(MIRBuilder.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC));
3571 } else {
3572 widenScalarDst(MI, WideTy, 0);
3573 }
3574
3575 Observer.changedInstr(MI);
3576 return Legalized;
3577 }
3578 case TargetOpcode::G_SEXT_INREG:
3579 if (TypeIdx != 0)
3580 return UnableToLegalize;
3581
3582 Observer.changingInstr(MI);
3583 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3584 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3585 Observer.changedInstr(MI);
3586 return Legalized;
3587 case TargetOpcode::G_PTRMASK: {
3588 if (TypeIdx != 1)
3589 return UnableToLegalize;
3590 Observer.changingInstr(MI);
3591 widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
3592 Observer.changedInstr(MI);
3593 return Legalized;
3594 }
3595 case TargetOpcode::G_VECREDUCE_ADD: {
3596 if (TypeIdx != 1)
3597 return UnableToLegalize;
3598 Observer.changingInstr(MI);
3599 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3600 widenScalarDst(MI, WideTy.getScalarType(), 0, TargetOpcode::G_TRUNC);
3601 Observer.changedInstr(MI);
3602 return Legalized;
3603 }
3604 case TargetOpcode::G_VECREDUCE_FADD:
3605 case TargetOpcode::G_VECREDUCE_FMUL:
3606 case TargetOpcode::G_VECREDUCE_FMIN:
3607 case TargetOpcode::G_VECREDUCE_FMAX:
3608 case TargetOpcode::G_VECREDUCE_FMINIMUM:
3609 case TargetOpcode::G_VECREDUCE_FMAXIMUM: {
3610 if (TypeIdx != 0)
3611 return UnableToLegalize;
3612 Observer.changingInstr(MI);
3613 Register VecReg = MI.getOperand(1).getReg();
3614 LLT VecTy = MRI.getType(VecReg);
3615 LLT WideVecTy = VecTy.changeElementType(WideTy);
3616 widenScalarSrcUsingFPExt(MI, WideVecTy, 1);
3617 widenScalarDstUsingFPTrunc(MI, WideTy, 0);
3618 Observer.changedInstr(MI);
3619 return Legalized;
3620 }
3621 case TargetOpcode::G_VSCALE: {
3622 MachineOperand &SrcMO = MI.getOperand(1);
3623 LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
3624 const APInt &SrcVal = SrcMO.getCImm()->getValue();
3625 // The CImm is always a signed value
3626 const APInt Val = SrcVal.sext(WideTy.getSizeInBits());
3627 Observer.changingInstr(MI);
3628 SrcMO.setCImm(ConstantInt::get(Ctx, Val));
3629 widenScalarDst(MI, WideTy);
3630 Observer.changedInstr(MI);
3631 return Legalized;
3632 }
3633 case TargetOpcode::G_SPLAT_VECTOR: {
3634 if (TypeIdx != 1)
3635 return UnableToLegalize;
3636
3637 Observer.changingInstr(MI);
3638 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3639 Observer.changedInstr(MI);
3640 return Legalized;
3641 }
3642 case TargetOpcode::G_INSERT_SUBVECTOR: {
3643 if (TypeIdx != 0)
3644 return UnableToLegalize;
3645
3647 Register BigVec = IS.getBigVec();
3648 Register SubVec = IS.getSubVec();
3649
3650 LLT SubVecTy = MRI.getType(SubVec);
3651 LLT SubVecWideTy = SubVecTy.changeElementType(WideTy.getElementType());
3652
3653 // Widen the G_INSERT_SUBVECTOR
3654 auto BigZExt = MIRBuilder.buildZExt(WideTy, BigVec);
3655 auto SubZExt = MIRBuilder.buildZExt(SubVecWideTy, SubVec);
3656 auto WideInsert = MIRBuilder.buildInsertSubvector(WideTy, BigZExt, SubZExt,
3657 IS.getIndexImm());
3658
3659 // Truncate back down
3660 auto SplatZero = MIRBuilder.buildSplatVector(
3661 WideTy, MIRBuilder.buildConstant(WideTy.getElementType(), 0));
3662 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, IS.getReg(0), WideInsert,
3663 SplatZero);
3664
3665 MI.eraseFromParent();
3666
3667 return Legalized;
3668 }
3669 case TargetOpcode::G_BITCAST:
3670 if (WideTy.isVector())
3671 return UnableToLegalize;
3672 Observer.changingInstr(MI);
3673 if (TypeIdx == 0)
3674 widenScalarDst(MI, WideTy, 0, TargetOpcode::G_TRUNC);
3675 else
3676 widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
3677 Observer.changedInstr(MI);
3678
3679 Register Dst = MI.getOperand(0).getReg();
3680 Register Src = MI.getOperand(1).getReg();
3681 if (MRI.getType(Dst) == MRI.getType(Src)) {
3682 Observer.changingAllUsesOfReg(MRI, Dst);
3683 MRI.replaceRegWith(Dst, Src);
3684 Observer.finishedChangingAllUsesOfReg();
3685 MI.eraseFromParent();
3686 }
3687
3688 return Legalized;
3689 }
3690}
3691
3693 MachineIRBuilder &B, Register Src, LLT Ty) {
3694 auto Unmerge = B.buildUnmerge(Ty, Src);
3695 for (int I = 0, E = Unmerge->getNumOperands() - 1; I != E; ++I)
3696 Pieces.push_back(Unmerge.getReg(I));
3697}
3698
3699static void emitLoadFromConstantPool(Register DstReg, const Constant *ConstVal,
3700 MachineIRBuilder &MIRBuilder) {
3701 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
3702 MachineFunction &MF = MIRBuilder.getMF();
3703 const DataLayout &DL = MIRBuilder.getDataLayout();
3704 unsigned AddrSpace = DL.getDefaultGlobalsAddressSpace();
3705 LLT AddrPtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
3706 LLT DstLLT = MRI.getType(DstReg);
3707
3708 Align Alignment(DL.getABITypeAlign(ConstVal->getType()));
3709
3710 auto Addr = MIRBuilder.buildConstantPool(
3711 AddrPtrTy,
3712 MF.getConstantPool()->getConstantPoolIndex(ConstVal, Alignment));
3713
3714 MachineMemOperand *MMO =
3716 MachineMemOperand::MOLoad, DstLLT, Alignment);
3717
3718 MIRBuilder.buildLoadInstr(TargetOpcode::G_LOAD, DstReg, Addr, *MMO);
3719}
3720
3723 const MachineOperand &ConstOperand = MI.getOperand(1);
3724 const Constant *ConstantVal = ConstOperand.getCImm();
3725
3726 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3727 MI.eraseFromParent();
3728
3729 return Legalized;
3730}
3731
3734 const MachineOperand &ConstOperand = MI.getOperand(1);
3735 const Constant *ConstantVal = ConstOperand.getFPImm();
3736
3737 emitLoadFromConstantPool(MI.getOperand(0).getReg(), ConstantVal, MIRBuilder);
3738 MI.eraseFromParent();
3739
3740 return Legalized;
3741}
3742
3745 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
3746 if (SrcTy.isVector()) {
3747 LLT SrcEltTy = SrcTy.getElementType();
3749
3750 if (DstTy.isVector()) {
3751 int NumDstElt = DstTy.getNumElements();
3752 int NumSrcElt = SrcTy.getNumElements();
3753
3754 LLT DstEltTy = DstTy.getElementType();
3755 LLT DstCastTy = DstEltTy; // Intermediate bitcast result type
3756 LLT SrcPartTy = SrcEltTy; // Original unmerge result type.
3757
3758 // If there's an element size mismatch, insert intermediate casts to match
3759 // the result element type.
3760 if (NumSrcElt < NumDstElt) { // Source element type is larger.
3761 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3762 //
3763 // =>
3764 //
3765 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3766 // %3:_(<2 x s8>) = G_BITCAST %2
3767 // %4:_(<2 x s8>) = G_BITCAST %3
3768 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3769 DstCastTy = DstTy.changeVectorElementCount(
3770 ElementCount::getFixed(NumDstElt / NumSrcElt));
3771 SrcPartTy = SrcEltTy;
3772 } else if (NumSrcElt > NumDstElt) { // Source element type is smaller.
3773 //
3774 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3775 //
3776 // =>
3777 //
3778 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3779 // %3:_(s16) = G_BITCAST %2
3780 // %4:_(s16) = G_BITCAST %3
3781 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3782 SrcPartTy = SrcTy.changeVectorElementCount(
3783 ElementCount::getFixed(NumSrcElt / NumDstElt));
3784 DstCastTy = DstEltTy;
3785 }
3786
3787 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcPartTy);
3788 for (Register &SrcReg : SrcRegs)
3789 SrcReg = MIRBuilder.buildBitcast(DstCastTy, SrcReg).getReg(0);
3790 } else
3791 getUnmergePieces(SrcRegs, MIRBuilder, Src, SrcEltTy);
3792
3793 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3794 MI.eraseFromParent();
3795 return Legalized;
3796 }
3797
3798 if (DstTy.isVector()) {
3800 getUnmergePieces(SrcRegs, MIRBuilder, Src, DstTy.getElementType());
3801 MIRBuilder.buildMergeLikeInstr(Dst, SrcRegs);
3802 MI.eraseFromParent();
3803 return Legalized;
3804 }
3805
3806 return UnableToLegalize;
3807}
3808
3809/// Figure out the bit offset into a register when coercing a vector index for
3810/// the wide element type. This is only for the case when promoting vector to
3811/// one with larger elements.
3812//
3813///
3814/// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3815/// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3817 Register Idx,
3818 unsigned NewEltSize,
3819 unsigned OldEltSize) {
3820 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3821 LLT IdxTy = B.getMRI()->getType(Idx);
3822
3823 // Now figure out the amount we need to shift to get the target bits.
3824 auto OffsetMask = B.buildConstant(
3825 IdxTy, ~(APInt::getAllOnes(IdxTy.getSizeInBits()) << Log2EltRatio));
3826 auto OffsetIdx = B.buildAnd(IdxTy, Idx, OffsetMask);
3827 return B.buildShl(IdxTy, OffsetIdx,
3828 B.buildConstant(IdxTy, Log2_32(OldEltSize))).getReg(0);
3829}
3830
3831/// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3832/// is casting to a vector with a smaller element size, perform multiple element
3833/// extracts and merge the results. If this is coercing to a vector with larger
3834/// elements, index the bitcasted vector and extract the target element with bit
3835/// operations. This is intended to force the indexing in the native register
3836/// size for architectures that can dynamically index the register file.
3839 LLT CastTy) {
3840 if (TypeIdx != 1)
3841 return UnableToLegalize;
3842
3843 auto [Dst, DstTy, SrcVec, SrcVecTy, Idx, IdxTy] = MI.getFirst3RegLLTs();
3844
3845 LLT SrcEltTy = SrcVecTy.getElementType();
3846 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3847 unsigned OldNumElts = SrcVecTy.getNumElements();
3848
3849 LLT NewEltTy = CastTy.getScalarType();
3850 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3851
3852 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3853 const unsigned OldEltSize = SrcEltTy.getSizeInBits();
3854 if (NewNumElts > OldNumElts) {
3855 // Decreasing the vector element size
3856 //
3857 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3858 // =>
3859 // v4i32:castx = bitcast x:v2i64
3860 //
3861 // i64 = bitcast
3862 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3863 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3864 //
3865 if (NewNumElts % OldNumElts != 0)
3866 return UnableToLegalize;
3867
3868 // Type of the intermediate result vector.
3869 const unsigned NewEltsPerOldElt = NewNumElts / OldNumElts;
3870 LLT MidTy =
3871 CastTy.changeElementCount(ElementCount::getFixed(NewEltsPerOldElt));
3872
3873 auto NewEltsPerOldEltK = MIRBuilder.buildConstant(IdxTy, NewEltsPerOldElt);
3874
3875 SmallVector<Register, 8> NewOps(NewEltsPerOldElt);
3876 auto NewBaseIdx = MIRBuilder.buildMul(IdxTy, Idx, NewEltsPerOldEltK);
3877
3878 for (unsigned I = 0; I < NewEltsPerOldElt; ++I) {
3879 auto IdxOffset = MIRBuilder.buildConstant(IdxTy, I);
3880 auto TmpIdx = MIRBuilder.buildAdd(IdxTy, NewBaseIdx, IdxOffset);
3881 auto Elt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec, TmpIdx);
3882 NewOps[I] = Elt.getReg(0);
3883 }
3884
3885 auto NewVec = MIRBuilder.buildBuildVector(MidTy, NewOps);
3886 MIRBuilder.buildBitcast(Dst, NewVec);
3887 MI.eraseFromParent();
3888 return Legalized;
3889 }
3890
3891 if (NewNumElts < OldNumElts) {
3892 if (NewEltSize % OldEltSize != 0)
3893 return UnableToLegalize;
3894
3895 // This only depends on powers of 2 because we use bit tricks to figure out
3896 // the bit offset we need to shift to get the target element. A general
3897 // expansion could emit division/multiply.
3898 if (!isPowerOf2_32(NewEltSize / OldEltSize))
3899 return UnableToLegalize;
3900
3901 // Increasing the vector element size.
3902 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3903 //
3904 // =>
3905 //
3906 // %cast = G_BITCAST %vec
3907 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3908 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3909 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3910 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3911 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3912 // %elt = G_TRUNC %elt_bits
3913
3914 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
3915 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
3916
3917 // Divide to get the index in the wider element type.
3918 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
3919
3920 Register WideElt = CastVec;
3921 if (CastTy.isVector()) {
3922 WideElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
3923 ScaledIdx).getReg(0);
3924 }
3925
3926 // Compute the bit offset into the register of the target element.
3928 MIRBuilder, Idx, NewEltSize, OldEltSize);
3929
3930 // Shift the wide element to get the target element.
3931 auto ExtractedBits = MIRBuilder.buildLShr(NewEltTy, WideElt, OffsetBits);
3932 MIRBuilder.buildTrunc(Dst, ExtractedBits);
3933 MI.eraseFromParent();
3934 return Legalized;
3935 }
3936
3937 return UnableToLegalize;
3938}
3939
3940/// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3941/// TargetReg, while preserving other bits in \p TargetReg.
3942///
3943/// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3945 Register TargetReg, Register InsertReg,
3946 Register OffsetBits) {
3947 LLT TargetTy = B.getMRI()->getType(TargetReg);
3948 LLT InsertTy = B.getMRI()->getType(InsertReg);
3949 auto ZextVal = B.buildZExt(TargetTy, InsertReg);
3950 auto ShiftedInsertVal = B.buildShl(TargetTy, ZextVal, OffsetBits);
3951
3952 // Produce a bitmask of the value to insert
3953 auto EltMask = B.buildConstant(
3954 TargetTy, APInt::getLowBitsSet(TargetTy.getSizeInBits(),
3955 InsertTy.getSizeInBits()));
3956 // Shift it into position
3957 auto ShiftedMask = B.buildShl(TargetTy, EltMask, OffsetBits);
3958 auto InvShiftedMask = B.buildNot(TargetTy, ShiftedMask);
3959
3960 // Clear out the bits in the wide element
3961 auto MaskedOldElt = B.buildAnd(TargetTy, TargetReg, InvShiftedMask);
3962
3963 // The value to insert has all zeros already, so stick it into the masked
3964 // wide element.
3965 return B.buildOr(TargetTy, MaskedOldElt, ShiftedInsertVal).getReg(0);
3966}
3967
3968/// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3969/// is increasing the element size, perform the indexing in the target element
3970/// type, and use bit operations to insert at the element position. This is
3971/// intended for architectures that can dynamically index the register file and
3972/// want to force indexing in the native register size.
3975 LLT CastTy) {
3976 if (TypeIdx != 0)
3977 return UnableToLegalize;
3978
3979 auto [Dst, DstTy, SrcVec, SrcVecTy, Val, ValTy, Idx, IdxTy] =
3980 MI.getFirst4RegLLTs();
3981 LLT VecTy = DstTy;
3982
3983 LLT VecEltTy = VecTy.getElementType();
3984 LLT NewEltTy = CastTy.isVector() ? CastTy.getElementType() : CastTy;
3985 const unsigned NewEltSize = NewEltTy.getSizeInBits();
3986 const unsigned OldEltSize = VecEltTy.getSizeInBits();
3987
3988 unsigned NewNumElts = CastTy.isVector() ? CastTy.getNumElements() : 1;
3989 unsigned OldNumElts = VecTy.getNumElements();
3990
3991 Register CastVec = MIRBuilder.buildBitcast(CastTy, SrcVec).getReg(0);
3992 if (NewNumElts < OldNumElts) {
3993 if (NewEltSize % OldEltSize != 0)
3994 return UnableToLegalize;
3995
3996 // This only depends on powers of 2 because we use bit tricks to figure out
3997 // the bit offset we need to shift to get the target element. A general
3998 // expansion could emit division/multiply.
3999 if (!isPowerOf2_32(NewEltSize / OldEltSize))
4000 return UnableToLegalize;
4001
4002 const unsigned Log2EltRatio = Log2_32(NewEltSize / OldEltSize);
4003 auto Log2Ratio = MIRBuilder.buildConstant(IdxTy, Log2EltRatio);
4004
4005 // Divide to get the index in the wider element type.
4006 auto ScaledIdx = MIRBuilder.buildLShr(IdxTy, Idx, Log2Ratio);
4007
4008 Register ExtractedElt = CastVec;
4009 if (CastTy.isVector()) {
4010 ExtractedElt = MIRBuilder.buildExtractVectorElement(NewEltTy, CastVec,
4011 ScaledIdx).getReg(0);
4012 }
4013
4014 // Compute the bit offset into the register of the target element.
4016 MIRBuilder, Idx, NewEltSize, OldEltSize);
4017
4018 Register InsertedElt = buildBitFieldInsert(MIRBuilder, ExtractedElt,
4019 Val, OffsetBits);
4020 if (CastTy.isVector()) {
4021 InsertedElt = MIRBuilder.buildInsertVectorElement(
4022 CastTy, CastVec, InsertedElt, ScaledIdx).getReg(0);
4023 }
4024
4025 MIRBuilder.buildBitcast(Dst, InsertedElt);
4026 MI.eraseFromParent();
4027 return Legalized;
4028 }
4029
4030 return UnableToLegalize;
4031}
4032
4033// This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
4034// those that have smaller than legal operands.
4035//
4036// <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
4037//
4038// ===>
4039//
4040// s32 = G_BITCAST <4 x s8>
4041// s32 = G_BITCAST <4 x s8>
4042// s32 = G_BITCAST <4 x s8>
4043// s32 = G_BITCAST <4 x s8>
4044// <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
4045// <16 x s8> = G_BITCAST <4 x s32>
4048 LLT CastTy) {
4049 // Convert it to CONCAT instruction
4050 auto ConcatMI = dyn_cast<GConcatVectors>(&MI);
4051 if (!ConcatMI) {
4052 return UnableToLegalize;
4053 }
4054
4055 // Check if bitcast is Legal
4056 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
4057 LLT SrcScalTy = CastTy.getScalarType();
4058
4059 // Check if the build vector is Legal
4060 if (!LI.isLegal({TargetOpcode::G_BUILD_VECTOR, {CastTy, SrcScalTy}})) {
4061 return UnableToLegalize;
4062 }
4063
4064 // Bitcast the sources
4065 SmallVector<Register> BitcastRegs;
4066 for (unsigned i = 0; i < ConcatMI->getNumSources(); i++) {
4067 BitcastRegs.push_back(
4068 MIRBuilder.buildBitcast(SrcScalTy, ConcatMI->getSourceReg(i))
4069 .getReg(0));
4070 }
4071
4072 // Build the scalar values into a vector
4073 Register BuildReg =
4074 MIRBuilder.buildBuildVector(CastTy, BitcastRegs).getReg(0);
4075 MIRBuilder.buildBitcast(DstReg, BuildReg);
4076
4077 MI.eraseFromParent();
4078 return Legalized;
4079}
4080
4081// This bitcasts a shuffle vector to a different type currently of the same
4082// element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
4083// will be used instead.
4084//
4085// <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
4086// ===>
4087// <4 x s64> = G_PTRTOINT <4 x p0>
4088// <4 x s64> = G_PTRTOINT <4 x p0>
4089// <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
4090// <16 x p0> = G_INTTOPTR <16 x s64>
4093 LLT CastTy) {
4094 auto ShuffleMI = cast<GShuffleVector>(&MI);
4095 LLT DstTy = MRI.getType(ShuffleMI->getReg(0));
4096 LLT SrcTy = MRI.getType(ShuffleMI->getReg(1));
4097
4098 // We currently only handle vectors of the same size.
4099 if (TypeIdx != 0 ||
4100 CastTy.getScalarSizeInBits() != DstTy.getScalarSizeInBits() ||
4101 CastTy.getElementCount() != DstTy.getElementCount())
4102 return UnableToLegalize;
4103
4104 LLT NewSrcTy = SrcTy.changeElementType(CastTy.getScalarType());
4105
4106 auto Inp1 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(1));
4107 auto Inp2 = MIRBuilder.buildCast(NewSrcTy, ShuffleMI->getReg(2));
4108 auto Shuf =
4109 MIRBuilder.buildShuffleVector(CastTy, Inp1, Inp2, ShuffleMI->getMask());
4110 MIRBuilder.buildCast(ShuffleMI->getReg(0), Shuf);
4111
4112 MI.eraseFromParent();
4113 return Legalized;
4114}
4115
4116/// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
4117///
4118/// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
4119///
4120/// ===>
4121///
4122/// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
4123/// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
4124/// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
4127 LLT CastTy) {
4128 auto ES = cast<GExtractSubvector>(&MI);
4129
4130 if (!CastTy.isVector())
4131 return UnableToLegalize;
4132
4133 if (TypeIdx != 0)
4134 return UnableToLegalize;
4135
4136 Register Dst = ES->getReg(0);
4137 Register Src = ES->getSrcVec();
4138 uint64_t Idx = ES->getIndexImm();
4139
4140 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4141
4142 LLT DstTy = MRI.getType(Dst);
4143 LLT SrcTy = MRI.getType(Src);
4144 ElementCount DstTyEC = DstTy.getElementCount();
4145 ElementCount SrcTyEC = SrcTy.getElementCount();
4146 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4147 auto SrcTyMinElts = SrcTyEC.getKnownMinValue();
4148
4149 if (DstTy == CastTy)
4150 return Legalized;
4151
4152 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4153 return UnableToLegalize;
4154
4155 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4156 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4157 if (CastEltSize < DstEltSize)
4158 return UnableToLegalize;
4159
4160 auto AdjustAmt = CastEltSize / DstEltSize;
4161 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4162 SrcTyMinElts % AdjustAmt != 0)
4163 return UnableToLegalize;
4164
4165 Idx /= AdjustAmt;
4166 SrcTy = LLT::vector(SrcTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4167 auto CastVec = MIRBuilder.buildBitcast(SrcTy, Src);
4168 auto PromotedES = MIRBuilder.buildExtractSubvector(CastTy, CastVec, Idx);
4169 MIRBuilder.buildBitcast(Dst, PromotedES);
4170
4171 ES->eraseFromParent();
4172 return Legalized;
4173}
4174
4175/// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
4176///
4177/// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
4178/// <vscale x 8 x i1>,
4179/// N
4180///
4181/// ===>
4182///
4183/// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
4184/// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
4185/// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
4186/// <vscale x 1 x i8>, N / 8
4187/// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
4190 LLT CastTy) {
4191 auto ES = cast<GInsertSubvector>(&MI);
4192
4193 if (!CastTy.isVector())
4194 return UnableToLegalize;
4195
4196 if (TypeIdx != 0)
4197 return UnableToLegalize;
4198
4199 Register Dst = ES->getReg(0);
4200 Register BigVec = ES->getBigVec();
4201 Register SubVec = ES->getSubVec();
4202 uint64_t Idx = ES->getIndexImm();
4203
4204 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
4205
4206 LLT DstTy = MRI.getType(Dst);
4207 LLT BigVecTy = MRI.getType(BigVec);
4208 LLT SubVecTy = MRI.getType(SubVec);
4209
4210 if (DstTy == CastTy)
4211 return Legalized;
4212
4213 if (DstTy.getSizeInBits() != CastTy.getSizeInBits())
4214 return UnableToLegalize;
4215
4216 ElementCount DstTyEC = DstTy.getElementCount();
4217 ElementCount BigVecTyEC = BigVecTy.getElementCount();
4218 ElementCount SubVecTyEC = SubVecTy.getElementCount();
4219 auto DstTyMinElts = DstTyEC.getKnownMinValue();
4220 auto BigVecTyMinElts = BigVecTyEC.getKnownMinValue();
4221 auto SubVecTyMinElts = SubVecTyEC.getKnownMinValue();
4222
4223 unsigned CastEltSize = CastTy.getElementType().getSizeInBits();
4224 unsigned DstEltSize = DstTy.getElementType().getSizeInBits();
4225 if (CastEltSize < DstEltSize)
4226 return UnableToLegalize;
4227
4228 auto AdjustAmt = CastEltSize / DstEltSize;
4229 if (Idx % AdjustAmt != 0 || DstTyMinElts % AdjustAmt != 0 ||
4230 BigVecTyMinElts % AdjustAmt != 0 || SubVecTyMinElts % AdjustAmt != 0)
4231 return UnableToLegalize;
4232
4233 Idx /= AdjustAmt;
4234 BigVecTy = LLT::vector(BigVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4235 SubVecTy = LLT::vector(SubVecTyEC.divideCoefficientBy(AdjustAmt), AdjustAmt);
4236 auto CastBigVec = MIRBuilder.buildBitcast(BigVecTy, BigVec);
4237 auto CastSubVec = MIRBuilder.buildBitcast(SubVecTy, SubVec);
4238 auto PromotedIS =
4239 MIRBuilder.buildInsertSubvector(CastTy, CastBigVec, CastSubVec, Idx);
4240 MIRBuilder.buildBitcast(Dst, PromotedIS);
4241
4242 ES->eraseFromParent();
4243 return Legalized;
4244}
4245
4247 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
4248 Register DstReg = LoadMI.getDstReg();
4249 Register PtrReg = LoadMI.getPointerReg();
4250 LLT DstTy = MRI.getType(DstReg);
4251 MachineMemOperand &MMO = LoadMI.getMMO();
4252 LLT MemTy = MMO.getMemoryType();
4253 MachineFunction &MF = MIRBuilder.getMF();
4254
4255 LLT EltTy = MemTy.getScalarType();
4256
4257 unsigned MemSizeInBits = MemTy.getSizeInBits();
4258 unsigned MemStoreSizeInBits = 8 * MemTy.getSizeInBytes();
4259
4260 if (MemSizeInBits != MemStoreSizeInBits) {
4261 if (MemTy.isVector())
4262 return UnableToLegalize;
4263
4264 // Promote to a byte-sized load if not loading an integral number of
4265 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
4266 LLT WideMemTy = EltTy.changeElementSize(MemStoreSizeInBits);
4267 MachineMemOperand *NewMMO =
4268 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideMemTy);
4269
4270 Register LoadReg = DstReg;
4271 LLT LoadTy = DstTy;
4272
4273 // If this wasn't already an extending load, we need to widen the result
4274 // register to avoid creating a load with a narrower result than the source.
4275 if (MemStoreSizeInBits > DstTy.getSizeInBits()) {
4276 LoadTy = WideMemTy;
4277 LoadReg = MRI.createGenericVirtualRegister(WideMemTy);
4278 }
4279
4280 if (isa<GSExtLoad>(LoadMI)) {
4281 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4282 MIRBuilder.buildSExtInReg(LoadReg, NewLoad, MemSizeInBits);
4283 } else if (isa<GZExtLoad>(LoadMI) || WideMemTy == LoadTy) {
4284 auto NewLoad = MIRBuilder.buildLoad(LoadTy, PtrReg, *NewMMO);
4285 // The extra bits are guaranteed to be zero, since we stored them that
4286 // way. A zext load from Wide thus automatically gives zext from MemVT.
4287 MIRBuilder.buildAssertZExt(LoadReg, NewLoad, MemSizeInBits);
4288 } else {
4289 MIRBuilder.buildLoad(LoadReg, PtrReg, *NewMMO);
4290 }
4291
4292 if (DstTy != LoadTy)
4293 MIRBuilder.buildTrunc(DstReg, LoadReg);
4294
4295 LoadMI.eraseFromParent();
4296 return Legalized;
4297 }
4298
4299 // Big endian lowering not implemented.
4300 if (MIRBuilder.getDataLayout().isBigEndian())
4301 return UnableToLegalize;
4302
4303 // This load needs splitting into power of 2 sized loads.
4304 //
4305 // Our strategy here is to generate anyextending loads for the smaller
4306 // types up to next power-2 result type, and then combine the two larger
4307 // result values together, before truncating back down to the non-pow-2
4308 // type.
4309 // E.g. v1 = i24 load =>
4310 // v2 = i32 zextload (2 byte)
4311 // v3 = i32 load (1 byte)
4312 // v4 = i32 shl v3, 16
4313 // v5 = i32 or v4, v2
4314 // v1 = i24 trunc v5
4315 // By doing this we generate the correct truncate which should get
4316 // combined away as an artifact with a matching extend.
4317
4318 uint64_t LargeSplitSize, SmallSplitSize;
4319
4320 if (!isPowerOf2_32(MemSizeInBits)) {
4321 // This load needs splitting into power of 2 sized loads.
4322 LargeSplitSize = llvm::bit_floor(MemSizeInBits);
4323 SmallSplitSize = MemSizeInBits - LargeSplitSize;
4324 } else {
4325 // This is already a power of 2, but we still need to split this in half.
4326 //
4327 // Assume we're being asked to decompose an unaligned load.
4328 // TODO: If this requires multiple splits, handle them all at once.
4329 auto &Ctx = MF.getFunction().getContext();
4330 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4331 return UnableToLegalize;
4332
4333 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4334 }
4335
4336 if (MemTy.isVector()) {
4337 // TODO: Handle vector extloads
4338 if (MemTy != DstTy)
4339 return UnableToLegalize;
4340
4341 Align Alignment = LoadMI.getAlign();
4342 // Given an alignment larger than the size of the memory, we can increase
4343 // the size of the load without needing to scalarize it.
4344 if (Alignment.value() * 8 > MemSizeInBits &&
4346 LLT MoreTy = DstTy.changeVectorElementCount(
4348 MachineMemOperand *NewMMO = MF.getMachineMemOperand(&MMO, 0, MoreTy);
4349 auto NewLoad = MIRBuilder.buildLoad(MoreTy, PtrReg, *NewMMO);
4350 MIRBuilder.buildDeleteTrailingVectorElements(LoadMI.getReg(0),
4351 NewLoad.getReg(0));
4352 LoadMI.eraseFromParent();
4353 return Legalized;
4354 }
4355
4356 // TODO: We can do better than scalarizing the vector and at least split it
4357 // in half.
4358 return reduceLoadStoreWidth(LoadMI, 0, DstTy.getElementType());
4359 }
4360
4361 MachineMemOperand *LargeMMO =
4362 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4363 MachineMemOperand *SmallMMO =
4364 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4365
4366 LLT PtrTy = MRI.getType(PtrReg);
4367 unsigned AnyExtSize = PowerOf2Ceil(DstTy.getSizeInBits());
4368
4369 LLT AnyExtTy;
4370 LLT OffsetCstRes;
4371 if (EltTy.isPointer()) {
4372 AnyExtTy = LLT::scalar(AnyExtSize);
4373 OffsetCstRes = LLT::scalar(PtrTy.getSizeInBits());
4374 } else {
4375 AnyExtTy = DstTy.changeElementSize(AnyExtSize);
4376 OffsetCstRes = DstTy.changeElementSize(PtrTy.getSizeInBits());
4377 }
4378
4379 auto LargeLoad = MIRBuilder.buildLoadInstr(TargetOpcode::G_ZEXTLOAD, AnyExtTy,
4380 PtrReg, *LargeMMO);
4381
4382 auto OffsetCst = MIRBuilder.buildConstant(OffsetCstRes, LargeSplitSize / 8);
4383 Register PtrAddReg = MRI.createGenericVirtualRegister(PtrTy);
4384 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrAddReg, PtrReg, OffsetCst);
4385 auto SmallLoad = MIRBuilder.buildLoadInstr(LoadMI.getOpcode(), AnyExtTy,
4386 SmallPtr, *SmallMMO);
4387
4388 auto ShiftAmt = MIRBuilder.buildConstant(AnyExtTy, LargeSplitSize);
4389 auto Shift = MIRBuilder.buildShl(AnyExtTy, SmallLoad, ShiftAmt);
4390
4391 if (AnyExtTy == DstTy)
4392 MIRBuilder.buildOr(DstReg, Shift, LargeLoad);
4393 else if (AnyExtTy.getSizeInBits() != DstTy.getSizeInBits()) {
4394 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4395 MIRBuilder.buildTrunc(DstReg, {Or});
4396 } else {
4397 assert(DstTy.isPointer() && "expected pointer");
4398 auto Or = MIRBuilder.buildOr(AnyExtTy, Shift, LargeLoad);
4399
4400 // FIXME: We currently consider this to be illegal for non-integral address
4401 // spaces, but we need still need a way to reinterpret the bits.
4402 MIRBuilder.buildIntToPtr(DstReg, Or);
4403 }
4404
4405 LoadMI.eraseFromParent();
4406 return Legalized;
4407}
4408
4410 // Lower a non-power of 2 store into multiple pow-2 stores.
4411 // E.g. split an i24 store into an i16 store + i8 store.
4412 // We do this by first extending the stored value to the next largest power
4413 // of 2 type, and then using truncating stores to store the components.
4414 // By doing this, likewise with G_LOAD, generate an extend that can be
4415 // artifact-combined away instead of leaving behind extracts.
4416 Register SrcReg = StoreMI.getValueReg();
4417 Register PtrReg = StoreMI.getPointerReg();
4418 LLT SrcTy = MRI.getType(SrcReg);
4419 MachineFunction &MF = MIRBuilder.getMF();
4420 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4421 LLT MemTy = MMO.getMemoryType();
4422
4423 unsigned StoreWidth = MemTy.getSizeInBits();
4424 unsigned StoreSizeInBits = 8 * MemTy.getSizeInBytes();
4425
4426 if (StoreWidth != StoreSizeInBits && !SrcTy.isVector()) {
4427 // Promote to a byte-sized store with upper bits zero if not
4428 // storing an integral number of bytes. For example, promote
4429 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4430 LLT WideTy = LLT::integer(StoreSizeInBits);
4431
4432 if (StoreSizeInBits > SrcTy.getSizeInBits()) {
4433 // Avoid creating a store with a narrower source than result.
4434 SrcReg = MIRBuilder.buildAnyExt(WideTy, SrcReg).getReg(0);
4435 SrcTy = WideTy;
4436 }
4437
4438 auto ZextInReg = MIRBuilder.buildZExtInReg(SrcTy, SrcReg, StoreWidth);
4439
4440 MachineMemOperand *NewMMO =
4441 MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), WideTy);
4442 MIRBuilder.buildStore(ZextInReg, PtrReg, *NewMMO);
4443 StoreMI.eraseFromParent();
4444 return Legalized;
4445 }
4446
4447 if (MemTy.isVector()) {
4448 if (MemTy != SrcTy)
4449 return scalarizeVectorBooleanStore(StoreMI);
4450
4451 // TODO: We can do better than scalarizing the vector and at least split it
4452 // in half.
4453 return reduceLoadStoreWidth(StoreMI, 0, SrcTy.getElementType());
4454 }
4455
4456 unsigned MemSizeInBits = MemTy.getSizeInBits();
4457 uint64_t LargeSplitSize, SmallSplitSize;
4458
4459 if (!isPowerOf2_32(MemSizeInBits)) {
4460 LargeSplitSize = llvm::bit_floor<uint64_t>(MemTy.getSizeInBits());
4461 SmallSplitSize = MemTy.getSizeInBits() - LargeSplitSize;
4462 } else {
4463 auto &Ctx = MF.getFunction().getContext();
4464 if (TLI.allowsMemoryAccess(Ctx, MIRBuilder.getDataLayout(), MemTy, MMO))
4465 return UnableToLegalize; // Don't know what we're being asked to do.
4466
4467 SmallSplitSize = LargeSplitSize = MemSizeInBits / 2;
4468 }
4469
4470 // Extend to the next pow-2. If this store was itself the result of lowering,
4471 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4472 // that's wider than the stored size.
4473 unsigned AnyExtSize = PowerOf2Ceil(MemTy.getSizeInBits());
4474 const LLT NewSrcTy = LLT::integer(AnyExtSize);
4475
4476 if (SrcTy.isPointer()) {
4477 const LLT IntPtrTy = LLT::integer(SrcTy.getSizeInBits());
4478 SrcReg = MIRBuilder.buildPtrToInt(IntPtrTy, SrcReg).getReg(0);
4479 }
4480
4481 auto ExtVal = MIRBuilder.buildAnyExtOrTrunc(NewSrcTy, SrcReg);
4482
4483 // Obtain the smaller value by shifting away the larger value.
4484 auto ShiftAmt = MIRBuilder.buildConstant(NewSrcTy, LargeSplitSize);
4485 auto SmallVal = MIRBuilder.buildLShr(NewSrcTy, ExtVal, ShiftAmt);
4486
4487 // Generate the PtrAdd and truncating stores.
4488 LLT PtrTy = MRI.getType(PtrReg);
4489 auto OffsetCst = MIRBuilder.buildConstant(LLT::integer(PtrTy.getSizeInBits()),
4490 LargeSplitSize / 8);
4491 auto SmallPtr = MIRBuilder.buildObjectPtrOffset(PtrTy, PtrReg, OffsetCst);
4492
4493 MachineMemOperand *LargeMMO =
4494 MF.getMachineMemOperand(&MMO, 0, LargeSplitSize / 8);
4495 MachineMemOperand *SmallMMO =
4496 MF.getMachineMemOperand(&MMO, LargeSplitSize / 8, SmallSplitSize / 8);
4497 MIRBuilder.buildStore(ExtVal, PtrReg, *LargeMMO);
4498 MIRBuilder.buildStore(SmallVal, SmallPtr, *SmallMMO);
4499 StoreMI.eraseFromParent();
4500 return Legalized;
4501}
4502
4505 Register SrcReg = StoreMI.getValueReg();
4506 Register PtrReg = StoreMI.getPointerReg();
4507 LLT SrcTy = MRI.getType(SrcReg);
4508 MachineMemOperand &MMO = **StoreMI.memoperands_begin();
4509 LLT MemTy = MMO.getMemoryType();
4510 LLT MemScalarTy = MemTy.getElementType();
4511 MachineFunction &MF = MIRBuilder.getMF();
4512
4513 assert(SrcTy.isVector() && "Expect a vector store type");
4514
4515 if (!MemScalarTy.isByteSized()) {
4516 // We need to build an integer scalar of the vector bit pattern.
4517 // It's not legal for us to add padding when storing a vector.
4518 unsigned NumBits = MemTy.getSizeInBits();
4519 LLT IntTy = LLT::integer(NumBits);
4520 auto CurrVal = MIRBuilder.buildConstant(IntTy, 0);
4521 LLT IdxTy = TLI.getVectorIdxLLT(MF.getDataLayout());
4522
4523 for (unsigned I = 0, E = MemTy.getNumElements(); I < E; ++I) {
4524 auto Elt = MIRBuilder.buildExtractVectorElement(
4525 SrcTy.getElementType(), SrcReg, MIRBuilder.buildConstant(IdxTy, I));
4526 auto Trunc = MIRBuilder.buildTrunc(MemScalarTy, Elt);
4527 auto ZExt = MIRBuilder.buildZExt(IntTy, Trunc);
4528 unsigned ShiftIntoIdx = MF.getDataLayout().isBigEndian()
4529 ? (MemTy.getNumElements() - 1) - I
4530 : I;
4531 auto ShiftAmt = MIRBuilder.buildConstant(
4532 IntTy, ShiftIntoIdx * MemScalarTy.getSizeInBits());
4533 auto Shifted = MIRBuilder.buildShl(IntTy, ZExt, ShiftAmt);
4534 CurrVal = MIRBuilder.buildOr(IntTy, CurrVal, Shifted);
4535 }
4536 auto PtrInfo = MMO.getPointerInfo();
4537 auto *NewMMO = MF.getMachineMemOperand(&MMO, PtrInfo, IntTy);
4538 MIRBuilder.buildStore(CurrVal, PtrReg, *NewMMO);
4539 StoreMI.eraseFromParent();
4540 return Legalized;
4541 }
4542
4543 // TODO: implement simple scalarization.
4544 return UnableToLegalize;
4545}
4546
4548LegalizerHelper::bitcast(MachineInstr &MI, unsigned TypeIdx, LLT CastTy) {
4549 switch (MI.getOpcode()) {
4550 case TargetOpcode::G_LOAD: {
4551 if (TypeIdx != 0)
4552 return UnableToLegalize;
4553 MachineMemOperand &MMO = **MI.memoperands_begin();
4554
4555 // Not sure how to interpret a bitcast of an extending load.
4556 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4557 return UnableToLegalize;
4558
4559 Observer.changingInstr(MI);
4560 bitcastDst(MI, CastTy, 0);
4561 MMO.setType(CastTy);
4562 // The range metadata is no longer valid when reinterpreted as a different
4563 // type.
4564 MMO.clearRanges();
4565 Observer.changedInstr(MI);
4566 return Legalized;
4567 }
4568 case TargetOpcode::G_STORE: {
4569 if (TypeIdx != 0)
4570 return UnableToLegalize;
4571
4572 MachineMemOperand &MMO = **MI.memoperands_begin();
4573
4574 // Not sure how to interpret a bitcast of a truncating store.
4575 if (MMO.getMemoryType().getSizeInBits() != CastTy.getSizeInBits())
4576 return UnableToLegalize;
4577
4578 Observer.changingInstr(MI);
4579 bitcastSrc(MI, CastTy, 0);
4580 MMO.setType(CastTy);
4581 Observer.changedInstr(MI);
4582 return Legalized;
4583 }
4584 case TargetOpcode::G_SELECT: {
4585 if (TypeIdx != 0)
4586 return UnableToLegalize;
4587
4588 if (MRI.getType(MI.getOperand(1).getReg()).isVector()) {
4589 LLVM_DEBUG(
4590 dbgs() << "bitcast action not implemented for vector select\n");
4591 return UnableToLegalize;
4592 }
4593
4594 Observer.changingInstr(MI);
4595 bitcastSrc(MI, CastTy, 2);
4596 bitcastSrc(MI, CastTy, 3);
4597 bitcastDst(MI, CastTy, 0);
4598 Observer.changedInstr(MI);
4599 return Legalized;
4600 }
4601 case TargetOpcode::G_AND:
4602 case TargetOpcode::G_OR:
4603 case TargetOpcode::G_XOR: {
4604 Observer.changingInstr(MI);
4605 bitcastSrc(MI, CastTy, 1);
4606 bitcastSrc(MI, CastTy, 2);
4607 bitcastDst(MI, CastTy, 0);
4608 Observer.changedInstr(MI);
4609 return Legalized;
4610 }
4611 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
4612 return bitcastExtractVectorElt(MI, TypeIdx, CastTy);
4613 case TargetOpcode::G_INSERT_VECTOR_ELT:
4614 return bitcastInsertVectorElt(MI, TypeIdx, CastTy);
4615 case TargetOpcode::G_CONCAT_VECTORS:
4616 return bitcastConcatVector(MI, TypeIdx, CastTy);
4617 case TargetOpcode::G_SHUFFLE_VECTOR:
4618 return bitcastShuffleVector(MI, TypeIdx, CastTy);
4619 case TargetOpcode::G_EXTRACT_SUBVECTOR:
4620 return bitcastExtractSubvector(MI, TypeIdx, CastTy);
4621 case TargetOpcode::G_INSERT_SUBVECTOR:
4622 return bitcastInsertSubvector(MI, TypeIdx, CastTy);
4623 default:
4624 return UnableToLegalize;
4625 }
4626}
4627
4628// Legalize an instruction by changing the opcode in place.
4629void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
4631 MI.setDesc(MIRBuilder.getTII().get(NewOpcode));
4633}
4634
4636LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
4637 using namespace TargetOpcode;
4638 switch(MI.getOpcode()) {
4639 default:
4640 return UnableToLegalize;
4641 case TargetOpcode::G_FCONSTANT:
4642 return lowerFConstant(MI);
4643 case TargetOpcode::G_BITCAST:
4644 return lowerBitcast(MI);
4645 case TargetOpcode::G_SREM:
4646 case TargetOpcode::G_UREM: {
4647 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
4648 auto Quot =
4649 MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV, {Ty},
4650 {MI.getOperand(1), MI.getOperand(2)});
4651
4652 auto Prod = MIRBuilder.buildMul(Ty, Quot, MI.getOperand(2));
4653 MIRBuilder.buildSub(MI.getOperand(0), MI.getOperand(1), Prod);
4654 MI.eraseFromParent();
4655 return Legalized;
4656 }
4657 case TargetOpcode::G_SADDO:
4658 case TargetOpcode::G_SSUBO:
4659 return lowerSADDO_SSUBO(MI);
4660 case TargetOpcode::G_SADDE:
4661 return lowerSADDE(MI);
4662 case TargetOpcode::G_SSUBE:
4663 return lowerSSUBE(MI);
4664 case TargetOpcode::G_UMULH:
4665 case TargetOpcode::G_SMULH:
4666 return lowerSMULH_UMULH(MI);
4667 case TargetOpcode::G_SMULO:
4668 case TargetOpcode::G_UMULO: {
4669 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4670 // result.
4671 auto [Res, Overflow, LHS, RHS] = MI.getFirst4Regs();
4672 LLT Ty = MRI.getType(Res);
4673
4674 unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
4675 ? TargetOpcode::G_SMULH
4676 : TargetOpcode::G_UMULH;
4677
4678 Observer.changingInstr(MI);
4679 const auto &TII = MIRBuilder.getTII();
4680 MI.setDesc(TII.get(TargetOpcode::G_MUL));
4681 MI.removeOperand(1);
4682 Observer.changedInstr(MI);
4683
4684 auto HiPart = MIRBuilder.buildInstr(Opcode, {Ty}, {LHS, RHS});
4685 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4686
4687 // Move insert point forward so we can use the Res register if needed.
4688 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
4689
4690 // For *signed* multiply, overflow is detected by checking:
4691 // (hi != (lo >> bitwidth-1))
4692 if (Opcode == TargetOpcode::G_SMULH) {
4693 auto ShiftAmt = MIRBuilder.buildConstant(Ty, Ty.getSizeInBits() - 1);
4694 auto Shifted = MIRBuilder.buildAShr(Ty, Res, ShiftAmt);
4695 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
4696 } else {
4697 MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
4698 }
4699 return Legalized;
4700 }
4701 case TargetOpcode::G_FNEG: {
4702 auto [Res, ResTy, SubByReg, SubByRegTy] = MI.getFirst2RegLLTs();
4703 LLT TyInt =
4704 ResTy.changeElementType(LLT::integer(ResTy.getScalarSizeInBits()));
4705 Register CastedSubByReg = SubByReg;
4706
4707 if (!SubByRegTy.getScalarType().isAnyScalar() &&
4708 !SubByRegTy.getScalarType().isInteger()) {
4709 auto BitcastDst = SubByRegTy.changeElementType(
4710 LLT::integer(SubByRegTy.getScalarSizeInBits()));
4711 CastedSubByReg = MIRBuilder.buildBitcast(BitcastDst, SubByReg).getReg(0);
4712 }
4713
4714 auto SignMask = MIRBuilder.buildConstant(
4715 TyInt, APInt::getSignMask(TyInt.getScalarSizeInBits()));
4716
4717 if (ResTy != TyInt) {
4718 Register NewDst =
4719 MIRBuilder.buildXor(TyInt, CastedSubByReg, SignMask).getReg(0);
4720 MIRBuilder.buildBitcast(Res, NewDst);
4721 } else
4722 MIRBuilder.buildXor(Res, CastedSubByReg, SignMask).getReg(0);
4723
4724 MI.eraseFromParent();
4725 return Legalized;
4726 }
4727 case TargetOpcode::G_FSUB:
4728 case TargetOpcode::G_STRICT_FSUB: {
4729 auto [Res, LHS, RHS] = MI.getFirst3Regs();
4730 LLT Ty = MRI.getType(Res);
4731
4732 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4733 auto Neg = MIRBuilder.buildFNeg(Ty, RHS);
4734
4735 if (MI.getOpcode() == TargetOpcode::G_STRICT_FSUB)
4736 MIRBuilder.buildStrictFAdd(Res, LHS, Neg, MI.getFlags());
4737 else
4738 MIRBuilder.buildFAdd(Res, LHS, Neg, MI.getFlags());
4739
4740 MI.eraseFromParent();
4741 return Legalized;
4742 }
4743 case TargetOpcode::G_FMAD:
4744 return lowerFMad(MI);
4745 case TargetOpcode::G_FFLOOR:
4746 return lowerFFloor(MI);
4747 case TargetOpcode::G_LROUND:
4748 case TargetOpcode::G_LLROUND: {
4749 Register DstReg = MI.getOperand(0).getReg();
4750 Register SrcReg = MI.getOperand(1).getReg();
4751 LLT SrcTy = MRI.getType(SrcReg);
4752 auto Round = MIRBuilder.buildInstr(TargetOpcode::G_INTRINSIC_ROUND, {SrcTy},
4753 {SrcReg});
4754 MIRBuilder.buildFPTOSI(DstReg, Round);
4755 MI.eraseFromParent();
4756 return Legalized;
4757 }
4758 case TargetOpcode::G_INTRINSIC_ROUND:
4759 return lowerIntrinsicRound(MI);
4760 case TargetOpcode::G_FRINT: {
4761 // Since round even is the assumed rounding mode for unconstrained FP
4762 // operations, rint and roundeven are the same operation.
4763 changeOpcode(MI, TargetOpcode::G_INTRINSIC_ROUNDEVEN);
4764 return Legalized;
4765 }
4766 case TargetOpcode::G_INTRINSIC_LRINT:
4767 case TargetOpcode::G_INTRINSIC_LLRINT: {
4768 Register DstReg = MI.getOperand(0).getReg();
4769 Register SrcReg = MI.getOperand(1).getReg();
4770 LLT SrcTy = MRI.getType(SrcReg);
4771 auto Round =
4772 MIRBuilder.buildInstr(TargetOpcode::G_FRINT, {SrcTy}, {SrcReg});
4773 MIRBuilder.buildFPTOSI(DstReg, Round);
4774 MI.eraseFromParent();
4775 return Legalized;
4776 }
4777 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
4778 auto [OldValRes, SuccessRes, Addr, CmpVal, NewVal] = MI.getFirst5Regs();
4779 Register NewOldValRes = MRI.cloneVirtualRegister(OldValRes);
4780 MIRBuilder.buildAtomicCmpXchg(NewOldValRes, Addr, CmpVal, NewVal,
4781 **MI.memoperands_begin());
4782 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, NewOldValRes, CmpVal);
4783 MIRBuilder.buildCopy(OldValRes, NewOldValRes);
4784 MI.eraseFromParent();
4785 return Legalized;
4786 }
4787 case TargetOpcode::G_LOAD:
4788 case TargetOpcode::G_SEXTLOAD:
4789 case TargetOpcode::G_ZEXTLOAD:
4790 return lowerLoad(cast<GAnyLoad>(MI));
4791 case TargetOpcode::G_STORE:
4792 return lowerStore(cast<GStore>(MI));
4793 case TargetOpcode::G_CTLZ_ZERO_POISON:
4794 case TargetOpcode::G_CTTZ_ZERO_POISON:
4795 case TargetOpcode::G_CTLZ:
4796 case TargetOpcode::G_CTTZ:
4797 case TargetOpcode::G_CTPOP:
4798 case TargetOpcode::G_CTLS:
4799 return lowerBitCount(MI);
4800 case G_UADDO: {
4801 auto [Res, CarryOut, LHS, RHS] = MI.getFirst4Regs();
4802
4803 Register NewRes = MRI.cloneVirtualRegister(Res);
4804
4805 MIRBuilder.buildAdd(NewRes, LHS, RHS);
4806 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, NewRes, RHS);
4807
4808 MIRBuilder.buildCopy(Res, NewRes);
4809
4810 MI.eraseFromParent();
4811 return Legalized;
4812 }
4813 case G_UADDE: {
4814 auto [Res, CarryOut, LHS, RHS, CarryIn] = MI.getFirst5Regs();
4815 const LLT CondTy = MRI.getType(CarryOut);
4816 const LLT Ty = MRI.getType(Res);
4817
4818 Register NewRes = MRI.cloneVirtualRegister(Res);
4819
4820 // Initial add of the two operands.
4821 auto TmpRes = MIRBuilder.buildAdd(Ty, LHS, RHS);
4822
4823 // Initial check for carry.
4824 auto Carry = MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CondTy, TmpRes, LHS);
4825
4826 // Add the sum and the carry.
4827 auto ZExtCarryIn = MIRBuilder.buildZExt(Ty, CarryIn);
4828 MIRBuilder.buildAdd(NewRes, TmpRes, ZExtCarryIn);
4829
4830 // Second check for carry. We can only carry if the initial sum is all 1s
4831 // and the carry is set, resulting in a new sum of 0.
4832 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4833 auto ResEqZero =
4834 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, NewRes, Zero);
4835 auto Carry2 = MIRBuilder.buildAnd(CondTy, ResEqZero, CarryIn);
4836 MIRBuilder.buildOr(CarryOut, Carry, Carry2);
4837
4838 MIRBuilder.buildCopy(Res, NewRes);
4839
4840 MI.eraseFromParent();
4841 return Legalized;
4842 }
4843 case G_USUBO: {
4844 auto [Res, BorrowOut, LHS, RHS] = MI.getFirst4Regs();
4845
4846 MIRBuilder.buildSub(Res, LHS, RHS);
4847 MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
4848
4849 MI.eraseFromParent();
4850 return Legalized;
4851 }
4852 case G_USUBE: {
4853 auto [Res, BorrowOut, LHS, RHS, BorrowIn] = MI.getFirst5Regs();
4854 const LLT CondTy = MRI.getType(BorrowOut);
4855 const LLT Ty = MRI.getType(Res);
4856
4857 // Initial subtract of the two operands.
4858 auto TmpRes = MIRBuilder.buildSub(Ty, LHS, RHS);
4859
4860 // Initial check for borrow.
4861 auto Borrow = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, CondTy, TmpRes, LHS);
4862
4863 // Subtract the borrow from the first subtract.
4864 auto ZExtBorrowIn = MIRBuilder.buildZExt(Ty, BorrowIn);
4865 MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
4866
4867 // Second check for borrow. We can only borrow if the initial difference is
4868 // 0 and the borrow is set, resulting in a new difference of all 1s.
4869 auto Zero = MIRBuilder.buildConstant(Ty, 0);
4870 auto TmpResEqZero =
4871 MIRBuilder.buildICmp(CmpInst::ICMP_EQ, CondTy, TmpRes, Zero);
4872 auto Borrow2 = MIRBuilder.buildAnd(CondTy, TmpResEqZero, BorrowIn);
4873 MIRBuilder.buildOr(BorrowOut, Borrow, Borrow2);
4874
4875 MI.eraseFromParent();
4876 return Legalized;
4877 }
4878 case G_UITOFP:
4879 return lowerUITOFP(MI);
4880 case G_SITOFP:
4881 return lowerSITOFP(MI);
4882 case G_FPTOUI:
4883 return lowerFPTOUI(MI);
4884 case G_FPTOSI:
4885 return lowerFPTOSI(MI);
4886 case G_FPTOUI_SAT:
4887 case G_FPTOSI_SAT:
4888 return lowerFPTOINT_SAT(MI);
4889 case G_FPEXT:
4890 return lowerFPEXT(MI);
4891 case G_FPTRUNC:
4892 return lowerFPTRUNC(MI);
4893 case G_FPOWI:
4894 return lowerFPOWI(MI);
4895 case G_FMODF:
4896 return lowerFMODF(MI);
4897 case G_SMIN:
4898 case G_SMAX:
4899 case G_UMIN:
4900 case G_UMAX:
4901 return lowerMinMax(MI);
4902 case G_SCMP:
4903 case G_UCMP:
4904 return lowerThreewayCompare(MI);
4905 case G_FCOPYSIGN:
4906 return lowerFCopySign(MI);
4907 case G_FMINNUM:
4908 case G_FMAXNUM:
4909 case G_FMINIMUMNUM:
4910 case G_FMAXIMUMNUM:
4911 return lowerFMinNumMaxNum(MI);
4912 case G_FMINIMUM:
4913 case G_FMAXIMUM:
4914 return lowerFMinimumMaximum(MI);
4915 case G_MERGE_VALUES:
4916 return lowerMergeValues(MI);
4917 case G_UNMERGE_VALUES:
4918 return lowerUnmergeValues(MI);
4919 case TargetOpcode::G_SEXT_INREG: {
4920 assert(MI.getOperand(2).isImm() && "Expected immediate");
4921 int64_t SizeInBits = MI.getOperand(2).getImm();
4922
4923 auto [DstReg, SrcReg] = MI.getFirst2Regs();
4924 LLT DstTy = MRI.getType(DstReg);
4925 Register TmpRes = MRI.createGenericVirtualRegister(DstTy);
4926
4927 auto MIBSz = MIRBuilder.buildConstant(DstTy, DstTy.getScalarSizeInBits() - SizeInBits);
4928 MIRBuilder.buildShl(TmpRes, SrcReg, MIBSz->getOperand(0));
4929 MIRBuilder.buildAShr(DstReg, TmpRes, MIBSz->getOperand(0));
4930 MI.eraseFromParent();
4931 return Legalized;
4932 }
4933 case G_EXTRACT_VECTOR_ELT:
4934 case G_INSERT_VECTOR_ELT:
4936 case G_SHUFFLE_VECTOR:
4937 return lowerShuffleVector(MI);
4938 case G_VECTOR_COMPRESS:
4939 return lowerVECTOR_COMPRESS(MI);
4940 case G_DYN_STACKALLOC:
4941 return lowerDynStackAlloc(MI);
4942 case G_INSERT_SUBVECTOR: {
4943 if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
4944 MRI.getType(MI.getOperand(2).getReg()).isScalable())
4945 return UnableToLegalize;
4946
4947 // Check that subvector is half size of main vector
4948 Register Vector = MI.getOperand(1).getReg();
4949 Register Subvector = MI.getOperand(2).getReg();
4950 auto InsertionPointImm = MI.getOperand(3).getImm();
4951
4952 LLT VectorTy = MRI.getType(Vector);
4953 LLT DstTy = MRI.getType(Subvector);
4954 // If so, -> concat(subvector, extract(half of vector))
4955 // (Operands can be either way round depending on insertion point
4956 if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
4957 bool InsertInLowHalf = InsertionPointImm == 0;
4958 auto Extract = MIRBuilder.buildExtractSubvector(
4959 DstTy, Vector,
4960 (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
4961
4962 auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
4963 auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
4964
4965 MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
4966 {LowHalf, HighHalf});
4967 MI.eraseFromParent();
4968 return Legalized;
4969 }
4970 // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
4971 else {
4972 // Extend subvector to same size as vector
4973 Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
4974 MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
4975
4976 // Calculate mask required for this shuffle
4977 SmallVector<int> Mask;
4978 for (int i = 0; i < VectorTy.getNumElements(); i++) {
4979 // If this index is within bounds, put subvector's index into mask
4980 if (i >= InsertionPointImm &&
4981 i < InsertionPointImm + DstTy.getNumElements())
4982 Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
4983 else
4984 Mask.push_back(i);
4985 }
4986
4987 // Build shuffle
4988 MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
4989 Mask);
4990 MI.eraseFromParent();
4991 return Legalized;
4992 }
4993 }
4994 case G_EXTRACT_SUBVECTOR: {
4995 Register DstReg = MI.getOperand(0).getReg();
4996 Register SrcReg = MI.getOperand(1).getReg();
4997 uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
4998
4999 LLT SrcTy = MRI.getType(SrcReg);
5000 LLT DstTy = MRI.getType(DstReg);
5001
5002 if (SrcTy.isScalable() || DstTy.isScalable())
5003 return UnableToLegalize;
5004
5005 if (SrcTy.getScalarType() != DstTy.getScalarType())
5006 return UnableToLegalize;
5007
5008 // extract_subvector = build_vector(extract_element, extract_element, ...)
5009 SmallVector<Register> ExtractedElements;
5010 for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
5011 ExtractedElements.push_back(
5013 .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
5014 ExtractionPointImm + i)
5015 .getReg(0));
5016 }
5017
5018 MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
5019 MI.eraseFromParent();
5020 return Legalized;
5021 }
5022 case G_STACKSAVE:
5023 return lowerStackSave(MI);
5024 case G_STACKRESTORE:
5025 return lowerStackRestore(MI);
5026 case G_EXTRACT:
5027 return lowerExtract(MI);
5028 case G_INSERT:
5029 return lowerInsert(MI);
5030 case G_BSWAP:
5031 return lowerBswap(MI);
5032 case G_BITREVERSE:
5033 return lowerBitreverse(MI);
5034 case G_READ_REGISTER:
5035 case G_WRITE_REGISTER:
5036 return lowerReadWriteRegister(MI);
5037 case G_UADDSAT:
5038 case G_USUBSAT: {
5039 // Try to make a reasonable guess about which lowering strategy to use. The
5040 // target can override this with custom lowering and calling the
5041 // implementation functions.
5042 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5043 if (LI.isLegalOrCustom({G_UMIN, Ty}))
5044 return lowerAddSubSatToMinMax(MI);
5046 }
5047 case G_SADDSAT:
5048 case G_SSUBSAT: {
5049 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5050
5051 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
5052 // since it's a shorter expansion. However, we would need to figure out the
5053 // preferred boolean type for the carry out for the query.
5054 if (LI.isLegalOrCustom({G_SMIN, Ty}) && LI.isLegalOrCustom({G_SMAX, Ty}))
5055 return lowerAddSubSatToMinMax(MI);
5057 }
5058 case G_SSHLSAT:
5059 case G_USHLSAT:
5060 return lowerShlSat(MI);
5061 case G_TRUNC_SSAT_S:
5062 case G_TRUNC_USAT_U:
5063 case G_TRUNC_SSAT_U:
5064 return lowerTruncSat(MI);
5065 case G_ABS:
5066 return lowerAbsToAddXor(MI);
5067 case G_ABDS:
5068 case G_ABDU: {
5069 bool IsSigned = MI.getOpcode() == G_ABDS;
5070 LLT Ty = MRI.getType(MI.getOperand(0).getReg());
5071 if ((IsSigned && LI.isLegal({G_SMIN, Ty}) && LI.isLegal({G_SMAX, Ty})) ||
5072 (!IsSigned && LI.isLegal({G_UMIN, Ty}) && LI.isLegal({G_UMAX, Ty}))) {
5073 return lowerAbsDiffToMinMax(MI);
5074 }
5075 return lowerAbsDiffToSelect(MI);
5076 }
5077 case G_FABS:
5078 return lowerFAbs(MI);
5079 case G_SELECT:
5080 return lowerSelect(MI);
5081 case G_IS_FPCLASS:
5082 return lowerISFPCLASS(MI);
5083 case G_SDIVREM:
5084 case G_UDIVREM:
5085 return lowerDIVREM(MI);
5086 case G_FSHL:
5087 case G_FSHR:
5088 return lowerFunnelShift(MI);
5089 case G_ROTL:
5090 case G_ROTR:
5091 return lowerRotate(MI);
5092 case G_MEMSET:
5093 case G_MEMCPY:
5094 case G_MEMMOVE:
5095 case G_MEMCPY_INLINE:
5096 case G_MEMSET_INLINE:
5097 return lowerMemCpyFamily(MI);
5098 case G_ZEXT:
5099 case G_SEXT:
5100 case G_ANYEXT:
5101 return lowerEXT(MI);
5102 case G_TRUNC:
5103 return lowerTRUNC(MI);
5105 return lowerVectorReduction(MI);
5106 case G_VAARG:
5107 return lowerVAArg(MI);
5108 case G_ATOMICRMW_SUB: {
5109 auto [Ret, Mem, Val] = MI.getFirst3Regs();
5110 const LLT ValTy = MRI.getType(Val);
5111 MachineMemOperand *MMO = *MI.memoperands_begin();
5112
5113 auto VNeg = MIRBuilder.buildNeg(ValTy, Val);
5114 MIRBuilder.buildAtomicRMW(G_ATOMICRMW_ADD, Ret, Mem, VNeg, *MMO);
5115 MI.eraseFromParent();
5116 return Legalized;
5117 }
5118 case G_SMULFIX:
5119 case G_UMULFIX:
5120 case G_SMULFIXSAT:
5121 case G_UMULFIXSAT:
5122 return lowerMulfix(MI);
5123 }
5124}
5125
5127 Align MinAlign) const {
5128 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
5129 // datalayout for the preferred alignment. Also there should be a target hook
5130 // for this to allow targets to reduce the alignment and ignore the
5131 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
5132 // the type.
5133 return std::max(Align(PowerOf2Ceil(Ty.getSizeInBytes())), MinAlign);
5134}
5135
5138 MachinePointerInfo &PtrInfo) {
5139 MachineFunction &MF = MIRBuilder.getMF();
5140 const DataLayout &DL = MIRBuilder.getDataLayout();
5141 int FrameIdx = MF.getFrameInfo().CreateStackObject(Bytes, Alignment, false);
5142
5143 unsigned AddrSpace = DL.getAllocaAddrSpace();
5144 LLT FramePtrTy = LLT::pointer(AddrSpace, DL.getPointerSizeInBits(AddrSpace));
5145
5146 PtrInfo = MachinePointerInfo::getFixedStack(MF, FrameIdx);
5147 return MIRBuilder.buildFrameIndex(FramePtrTy, FrameIdx);
5148}
5149
5151 const SrcOp &Val) {
5152 LLT SrcTy = Val.getLLTTy(MRI);
5153 Align StackTypeAlign =
5154 std::max(getStackTemporaryAlignment(SrcTy),
5156 MachinePointerInfo PtrInfo;
5157 auto StackTemp =
5158 createStackTemporary(SrcTy.getSizeInBytes(), StackTypeAlign, PtrInfo);
5159
5160 MIRBuilder.buildStore(Val, StackTemp, PtrInfo, StackTypeAlign);
5161 return MIRBuilder.buildLoad(Res, StackTemp, PtrInfo, StackTypeAlign);
5162}
5163
5165 LLT VecTy) {
5166 LLT IdxTy = B.getMRI()->getType(IdxReg);
5167 unsigned NElts = VecTy.getNumElements();
5168
5169 int64_t IdxVal;
5170 if (mi_match(IdxReg, *B.getMRI(), m_ICst(IdxVal))) {
5171 if (IdxVal < VecTy.getNumElements())
5172 return IdxReg;
5173 // If a constant index would be out of bounds, clamp it as well.
5174 }
5175
5176 if (isPowerOf2_32(NElts)) {
5178 return B.buildAnd(IdxTy, IdxReg, B.buildConstant(IdxTy, Imm)).getReg(0);
5179 }
5180
5181 return B.buildUMin(IdxTy, IdxReg, B.buildConstant(IdxTy, NElts - 1))
5182 .getReg(0);
5183}
5184
5186 Register Index) {
5187 LLT EltTy = VecTy.getElementType();
5188
5189 // Calculate the element offset and add it to the pointer.
5190 unsigned EltSize = EltTy.getSizeInBits() / 8; // FIXME: should be ABI size.
5191 assert(EltSize * 8 == EltTy.getSizeInBits() &&
5192 "Converting bits to bytes lost precision");
5193
5194 Index = clampVectorIndex(MIRBuilder, Index, VecTy);
5195
5196 // Convert index to the correct size for the address space.
5197 const DataLayout &DL = MIRBuilder.getDataLayout();
5198 unsigned AS = MRI.getType(VecPtr).getAddressSpace();
5199 unsigned IndexSizeInBits = DL.getIndexSize(AS) * 8;
5200 LLT IdxTy = MRI.getType(Index).changeElementSize(IndexSizeInBits);
5201 if (IdxTy != MRI.getType(Index))
5202 Index = MIRBuilder.buildSExtOrTrunc(IdxTy, Index).getReg(0);
5203
5204 auto Mul = MIRBuilder.buildMul(IdxTy, Index,
5205 MIRBuilder.buildConstant(IdxTy, EltSize));
5206
5207 LLT PtrTy = MRI.getType(VecPtr);
5208 return MIRBuilder.buildPtrAdd(PtrTy, VecPtr, Mul).getReg(0);
5209}
5210
5211#ifndef NDEBUG
5212/// Check that all vector operands have same number of elements. Other operands
5213/// should be listed in NonVecOp.
5216 std::initializer_list<unsigned> NonVecOpIndices) {
5217 if (MI.getNumMemOperands() != 0)
5218 return false;
5219
5220 LLT VecTy = MRI.getType(MI.getReg(0));
5221 if (!VecTy.isVector())
5222 return false;
5223 unsigned NumElts = VecTy.getNumElements();
5224
5225 for (unsigned OpIdx = 1; OpIdx < MI.getNumOperands(); ++OpIdx) {
5226 MachineOperand &Op = MI.getOperand(OpIdx);
5227 if (!Op.isReg()) {
5228 if (!is_contained(NonVecOpIndices, OpIdx))
5229 return false;
5230 continue;
5231 }
5232
5233 LLT Ty = MRI.getType(Op.getReg());
5234 if (!Ty.isVector()) {
5235 if (!is_contained(NonVecOpIndices, OpIdx))
5236 return false;
5237 continue;
5238 }
5239
5240 if (Ty.getNumElements() != NumElts)
5241 return false;
5242 }
5243
5244 return true;
5245}
5246#endif
5247
5248/// Fill \p DstOps with DstOps that have same number of elements combined as
5249/// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
5250/// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
5251/// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
5252static void makeDstOps(SmallVectorImpl<DstOp> &DstOps, LLT Ty,
5253 unsigned NumElts) {
5254 LLT LeftoverTy;
5255 assert(Ty.isVector() && "Expected vector type");
5256 LLT NarrowTy = Ty.changeElementCount(ElementCount::getFixed(NumElts));
5257 int NumParts, NumLeftover;
5258 std::tie(NumParts, NumLeftover) =
5259 getNarrowTypeBreakDown(Ty, NarrowTy, LeftoverTy);
5260
5261 assert(NumParts > 0 && "Error in getNarrowTypeBreakDown");
5262 for (int i = 0; i < NumParts; ++i) {
5263 DstOps.push_back(NarrowTy);
5264 }
5265
5266 if (LeftoverTy.isValid()) {
5267 assert(NumLeftover == 1 && "expected exactly one leftover");
5268 DstOps.push_back(LeftoverTy);
5269 }
5270}
5271
5272/// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
5273/// made from \p Op depending on operand type.
5275 MachineOperand &Op) {
5276 for (unsigned i = 0; i < N; ++i) {
5277 if (Op.isReg())
5278 Ops.push_back(Op.getReg());
5279 else if (Op.isImm())
5280 Ops.push_back(Op.getImm());
5281 else if (Op.isPredicate())
5282 Ops.push_back(static_cast<CmpInst::Predicate>(Op.getPredicate()));
5283 else
5284 llvm_unreachable("Unsupported type");
5285 }
5286}
5287
5288// Handle splitting vector operations which need to have the same number of
5289// elements in each type index, but each type index may have a different element
5290// type.
5291//
5292// e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
5293// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5294// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5295//
5296// Also handles some irregular breakdown cases, e.g.
5297// e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
5298// <2 x s64> = G_SHL <2 x s64>, <2 x s32>
5299// s64 = G_SHL s64, s32
5302 GenericMachineInstr &MI, unsigned NumElts,
5303 std::initializer_list<unsigned> NonVecOpIndices) {
5304 assert(hasSameNumEltsOnAllVectorOperands(MI, MRI, NonVecOpIndices) &&
5305 "Non-compatible opcode or not specified non-vector operands");
5306 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5307
5308 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5309 unsigned NumDefs = MI.getNumDefs();
5310
5311 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
5312 // Build instructions with DstOps to use instruction found by CSE directly.
5313 // CSE copies found instruction into given vreg when building with vreg dest.
5314 SmallVector<SmallVector<DstOp, 8>, 2> OutputOpsPieces(NumDefs);
5315 // Output registers will be taken from created instructions.
5316 SmallVector<SmallVector<Register, 8>, 2> OutputRegs(NumDefs);
5317 for (unsigned i = 0; i < NumDefs; ++i) {
5318 makeDstOps(OutputOpsPieces[i], MRI.getType(MI.getReg(i)), NumElts);
5319 }
5320
5321 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
5322 // Operands listed in NonVecOpIndices will be used as is without splitting;
5323 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
5324 // scalar condition (op 1), immediate in sext_inreg (op 2).
5325 SmallVector<SmallVector<SrcOp, 8>, 3> InputOpsPieces(NumInputs);
5326 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5327 ++UseIdx, ++UseNo) {
5328 if (is_contained(NonVecOpIndices, UseIdx)) {
5329 broadcastSrcOp(InputOpsPieces[UseNo], OutputOpsPieces[0].size(),
5330 MI.getOperand(UseIdx));
5331 } else {
5332 SmallVector<Register, 8> SplitPieces;
5333 extractVectorParts(MI.getReg(UseIdx), NumElts, SplitPieces, MIRBuilder,
5334 MRI);
5335 llvm::append_range(InputOpsPieces[UseNo], SplitPieces);
5336 }
5337 }
5338
5339 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5340
5341 // Take i-th piece of each input operand split and build sub-vector/scalar
5342 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
5343 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5345 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5346 Defs.push_back(OutputOpsPieces[DstNo][i]);
5347
5349 for (unsigned InputNo = 0; InputNo < NumInputs; ++InputNo)
5350 Uses.push_back(InputOpsPieces[InputNo][i]);
5351
5352 auto I = MIRBuilder.buildInstr(MI.getOpcode(), Defs, Uses, MI.getFlags());
5353 for (unsigned DstNo = 0; DstNo < NumDefs; ++DstNo)
5354 OutputRegs[DstNo].push_back(I.getReg(DstNo));
5355 }
5356
5357 // Merge small outputs into MI's output for each def operand.
5358 if (NumLeftovers) {
5359 for (unsigned i = 0; i < NumDefs; ++i)
5360 mergeMixedSubvectors(MI.getReg(i), OutputRegs[i]);
5361 } else {
5362 for (unsigned i = 0; i < NumDefs; ++i)
5363 MIRBuilder.buildMergeLikeInstr(MI.getReg(i), OutputRegs[i]);
5364 }
5365
5366 MI.eraseFromParent();
5367 return Legalized;
5368}
5369
5372 unsigned NumElts) {
5373 unsigned OrigNumElts = MRI.getType(MI.getReg(0)).getNumElements();
5374
5375 unsigned NumInputs = MI.getNumOperands() - MI.getNumDefs();
5376 unsigned NumDefs = MI.getNumDefs();
5377
5378 SmallVector<DstOp, 8> OutputOpsPieces;
5379 SmallVector<Register, 8> OutputRegs;
5380 makeDstOps(OutputOpsPieces, MRI.getType(MI.getReg(0)), NumElts);
5381
5382 // Instructions that perform register split will be inserted in basic block
5383 // where register is defined (basic block is in the next operand).
5384 SmallVector<SmallVector<Register, 8>, 3> InputOpsPieces(NumInputs / 2);
5385 for (unsigned UseIdx = NumDefs, UseNo = 0; UseIdx < MI.getNumOperands();
5386 UseIdx += 2, ++UseNo) {
5387 MachineBasicBlock &OpMBB = *MI.getOperand(UseIdx + 1).getMBB();
5388 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminatorForward());
5389 extractVectorParts(MI.getReg(UseIdx), NumElts, InputOpsPieces[UseNo],
5390 MIRBuilder, MRI);
5391 }
5392
5393 // Build PHIs with fewer elements.
5394 unsigned NumLeftovers = OrigNumElts % NumElts ? 1 : 0;
5395 MIRBuilder.setInsertPt(*MI.getParent(), MI);
5396 for (unsigned i = 0; i < OrigNumElts / NumElts + NumLeftovers; ++i) {
5397 auto Phi = MIRBuilder.buildInstr(TargetOpcode::G_PHI);
5398 Phi.addDef(
5399 MRI.createGenericVirtualRegister(OutputOpsPieces[i].getLLTTy(MRI)));
5400 OutputRegs.push_back(Phi.getReg(0));
5401
5402 for (unsigned j = 0; j < NumInputs / 2; ++j) {
5403 Phi.addUse(InputOpsPieces[j][i]);
5404 Phi.add(MI.getOperand(1 + j * 2 + 1));
5405 }
5406 }
5407
5408 // Set the insert point after the existing PHIs
5409 MachineBasicBlock &MBB = *MI.getParent();
5410 MIRBuilder.setInsertPt(MBB, MBB.getFirstNonPHI());
5411
5412 // Merge small outputs into MI's def.
5413 if (NumLeftovers) {
5414 mergeMixedSubvectors(MI.getReg(0), OutputRegs);
5415 } else {
5416 MIRBuilder.buildMergeLikeInstr(MI.getReg(0), OutputRegs);
5417 }
5418
5419 MI.eraseFromParent();
5420 return Legalized;
5421}
5422
5425 unsigned TypeIdx,
5426 LLT NarrowTy) {
5427 const int NumDst = MI.getNumOperands() - 1;
5428 const Register SrcReg = MI.getOperand(NumDst).getReg();
5429 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
5430 LLT SrcTy = MRI.getType(SrcReg);
5431
5432 if (TypeIdx != 1 || NarrowTy == DstTy)
5433 return UnableToLegalize;
5434
5435 // Requires compatible types. Otherwise SrcReg should have been defined by
5436 // merge-like instruction that would get artifact combined. Most likely
5437 // instruction that defines SrcReg has to perform more/fewer elements
5438 // legalization compatible with NarrowTy.
5439 assert(SrcTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5440 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5441
5442 if ((SrcTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5443 (NarrowTy.getSizeInBits() % DstTy.getSizeInBits() != 0))
5444 return UnableToLegalize;
5445
5446 // This is most likely DstTy (smaller then register size) packed in SrcTy
5447 // (larger then register size) and since unmerge was not combined it will be
5448 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5449 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5450
5451 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5452 //
5453 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5454 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5455 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5456 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5457 const int NumUnmerge = Unmerge->getNumOperands() - 1;
5458 const int PartsPerUnmerge = NumDst / NumUnmerge;
5459
5460 for (int I = 0; I != NumUnmerge; ++I) {
5461 auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_UNMERGE_VALUES);
5462
5463 for (int J = 0; J != PartsPerUnmerge; ++J)
5464 MIB.addDef(MI.getOperand(I * PartsPerUnmerge + J).getReg());
5465 MIB.addUse(Unmerge.getReg(I));
5466 }
5467
5468 MI.eraseFromParent();
5469 return Legalized;
5470}
5471
5474 LLT NarrowTy) {
5475 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5476 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5477 // that should have been artifact combined. Most likely instruction that uses
5478 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5479 assert(DstTy.isVector() && NarrowTy.isVector() && "Expected vector types");
5480 assert((DstTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5481 if (NarrowTy == SrcTy)
5482 return UnableToLegalize;
5483
5484 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5485 // is for old mir tests. Since the changes to more/fewer elements it should no
5486 // longer be possible to generate MIR like this when starting from llvm-ir
5487 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5488 if (TypeIdx == 1) {
5489 assert(SrcTy.isVector() && "Expected vector types");
5490 assert((SrcTy.getScalarType() == NarrowTy.getScalarType()) && "bad type");
5491 if ((DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0) ||
5492 (NarrowTy.getNumElements() >= SrcTy.getNumElements()))
5493 return UnableToLegalize;
5494 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5495 //
5496 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5497 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5498 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5499 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5500 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5501 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5502
5504 LLT EltTy = MRI.getType(MI.getOperand(1).getReg()).getScalarType();
5505 for (unsigned i = 1; i < MI.getNumOperands(); ++i) {
5506 auto Unmerge = MIRBuilder.buildUnmerge(EltTy, MI.getOperand(i).getReg());
5507 for (unsigned j = 0; j < Unmerge->getNumDefs(); ++j)
5508 Elts.push_back(Unmerge.getReg(j));
5509 }
5510
5511 SmallVector<Register, 8> NarrowTyElts;
5512 unsigned NumNarrowTyElts = NarrowTy.getNumElements();
5513 unsigned NumNarrowTyPieces = DstTy.getNumElements() / NumNarrowTyElts;
5514 for (unsigned i = 0, Offset = 0; i < NumNarrowTyPieces;
5515 ++i, Offset += NumNarrowTyElts) {
5516 ArrayRef<Register> Pieces(&Elts[Offset], NumNarrowTyElts);
5517 NarrowTyElts.push_back(
5518 MIRBuilder.buildMergeLikeInstr(NarrowTy, Pieces).getReg(0));
5519 }
5520
5521 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5522 MI.eraseFromParent();
5523 return Legalized;
5524 }
5525
5526 assert(TypeIdx == 0 && "Bad type index");
5527 if ((NarrowTy.getSizeInBits() % SrcTy.getSizeInBits() != 0) ||
5528 (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0))
5529 return UnableToLegalize;
5530
5531 // This is most likely SrcTy (smaller then register size) packed in DstTy
5532 // (larger then register size) and since merge was not combined it will be
5533 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5534 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5535
5536 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5537 //
5538 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5539 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5540 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5541 SmallVector<Register, 8> NarrowTyElts;
5542 unsigned NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
5543 unsigned NumSrcElts = SrcTy.isVector() ? SrcTy.getNumElements() : 1;
5544 unsigned NumElts = NarrowTy.getNumElements() / NumSrcElts;
5545 for (unsigned i = 0; i < NumParts; ++i) {
5547 for (unsigned j = 0; j < NumElts; ++j)
5548 Sources.push_back(MI.getOperand(1 + i * NumElts + j).getReg());
5549 NarrowTyElts.push_back(
5550 MIRBuilder.buildMergeLikeInstr(NarrowTy, Sources).getReg(0));
5551 }
5552
5553 MIRBuilder.buildMergeLikeInstr(DstReg, NarrowTyElts);
5554 MI.eraseFromParent();
5555 return Legalized;
5556}
5557
5560 unsigned TypeIdx,
5561 LLT NarrowVecTy) {
5562 auto [DstReg, SrcVec] = MI.getFirst2Regs();
5563 Register InsertVal;
5564 bool IsInsert = MI.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
5565
5566 assert((IsInsert ? TypeIdx == 0 : TypeIdx == 1) && "not a vector type index");
5567 if (IsInsert)
5568 InsertVal = MI.getOperand(2).getReg();
5569
5570 Register Idx = MI.getOperand(MI.getNumOperands() - 1).getReg();
5571 LLT VecTy = MRI.getType(SrcVec);
5572
5573 // If the index is a constant, we can really break this down as you would
5574 // expect, and index into the target size pieces.
5575 auto MaybeCst = getIConstantVRegValWithLookThrough(Idx, MRI);
5576 if (MaybeCst) {
5577 uint64_t IdxVal = MaybeCst->Value.getZExtValue();
5578 // Avoid out of bounds indexing the pieces.
5579 if (IdxVal >= VecTy.getNumElements()) {
5580 MIRBuilder.buildUndef(DstReg);
5581 MI.eraseFromParent();
5582 return Legalized;
5583 }
5584
5585 if (!NarrowVecTy.isVector()) {
5586 SmallVector<Register, 8> SplitPieces;
5587 extractParts(MI.getOperand(1).getReg(), NarrowVecTy,
5588 VecTy.getNumElements(), SplitPieces, MIRBuilder, MRI);
5589 if (IsInsert) {
5590 SplitPieces[IdxVal] = InsertVal;
5591 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0).getReg(), SplitPieces);
5592 } else {
5593 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), SplitPieces[IdxVal]);
5594 }
5595 } else {
5596 SmallVector<Register, 8> VecParts;
5597 LLT GCDTy = extractGCDType(VecParts, VecTy, NarrowVecTy, SrcVec);
5598
5599 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5600 LLT LCMTy = buildLCMMergePieces(VecTy, NarrowVecTy, GCDTy, VecParts,
5601 TargetOpcode::G_ANYEXT);
5602
5603 unsigned NewNumElts = NarrowVecTy.getNumElements();
5604
5605 LLT IdxTy = MRI.getType(Idx);
5606 int64_t PartIdx = IdxVal / NewNumElts;
5607 auto NewIdx =
5608 MIRBuilder.buildConstant(IdxTy, IdxVal - NewNumElts * PartIdx);
5609
5610 if (IsInsert) {
5611 LLT PartTy = MRI.getType(VecParts[PartIdx]);
5612
5613 // Use the adjusted index to insert into one of the subvectors.
5614 auto InsertPart = MIRBuilder.buildInsertVectorElement(
5615 PartTy, VecParts[PartIdx], InsertVal, NewIdx);
5616 VecParts[PartIdx] = InsertPart.getReg(0);
5617
5618 // Recombine the inserted subvector with the others to reform the result
5619 // vector.
5620 buildWidenedRemergeToDst(DstReg, LCMTy, VecParts);
5621 } else {
5622 MIRBuilder.buildExtractVectorElement(DstReg, VecParts[PartIdx], NewIdx);
5623 }
5624 }
5625
5626 MI.eraseFromParent();
5627 return Legalized;
5628 }
5629
5630 // With a variable index, we can't perform the operation in a smaller type, so
5631 // we're forced to expand this.
5632 //
5633 // TODO: We could emit a chain of compare/select to figure out which piece to
5634 // index.
5636}
5637
5640 LLT NarrowTy) {
5641 // FIXME: Don't know how to handle secondary types yet.
5642 if (TypeIdx != 0)
5643 return UnableToLegalize;
5644
5645 if (!NarrowTy.isByteSized()) {
5646 LLVM_DEBUG(dbgs() << "Can't narrow load/store to non-byte-sized type\n");
5647 return UnableToLegalize;
5648 }
5649
5650 // This implementation doesn't work for atomics. Give up instead of doing
5651 // something invalid.
5652 if (LdStMI.isAtomic())
5653 return UnableToLegalize;
5654
5655 bool IsLoad = isa<GLoad>(LdStMI);
5656 Register ValReg = LdStMI.getReg(0);
5657 Register AddrReg = LdStMI.getPointerReg();
5658 LLT ValTy = MRI.getType(ValReg);
5659
5660 // FIXME: Do we need a distinct NarrowMemory legalize action?
5661 if (ValTy.getSizeInBits() != 8 * LdStMI.getMemSize().getValue()) {
5662 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5663 return UnableToLegalize;
5664 }
5665
5666 int NumParts = -1;
5667 int NumLeftover = -1;
5668 LLT LeftoverTy;
5669 SmallVector<Register, 8> NarrowRegs, NarrowLeftoverRegs;
5670 if (IsLoad) {
5671 std::tie(NumParts, NumLeftover) = getNarrowTypeBreakDown(ValTy, NarrowTy, LeftoverTy);
5672 } else {
5673 if (extractParts(ValReg, ValTy, NarrowTy, LeftoverTy, NarrowRegs,
5674 NarrowLeftoverRegs, MIRBuilder, MRI)) {
5675 NumParts = NarrowRegs.size();
5676 NumLeftover = NarrowLeftoverRegs.size();
5677 }
5678 }
5679
5680 if (NumParts == -1)
5681 return UnableToLegalize;
5682
5683 LLT PtrTy = MRI.getType(AddrReg);
5684 const LLT OffsetTy = LLT::integer(PtrTy.getSizeInBits());
5685
5686 unsigned TotalSize = ValTy.getSizeInBits();
5687
5688 // Split the load/store into PartTy sized pieces starting at Offset. If this
5689 // is a load, return the new registers in ValRegs. For a store, each elements
5690 // of ValRegs should be PartTy. Returns the next offset that needs to be
5691 // handled.
5692 bool isBigEndian = MIRBuilder.getDataLayout().isBigEndian();
5693 auto MMO = LdStMI.getMMO();
5694 auto splitTypePieces = [=](LLT PartTy, SmallVectorImpl<Register> &ValRegs,
5695 unsigned NumParts, unsigned Offset) -> unsigned {
5696 MachineFunction &MF = MIRBuilder.getMF();
5697 unsigned PartSize = PartTy.getSizeInBits();
5698 for (unsigned Idx = 0, E = NumParts; Idx != E && Offset < TotalSize;
5699 ++Idx) {
5700 unsigned ByteOffset = Offset / 8;
5701 Register NewAddrReg;
5702
5703 MIRBuilder.materializeObjectPtrOffset(NewAddrReg, AddrReg, OffsetTy,
5704 ByteOffset);
5705
5706 MachineMemOperand *NewMMO =
5707 MF.getMachineMemOperand(&MMO, ByteOffset, PartTy);
5708
5709 if (IsLoad) {
5710 Register Dst = MRI.createGenericVirtualRegister(PartTy);
5711 ValRegs.push_back(Dst);
5712 MIRBuilder.buildLoad(Dst, NewAddrReg, *NewMMO);
5713 } else {
5714 MIRBuilder.buildStore(ValRegs[Idx], NewAddrReg, *NewMMO);
5715 }
5716 Offset = isBigEndian ? Offset - PartSize : Offset + PartSize;
5717 }
5718
5719 return Offset;
5720 };
5721
5722 unsigned Offset = isBigEndian ? TotalSize - NarrowTy.getSizeInBits() : 0;
5723 unsigned HandledOffset =
5724 splitTypePieces(NarrowTy, NarrowRegs, NumParts, Offset);
5725
5726 // Handle the rest of the register if this isn't an even type breakdown.
5727 if (LeftoverTy.isValid())
5728 splitTypePieces(LeftoverTy, NarrowLeftoverRegs, NumLeftover, HandledOffset);
5729
5730 if (IsLoad) {
5731 insertParts(ValReg, ValTy, NarrowTy, NarrowRegs,
5732 LeftoverTy, NarrowLeftoverRegs);
5733 }
5734
5735 LdStMI.eraseFromParent();
5736 return Legalized;
5737}
5738
5741 LLT NarrowTy) {
5742 using namespace TargetOpcode;
5744 unsigned NumElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
5745
5746 switch (MI.getOpcode()) {
5747 case G_IMPLICIT_DEF:
5748 case G_TRUNC:
5749 case G_AND:
5750 case G_OR:
5751 case G_XOR:
5752 case G_ADD:
5753 case G_SUB:
5754 case G_MUL:
5755 case G_PTR_ADD:
5756 case G_SMULH:
5757 case G_UMULH:
5758 case G_FADD:
5759 case G_FMUL:
5760 case G_FSUB:
5761 case G_FNEG:
5762 case G_FABS:
5763 case G_FCANONICALIZE:
5764 case G_FDIV:
5765 case G_FREM:
5766 case G_FMA:
5767 case G_FMAD:
5768 case G_FPOW:
5769 case G_FEXP:
5770 case G_FEXP2:
5771 case G_FEXP10:
5772 case G_FLOG:
5773 case G_FLOG2:
5774 case G_FLOG10:
5775 case G_FLDEXP:
5776 case G_FNEARBYINT:
5777 case G_FCEIL:
5778 case G_FFLOOR:
5779 case G_FRINT:
5780 case G_INTRINSIC_LRINT:
5781 case G_INTRINSIC_LLRINT:
5782 case G_INTRINSIC_ROUND:
5783 case G_INTRINSIC_ROUNDEVEN:
5784 case G_LROUND:
5785 case G_LLROUND:
5786 case G_INTRINSIC_TRUNC:
5787 case G_FMODF:
5788 case G_FCOS:
5789 case G_FSIN:
5790 case G_FTAN:
5791 case G_FACOS:
5792 case G_FASIN:
5793 case G_FATAN:
5794 case G_FATAN2:
5795 case G_FCOSH:
5796 case G_FSINH:
5797 case G_FTANH:
5798 case G_FSQRT:
5799 case G_BSWAP:
5800 case G_BITREVERSE:
5801 case G_SDIV:
5802 case G_UDIV:
5803 case G_SREM:
5804 case G_UREM:
5805 case G_SDIVREM:
5806 case G_UDIVREM:
5807 case G_SMIN:
5808 case G_SMAX:
5809 case G_UMIN:
5810 case G_UMAX:
5811 case G_ABS:
5812 case G_FMINNUM:
5813 case G_FMAXNUM:
5814 case G_FMINNUM_IEEE:
5815 case G_FMAXNUM_IEEE:
5816 case G_FMINIMUM:
5817 case G_FMAXIMUM:
5818 case G_FMINIMUMNUM:
5819 case G_FMAXIMUMNUM:
5820 case G_FSHL:
5821 case G_FSHR:
5822 case G_ROTL:
5823 case G_ROTR:
5824 case G_FREEZE:
5825 case G_SADDSAT:
5826 case G_SSUBSAT:
5827 case G_UADDSAT:
5828 case G_USUBSAT:
5829 case G_UMULO:
5830 case G_SMULO:
5831 case G_SHL:
5832 case G_LSHR:
5833 case G_ASHR:
5834 case G_SSHLSAT:
5835 case G_USHLSAT:
5836 case G_CTLZ:
5837 case G_CTLZ_ZERO_POISON:
5838 case G_CTTZ:
5839 case G_CTTZ_ZERO_POISON:
5840 case G_CTPOP:
5841 case G_CTLS:
5842 case G_FCOPYSIGN:
5843 case G_ZEXT:
5844 case G_SEXT:
5845 case G_ANYEXT:
5846 case G_FPEXT:
5847 case G_FPTRUNC:
5848 case G_SITOFP:
5849 case G_UITOFP:
5850 case G_FPTOSI:
5851 case G_FPTOUI:
5852 case G_FPTOSI_SAT:
5853 case G_FPTOUI_SAT:
5854 case G_INTTOPTR:
5855 case G_PTRTOINT:
5856 case G_ADDRSPACE_CAST:
5857 case G_UADDO:
5858 case G_USUBO:
5859 case G_UADDE:
5860 case G_USUBE:
5861 case G_SADDO:
5862 case G_SSUBO:
5863 case G_SADDE:
5864 case G_SSUBE:
5865 case G_STRICT_FADD:
5866 case G_STRICT_FSUB:
5867 case G_STRICT_FMUL:
5868 case G_STRICT_FMA:
5869 case G_STRICT_FLDEXP:
5870 case G_FFREXP:
5871 case G_TRUNC_SSAT_S:
5872 case G_TRUNC_SSAT_U:
5873 case G_TRUNC_USAT_U:
5874 return fewerElementsVectorMultiEltType(GMI, NumElts);
5875 case G_ICMP:
5876 case G_FCMP:
5877 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*cpm predicate*/});
5878 case G_IS_FPCLASS:
5879 return fewerElementsVectorMultiEltType(GMI, NumElts, {2, 3 /*mask,fpsem*/});
5880 case G_SELECT:
5881 if (MRI.getType(MI.getOperand(1).getReg()).isVector())
5882 return fewerElementsVectorMultiEltType(GMI, NumElts);
5883 return fewerElementsVectorMultiEltType(GMI, NumElts, {1 /*scalar cond*/});
5884 case G_PHI:
5885 return fewerElementsVectorPhi(GMI, NumElts);
5886 case G_UNMERGE_VALUES:
5887 return fewerElementsVectorUnmergeValues(MI, TypeIdx, NarrowTy);
5888 case G_BUILD_VECTOR:
5889 assert(TypeIdx == 0 && "not a vector type index");
5890 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5891 case G_CONCAT_VECTORS:
5892 if (TypeIdx != 1) // TODO: This probably does work as expected already.
5893 return UnableToLegalize;
5894 return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
5895 case G_EXTRACT_SUBVECTOR: {
5896 Register DstReg = MI.getOperand(0).getReg();
5897 LLT DstTy = MRI.getType(DstReg);
5898 Register SrcReg = MI.getOperand(1).getReg();
5899 uint64_t InsertionPointImm = MI.getOperand(2).getImm();
5900
5901 // If Dst > NarrowTy bits, then cannot legalize
5902 if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
5903 return UnableToLegalize;
5904
5905 // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
5906 if (!DstTy.getElementCount().isKnownMultipleOf(NarrowTy.getElementCount()))
5907 return UnableToLegalize;
5908
5909 auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
5910 uint64_t RequiredSubvectorIndex =
5911 InsertionPointImm / NarrowTy.getNumElements();
5912 // If Dst and Narrow are both same size, convert to a copy
5913 if (DstTy.getNumElements() == NarrowTy.getNumElements())
5914 MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
5915 else
5916 MIRBuilder.buildExtractSubvector(
5917 DstReg, Unmerge.getReg(RequiredSubvectorIndex),
5918 InsertionPointImm % NarrowTy.getNumElements());
5919
5920 MI.eraseFromParent();
5921 return Legalized;
5922 }
5923 case G_EXTRACT_VECTOR_ELT:
5924 case G_INSERT_VECTOR_ELT:
5925 return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
5926 case G_LOAD:
5927 case G_STORE:
5928 return reduceLoadStoreWidth(cast<GLoadStore>(MI), TypeIdx, NarrowTy);
5929 case G_SEXT_INREG:
5930 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*imm*/});
5932 return fewerElementsVectorReductions(MI, TypeIdx, NarrowTy);
5933 case TargetOpcode::G_VECREDUCE_SEQ_FADD:
5934 case TargetOpcode::G_VECREDUCE_SEQ_FMUL:
5935 return fewerElementsVectorSeqReductions(MI, TypeIdx, NarrowTy);
5936 case G_SHUFFLE_VECTOR:
5937 return fewerElementsVectorShuffle(MI, TypeIdx, NarrowTy);
5938 case G_FPOWI:
5939 return fewerElementsVectorMultiEltType(GMI, NumElts, {2 /*pow*/});
5940 case G_BITCAST:
5941 return fewerElementsBitcast(MI, TypeIdx, NarrowTy);
5942 case G_INTRINSIC_FPTRUNC_ROUND:
5943 return fewerElementsVectorMultiEltType(GMI, NumElts, {2});
5944 default:
5945 return UnableToLegalize;
5946 }
5947}
5948
5951 LLT NarrowTy) {
5952 assert(MI.getOpcode() == TargetOpcode::G_BITCAST &&
5953 "Not a bitcast operation");
5954
5955 if (TypeIdx != 0)
5956 return UnableToLegalize;
5957
5958 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
5959
5960 unsigned NewElemCount =
5961 NarrowTy.getSizeInBits() / SrcTy.getScalarSizeInBits();
5962 SmallVector<Register> SrcVRegs, BitcastVRegs;
5963 if (NewElemCount == 1) {
5964 LLT SrcNarrowTy = SrcTy.getElementType();
5965
5966 auto Unmerge = MIRBuilder.buildUnmerge(SrcNarrowTy, SrcReg);
5967 getUnmergeResults(SrcVRegs, *Unmerge);
5968 } else {
5969 LLT SrcNarrowTy =
5971
5972 // Split the Src and Dst Reg into smaller registers
5973 if (extractGCDType(SrcVRegs, DstTy, SrcNarrowTy, SrcReg) != SrcNarrowTy)
5974 return UnableToLegalize;
5975 }
5976
5977 // Build new smaller bitcast instructions
5978 // Not supporting Leftover types for now but will have to
5979 for (Register Reg : SrcVRegs)
5980 BitcastVRegs.push_back(MIRBuilder.buildBitcast(NarrowTy, Reg).getReg(0));
5981
5982 MIRBuilder.buildMergeLikeInstr(DstReg, BitcastVRegs);
5983 MI.eraseFromParent();
5984 return Legalized;
5985}
5986
5988 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
5989 assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR);
5990 if (TypeIdx != 0)
5991 return UnableToLegalize;
5992
5993 auto [DstReg, DstTy, Src1Reg, Src1Ty, Src2Reg, Src2Ty] =
5994 MI.getFirst3RegLLTs();
5995 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
5996 // The shuffle should be canonicalized by now.
5997 if (DstTy != Src1Ty)
5998 return UnableToLegalize;
5999 if (DstTy != Src2Ty)
6000 return UnableToLegalize;
6001
6002 if (!isPowerOf2_32(DstTy.getNumElements()))
6003 return UnableToLegalize;
6004
6005 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
6006 // Further legalization attempts will be needed to do split further.
6007 NarrowTy =
6008 DstTy.changeElementCount(DstTy.getElementCount().divideCoefficientBy(2));
6009 unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
6010
6011 SmallVector<Register> SplitSrc1Regs, SplitSrc2Regs;
6012 extractParts(Src1Reg, NarrowTy, 2, SplitSrc1Regs, MIRBuilder, MRI);
6013 extractParts(Src2Reg, NarrowTy, 2, SplitSrc2Regs, MIRBuilder, MRI);
6014 Register Inputs[4] = {SplitSrc1Regs[0], SplitSrc1Regs[1], SplitSrc2Regs[0],
6015 SplitSrc2Regs[1]};
6016
6017 Register Hi, Lo;
6018
6019 // If Lo or Hi uses elements from at most two of the four input vectors, then
6020 // express it as a vector shuffle of those two inputs. Otherwise extract the
6021 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
6023 for (unsigned High = 0; High < 2; ++High) {
6024 Register &Output = High ? Hi : Lo;
6025
6026 // Build a shuffle mask for the output, discovering on the fly which
6027 // input vectors to use as shuffle operands (recorded in InputUsed).
6028 // If building a suitable shuffle vector proves too hard, then bail
6029 // out with useBuildVector set.
6030 unsigned InputUsed[2] = {-1U, -1U}; // Not yet discovered.
6031 unsigned FirstMaskIdx = High * NewElts;
6032 bool UseBuildVector = false;
6033 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6034 // The mask element. This indexes into the input.
6035 int Idx = Mask[FirstMaskIdx + MaskOffset];
6036
6037 // The input vector this mask element indexes into.
6038 unsigned Input = (unsigned)Idx / NewElts;
6039
6040 if (Input >= std::size(Inputs)) {
6041 // The mask element does not index into any input vector.
6042 Ops.push_back(-1);
6043 continue;
6044 }
6045
6046 // Turn the index into an offset from the start of the input vector.
6047 Idx -= Input * NewElts;
6048
6049 // Find or create a shuffle vector operand to hold this input.
6050 unsigned OpNo;
6051 for (OpNo = 0; OpNo < std::size(InputUsed); ++OpNo) {
6052 if (InputUsed[OpNo] == Input) {
6053 // This input vector is already an operand.
6054 break;
6055 } else if (InputUsed[OpNo] == -1U) {
6056 // Create a new operand for this input vector.
6057 InputUsed[OpNo] = Input;
6058 break;
6059 }
6060 }
6061
6062 if (OpNo >= std::size(InputUsed)) {
6063 // More than two input vectors used! Give up on trying to create a
6064 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
6065 UseBuildVector = true;
6066 break;
6067 }
6068
6069 // Add the mask index for the new shuffle vector.
6070 Ops.push_back(Idx + OpNo * NewElts);
6071 }
6072
6073 if (UseBuildVector) {
6074 LLT EltTy = NarrowTy.getElementType();
6076
6077 // Extract the input elements by hand.
6078 for (unsigned MaskOffset = 0; MaskOffset < NewElts; ++MaskOffset) {
6079 // The mask element. This indexes into the input.
6080 int Idx = Mask[FirstMaskIdx + MaskOffset];
6081
6082 // The input vector this mask element indexes into.
6083 unsigned Input = (unsigned)Idx / NewElts;
6084
6085 if (Input >= std::size(Inputs)) {
6086 // The mask element is "undef" or indexes off the end of the input.
6087 SVOps.push_back(MIRBuilder.buildUndef(EltTy).getReg(0));
6088 continue;
6089 }
6090
6091 // Turn the index into an offset from the start of the input vector.
6092 Idx -= Input * NewElts;
6093
6094 // Extract the vector element by hand.
6095 SVOps.push_back(MIRBuilder
6096 .buildExtractVectorElement(
6097 EltTy, Inputs[Input],
6098 MIRBuilder.buildConstant(LLT::integer(32), Idx))
6099 .getReg(0));
6100 }
6101
6102 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
6103 Output = MIRBuilder.buildBuildVector(NarrowTy, SVOps).getReg(0);
6104 } else if (InputUsed[0] == -1U) {
6105 // No input vectors were used! The result is undefined.
6106 Output = MIRBuilder.buildUndef(NarrowTy).getReg(0);
6107 } else if (NewElts == 1) {
6108 Output = MIRBuilder.buildCopy(NarrowTy, Inputs[InputUsed[0]]).getReg(0);
6109 } else {
6110 Register Op0 = Inputs[InputUsed[0]];
6111 // If only one input was used, use an undefined vector for the other.
6112 Register Op1 = InputUsed[1] == -1U
6113 ? MIRBuilder.buildUndef(NarrowTy).getReg(0)
6114 : Inputs[InputUsed[1]];
6115 // At least one input vector was used. Create a new shuffle vector.
6116 Output = MIRBuilder.buildShuffleVector(NarrowTy, Op0, Op1, Ops).getReg(0);
6117 }
6118
6119 Ops.clear();
6120 }
6121
6122 MIRBuilder.buildMergeLikeInstr(DstReg, {Lo, Hi});
6123 MI.eraseFromParent();
6124 return Legalized;
6125}
6126
6128 MachineInstr &MI, unsigned int TypeIdx, LLT NarrowTy) {
6129 auto &RdxMI = cast<GVecReduce>(MI);
6130
6131 if (TypeIdx != 1)
6132 return UnableToLegalize;
6133
6134 // The semantics of the normal non-sequential reductions allow us to freely
6135 // re-associate the operation.
6136 auto [DstReg, DstTy, SrcReg, SrcTy] = RdxMI.getFirst2RegLLTs();
6137
6138 if (NarrowTy.isVector() &&
6139 (SrcTy.getNumElements() % NarrowTy.getNumElements() != 0))
6140 return UnableToLegalize;
6141
6142 unsigned ScalarOpc = RdxMI.getScalarOpcForReduction();
6143 SmallVector<Register> SplitSrcs;
6144 // If NarrowTy is a scalar then we're being asked to scalarize.
6145 const unsigned NumParts =
6146 NarrowTy.isVector() ? SrcTy.getNumElements() / NarrowTy.getNumElements()
6147 : SrcTy.getNumElements();
6148
6149 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6150 if (NarrowTy.isScalar()) {
6151 if (DstTy != NarrowTy)
6152 return UnableToLegalize; // FIXME: handle implicit extensions.
6153
6154 if (isPowerOf2_32(NumParts)) {
6155 // Generate a tree of scalar operations to reduce the critical path.
6156 SmallVector<Register> PartialResults;
6157 unsigned NumPartsLeft = NumParts;
6158 while (NumPartsLeft > 1) {
6159 for (unsigned Idx = 0; Idx < NumPartsLeft - 1; Idx += 2) {
6160 PartialResults.emplace_back(
6162 .buildInstr(ScalarOpc, {NarrowTy},
6163 {SplitSrcs[Idx], SplitSrcs[Idx + 1]})
6164 .getReg(0));
6165 }
6166 SplitSrcs = PartialResults;
6167 PartialResults.clear();
6168 NumPartsLeft = SplitSrcs.size();
6169 }
6170 assert(SplitSrcs.size() == 1);
6171 MIRBuilder.buildCopy(DstReg, SplitSrcs[0]);
6172 MI.eraseFromParent();
6173 return Legalized;
6174 }
6175 // If we can't generate a tree, then just do sequential operations.
6176 Register Acc = SplitSrcs[0];
6177 for (unsigned Idx = 1; Idx < NumParts; ++Idx)
6178 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[Idx]})
6179 .getReg(0);
6180 MIRBuilder.buildCopy(DstReg, Acc);
6181 MI.eraseFromParent();
6182 return Legalized;
6183 }
6184 SmallVector<Register> PartialReductions;
6185 for (unsigned Part = 0; Part < NumParts; ++Part) {
6186 PartialReductions.push_back(
6187 MIRBuilder.buildInstr(RdxMI.getOpcode(), {DstTy}, {SplitSrcs[Part]})
6188 .getReg(0));
6189 }
6190
6191 // If the types involved are powers of 2, we can generate intermediate vector
6192 // ops, before generating a final reduction operation.
6193 if (isPowerOf2_32(SrcTy.getNumElements()) &&
6194 isPowerOf2_32(NarrowTy.getNumElements())) {
6195 return tryNarrowPow2Reduction(MI, SrcReg, SrcTy, NarrowTy, ScalarOpc);
6196 }
6197
6198 Register Acc = PartialReductions[0];
6199 for (unsigned Part = 1; Part < NumParts; ++Part) {
6200 if (Part == NumParts - 1) {
6201 MIRBuilder.buildInstr(ScalarOpc, {DstReg},
6202 {Acc, PartialReductions[Part]});
6203 } else {
6204 Acc = MIRBuilder
6205 .buildInstr(ScalarOpc, {DstTy}, {Acc, PartialReductions[Part]})
6206 .getReg(0);
6207 }
6208 }
6209 MI.eraseFromParent();
6210 return Legalized;
6211}
6212
6215 unsigned int TypeIdx,
6216 LLT NarrowTy) {
6217 auto [DstReg, DstTy, ScalarReg, ScalarTy, SrcReg, SrcTy] =
6218 MI.getFirst3RegLLTs();
6219 if (!NarrowTy.isScalar() || TypeIdx != 2 || DstTy != ScalarTy ||
6220 DstTy != NarrowTy)
6221 return UnableToLegalize;
6222
6223 assert((MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD ||
6224 MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL) &&
6225 "Unexpected vecreduce opcode");
6226 unsigned ScalarOpc = MI.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
6227 ? TargetOpcode::G_FADD
6228 : TargetOpcode::G_FMUL;
6229
6230 SmallVector<Register> SplitSrcs;
6231 unsigned NumParts = SrcTy.getNumElements();
6232 extractParts(SrcReg, NarrowTy, NumParts, SplitSrcs, MIRBuilder, MRI);
6233 Register Acc = ScalarReg;
6234 for (unsigned i = 0; i < NumParts; i++)
6235 Acc = MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {Acc, SplitSrcs[i]})
6236 .getReg(0);
6237
6238 MIRBuilder.buildCopy(DstReg, Acc);
6239 MI.eraseFromParent();
6240 return Legalized;
6241}
6242
6244LegalizerHelper::tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
6245 LLT SrcTy, LLT NarrowTy,
6246 unsigned ScalarOpc) {
6247 SmallVector<Register> SplitSrcs;
6248 // Split the sources into NarrowTy size pieces.
6249 extractParts(SrcReg, NarrowTy,
6250 SrcTy.getNumElements() / NarrowTy.getNumElements(), SplitSrcs,
6251 MIRBuilder, MRI);
6252 // We're going to do a tree reduction using vector operations until we have
6253 // one NarrowTy size value left.
6254 while (SplitSrcs.size() > 1) {
6255 SmallVector<Register> PartialRdxs;
6256 for (unsigned Idx = 0; Idx < SplitSrcs.size()-1; Idx += 2) {
6257 Register LHS = SplitSrcs[Idx];
6258 Register RHS = SplitSrcs[Idx + 1];
6259 // Create the intermediate vector op.
6260 Register Res =
6261 MIRBuilder.buildInstr(ScalarOpc, {NarrowTy}, {LHS, RHS}).getReg(0);
6262 PartialRdxs.push_back(Res);
6263 }
6264 SplitSrcs = std::move(PartialRdxs);
6265 }
6266 // Finally generate the requested NarrowTy based reduction.
6267 Observer.changingInstr(MI);
6268 MI.getOperand(1).setReg(SplitSrcs[0]);
6269 Observer.changedInstr(MI);
6270 return Legalized;
6271}
6272
6275 const LLT HalfTy, const LLT AmtTy) {
6276
6277 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6278 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6279 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6280
6281 if (Amt.isZero()) {
6282 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {InL, InH});
6283 MI.eraseFromParent();
6284 return Legalized;
6285 }
6286
6287 LLT NVT = HalfTy;
6288 unsigned NVTBits = HalfTy.getSizeInBits();
6289 unsigned VTBits = 2 * NVTBits;
6290
6291 SrcOp Lo(Register(0)), Hi(Register(0));
6292 if (MI.getOpcode() == TargetOpcode::G_SHL) {
6293 if (Amt.ugt(VTBits)) {
6294 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6295 } else if (Amt.ugt(NVTBits)) {
6296 Lo = MIRBuilder.buildConstant(NVT, 0);
6297 Hi = MIRBuilder.buildShl(NVT, InL,
6298 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6299 } else if (Amt == NVTBits) {
6300 Lo = MIRBuilder.buildConstant(NVT, 0);
6301 Hi = InL;
6302 } else {
6303 Lo = MIRBuilder.buildShl(NVT, InL, MIRBuilder.buildConstant(AmtTy, Amt));
6304 auto OrLHS =
6305 MIRBuilder.buildShl(NVT, InH, MIRBuilder.buildConstant(AmtTy, Amt));
6306 auto OrRHS = MIRBuilder.buildLShr(
6307 NVT, InL, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6308 Hi = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6309 }
6310 } else if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6311 if (Amt.ugt(VTBits)) {
6312 Lo = Hi = MIRBuilder.buildConstant(NVT, 0);
6313 } else if (Amt.ugt(NVTBits)) {
6314 Lo = MIRBuilder.buildLShr(NVT, InH,
6315 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6316 Hi = MIRBuilder.buildConstant(NVT, 0);
6317 } else if (Amt == NVTBits) {
6318 Lo = InH;
6319 Hi = MIRBuilder.buildConstant(NVT, 0);
6320 } else {
6321 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6322
6323 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6324 auto OrRHS = MIRBuilder.buildShl(
6325 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6326
6327 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6328 Hi = MIRBuilder.buildLShr(NVT, InH, ShiftAmtConst);
6329 }
6330 } else {
6331 if (Amt.ugt(VTBits)) {
6332 Hi = Lo = MIRBuilder.buildAShr(
6333 NVT, InH, MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6334 } else if (Amt.ugt(NVTBits)) {
6335 Lo = MIRBuilder.buildAShr(NVT, InH,
6336 MIRBuilder.buildConstant(AmtTy, Amt - NVTBits));
6337 Hi = MIRBuilder.buildAShr(NVT, InH,
6338 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6339 } else if (Amt == NVTBits) {
6340 Lo = InH;
6341 Hi = MIRBuilder.buildAShr(NVT, InH,
6342 MIRBuilder.buildConstant(AmtTy, NVTBits - 1));
6343 } else {
6344 auto ShiftAmtConst = MIRBuilder.buildConstant(AmtTy, Amt);
6345
6346 auto OrLHS = MIRBuilder.buildLShr(NVT, InL, ShiftAmtConst);
6347 auto OrRHS = MIRBuilder.buildShl(
6348 NVT, InH, MIRBuilder.buildConstant(AmtTy, -Amt + NVTBits));
6349
6350 Lo = MIRBuilder.buildOr(NVT, OrLHS, OrRHS);
6351 Hi = MIRBuilder.buildAShr(NVT, InH, ShiftAmtConst);
6352 }
6353 }
6354
6355 MIRBuilder.buildMergeLikeInstr(MI.getOperand(0), {Lo, Hi});
6356 MI.eraseFromParent();
6357
6358 return Legalized;
6359}
6360
6363 LLT RequestedTy) {
6364 if (TypeIdx == 1) {
6365 Observer.changingInstr(MI);
6366 narrowScalarSrc(MI, RequestedTy, 2);
6367 Observer.changedInstr(MI);
6368 return Legalized;
6369 }
6370
6371 Register DstReg = MI.getOperand(0).getReg();
6372 LLT DstTy = MRI.getType(DstReg);
6373 if (DstTy.isVector())
6374 return UnableToLegalize;
6375
6376 Register Amt = MI.getOperand(2).getReg();
6377 LLT ShiftAmtTy = MRI.getType(Amt);
6378 const unsigned DstEltSize = DstTy.getScalarSizeInBits();
6379 if (DstEltSize % 2 != 0)
6380 return UnableToLegalize;
6381
6382 // Check if we should use multi-way splitting instead of recursive binary
6383 // splitting.
6384 //
6385 // Multi-way splitting directly decomposes wide shifts (e.g., 128-bit ->
6386 // 4×32-bit) in a single legalization step, avoiding the recursive overhead
6387 // and dependency chains created by usual binary splitting approach
6388 // (128->64->32).
6389 //
6390 // The >= 8 parts threshold ensures we only use this optimization when binary
6391 // splitting would require multiple recursive passes, avoiding overhead for
6392 // simple 2-way splits where binary approach is sufficient.
6393 if (RequestedTy.isValid() && RequestedTy.isScalar() &&
6394 DstEltSize % RequestedTy.getSizeInBits() == 0) {
6395 const unsigned NumParts = DstEltSize / RequestedTy.getSizeInBits();
6396 // Use multiway if we have 8 or more parts (i.e., would need 3+ recursive
6397 // steps).
6398 if (NumParts >= 8)
6399 return narrowScalarShiftMultiway(MI, RequestedTy);
6400 }
6401
6402 // Fall back to binary splitting:
6403 // Ignore the input type. We can only go to exactly half the size of the
6404 // input. If that isn't small enough, the resulting pieces will be further
6405 // legalized.
6406 const unsigned NewBitSize = DstEltSize / 2;
6407 const LLT HalfTy = DstTy.getScalarType().changeElementSize(NewBitSize);
6408 const LLT CondTy = LLT::integer(1);
6409
6410 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(Amt, MRI)) {
6411 return narrowScalarShiftByConstant(MI, VRegAndVal->Value, HalfTy,
6412 ShiftAmtTy);
6413 }
6414
6415 // TODO: Expand with known bits.
6416
6417 // Handle the fully general expansion by an unknown amount.
6418 auto NewBits = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize);
6419
6420 Register InL = MRI.createGenericVirtualRegister(HalfTy);
6421 Register InH = MRI.createGenericVirtualRegister(HalfTy);
6422 MIRBuilder.buildUnmerge({InL, InH}, MI.getOperand(1));
6423
6424 auto AmtExcess = MIRBuilder.buildSub(ShiftAmtTy, Amt, NewBits);
6425 auto AmtLack = MIRBuilder.buildSub(ShiftAmtTy, NewBits, Amt);
6426
6427 auto Zero = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6428 auto IsShort = MIRBuilder.buildICmp(ICmpInst::ICMP_ULT, CondTy, Amt, NewBits);
6429 auto IsZero = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, CondTy, Amt, Zero);
6430
6431 Register ResultRegs[2];
6432 switch (MI.getOpcode()) {
6433 case TargetOpcode::G_SHL: {
6434 // Short: ShAmt < NewBitSize
6435 auto LoS = MIRBuilder.buildShl(HalfTy, InL, Amt);
6436
6437 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, AmtLack);
6438 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, Amt);
6439 auto HiS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6440
6441 // Long: ShAmt >= NewBitSize
6442 auto LoL = MIRBuilder.buildConstant(HalfTy, 0); // Lo part is zero.
6443 auto HiL = MIRBuilder.buildShl(HalfTy, InL, AmtExcess); // Hi from Lo part.
6444
6445 auto Lo = MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL);
6446 auto Hi = MIRBuilder.buildSelect(
6447 HalfTy, IsZero, InH, MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL));
6448
6449 ResultRegs[0] = Lo.getReg(0);
6450 ResultRegs[1] = Hi.getReg(0);
6451 break;
6452 }
6453 case TargetOpcode::G_LSHR:
6454 case TargetOpcode::G_ASHR: {
6455 // Short: ShAmt < NewBitSize
6456 auto HiS = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy}, {InH, Amt});
6457
6458 auto LoOr = MIRBuilder.buildLShr(HalfTy, InL, Amt);
6459 auto HiOr = MIRBuilder.buildShl(HalfTy, InH, AmtLack);
6460 auto LoS = MIRBuilder.buildOr(HalfTy, LoOr, HiOr);
6461
6462 // Long: ShAmt >= NewBitSize
6464 if (MI.getOpcode() == TargetOpcode::G_LSHR) {
6465 HiL = MIRBuilder.buildConstant(HalfTy, 0); // Hi part is zero.
6466 } else {
6467 auto ShiftAmt = MIRBuilder.buildConstant(ShiftAmtTy, NewBitSize - 1);
6468 HiL = MIRBuilder.buildAShr(HalfTy, InH, ShiftAmt); // Sign of Hi part.
6469 }
6470 auto LoL = MIRBuilder.buildInstr(MI.getOpcode(), {HalfTy},
6471 {InH, AmtExcess}); // Lo from Hi part.
6472
6473 auto Lo = MIRBuilder.buildSelect(
6474 HalfTy, IsZero, InL, MIRBuilder.buildSelect(HalfTy, IsShort, LoS, LoL));
6475
6476 auto Hi = MIRBuilder.buildSelect(HalfTy, IsShort, HiS, HiL);
6477
6478 ResultRegs[0] = Lo.getReg(0);
6479 ResultRegs[1] = Hi.getReg(0);
6480 break;
6481 }
6482 default:
6483 llvm_unreachable("not a shift");
6484 }
6485
6486 MIRBuilder.buildMergeLikeInstr(DstReg, ResultRegs);
6487 MI.eraseFromParent();
6488 return Legalized;
6489}
6490
6492 unsigned PartIdx,
6493 unsigned NumParts,
6494 ArrayRef<Register> SrcParts,
6495 const ShiftParams &Params,
6496 LLT TargetTy, LLT ShiftAmtTy) {
6497 auto WordShiftConst = getIConstantVRegVal(Params.WordShift, MRI);
6498 auto BitShiftConst = getIConstantVRegVal(Params.BitShift, MRI);
6499 assert(WordShiftConst && BitShiftConst && "Expected constants");
6500
6501 const unsigned ShiftWords = WordShiftConst->getZExtValue();
6502 const unsigned ShiftBits = BitShiftConst->getZExtValue();
6503 const bool NeedsInterWordShift = ShiftBits != 0;
6504
6505 switch (Opcode) {
6506 case TargetOpcode::G_SHL: {
6507 // Data moves from lower indices to higher indices
6508 // If this part would come from a source beyond our range, it's zero
6509 if (PartIdx < ShiftWords)
6510 return Params.Zero;
6511
6512 unsigned SrcIdx = PartIdx - ShiftWords;
6513 if (!NeedsInterWordShift)
6514 return SrcParts[SrcIdx];
6515
6516 // Combine shifted main part with carry from previous part
6517 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6518 if (SrcIdx > 0) {
6519 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx - 1],
6520 Params.InvBitShift);
6521 return MIRBuilder.buildOr(TargetTy, Hi, Lo).getReg(0);
6522 }
6523 return Hi.getReg(0);
6524 }
6525
6526 case TargetOpcode::G_LSHR: {
6527 unsigned SrcIdx = PartIdx + ShiftWords;
6528 if (SrcIdx >= NumParts)
6529 return Params.Zero;
6530 if (!NeedsInterWordShift)
6531 return SrcParts[SrcIdx];
6532
6533 // Combine shifted main part with carry from next part
6534 auto Lo = MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6535 if (SrcIdx + 1 < NumParts) {
6536 auto Hi = MIRBuilder.buildShl(TargetTy, SrcParts[SrcIdx + 1],
6537 Params.InvBitShift);
6538 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6539 }
6540 return Lo.getReg(0);
6541 }
6542
6543 case TargetOpcode::G_ASHR: {
6544 // Like LSHR but preserves sign bit
6545 unsigned SrcIdx = PartIdx + ShiftWords;
6546 if (SrcIdx >= NumParts)
6547 return Params.SignBit;
6548 if (!NeedsInterWordShift)
6549 return SrcParts[SrcIdx];
6550
6551 // Only the original MSB part uses arithmetic shift to preserve sign. All
6552 // other parts use logical shift since they're just moving data bits.
6553 auto Lo =
6554 (SrcIdx == NumParts - 1)
6555 ? MIRBuilder.buildAShr(TargetTy, SrcParts[SrcIdx], Params.BitShift)
6556 : MIRBuilder.buildLShr(TargetTy, SrcParts[SrcIdx], Params.BitShift);
6557 Register HiSrc =
6558 (SrcIdx + 1 < NumParts) ? SrcParts[SrcIdx + 1] : Params.SignBit;
6559 auto Hi = MIRBuilder.buildShl(TargetTy, HiSrc, Params.InvBitShift);
6560 return MIRBuilder.buildOr(TargetTy, Lo, Hi).getReg(0);
6561 }
6562
6563 default:
6564 llvm_unreachable("not a shift");
6565 }
6566}
6567
6569 Register MainOperand,
6570 Register ShiftAmt,
6571 LLT TargetTy,
6572 Register CarryOperand) {
6573 // This helper generates a single output part for variable shifts by combining
6574 // the main operand (shifted by BitShift) with carry bits from an adjacent
6575 // part.
6576
6577 // For G_ASHR, individual parts don't have their own sign bit, only the
6578 // complete value does. So we use LSHR for the main operand shift in ASHR
6579 // context.
6580 unsigned MainOpcode = (Opcode == TargetOpcode::G_ASHR)
6581 ? static_cast<unsigned>(TargetOpcode::G_LSHR)
6582 : Opcode;
6583
6584 // Perform the primary shift on the main operand
6585 Register MainShifted =
6586 MIRBuilder.buildInstr(MainOpcode, {TargetTy}, {MainOperand, ShiftAmt})
6587 .getReg(0);
6588
6589 // No carry operand available
6590 if (!CarryOperand.isValid())
6591 return MainShifted;
6592
6593 // If BitShift is 0 (word-aligned shift), no inter-word bit movement occurs,
6594 // so carry bits aren't needed.
6595 LLT ShiftAmtTy = MRI.getType(ShiftAmt);
6596 auto ZeroConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6597 LLT BoolTy = LLT::scalar(1);
6598 auto IsZeroBitShift =
6599 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, ShiftAmt, ZeroConst);
6600
6601 // Extract bits from the adjacent part that will "carry over" into this part.
6602 // The carry direction is opposite to the main shift direction, so we can
6603 // align the two shifted values before combining them with OR.
6604
6605 // Determine the carry shift opcode (opposite direction)
6606 unsigned CarryOpcode = (Opcode == TargetOpcode::G_SHL) ? TargetOpcode::G_LSHR
6607 : TargetOpcode::G_SHL;
6608
6609 // Calculate inverse shift amount: BitWidth - ShiftAmt
6610 auto TargetBitsConst =
6611 MIRBuilder.buildConstant(ShiftAmtTy, TargetTy.getScalarSizeInBits());
6612 auto InvShiftAmt = MIRBuilder.buildSub(ShiftAmtTy, TargetBitsConst, ShiftAmt);
6613
6614 // Shift the carry operand
6615 Register CarryBits =
6617 .buildInstr(CarryOpcode, {TargetTy}, {CarryOperand, InvShiftAmt})
6618 .getReg(0);
6619
6620 // If BitShift is 0, don't include carry bits (InvShiftAmt would equal
6621 // TargetBits which would be poison for the individual carry shift operation).
6622 auto ZeroReg = MIRBuilder.buildConstant(TargetTy, 0);
6623 Register SafeCarryBits =
6624 MIRBuilder.buildSelect(TargetTy, IsZeroBitShift, ZeroReg, CarryBits)
6625 .getReg(0);
6626
6627 // Combine the main shifted part with the carry bits
6628 return MIRBuilder.buildOr(TargetTy, MainShifted, SafeCarryBits).getReg(0);
6629}
6630
6633 const APInt &Amt,
6634 LLT TargetTy,
6635 LLT ShiftAmtTy) {
6636 // Any wide shift can be decomposed into WordShift + BitShift components.
6637 // When shift amount is known constant, directly compute the decomposition
6638 // values and generate constant registers.
6639 Register DstReg = MI.getOperand(0).getReg();
6640 Register SrcReg = MI.getOperand(1).getReg();
6641 LLT DstTy = MRI.getType(DstReg);
6642
6643 const unsigned DstBits = DstTy.getScalarSizeInBits();
6644 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6645 const unsigned NumParts = DstBits / TargetBits;
6646
6647 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6648
6649 // When the shift amount is known at compile time, we just calculate which
6650 // source parts contribute to each output part.
6651
6652 SmallVector<Register, 8> SrcParts;
6653 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6654
6655 if (Amt.isZero()) {
6656 // No shift needed, just copy
6657 MIRBuilder.buildMergeLikeInstr(DstReg, SrcParts);
6658 MI.eraseFromParent();
6659 return Legalized;
6660 }
6661
6662 ShiftParams Params;
6663 const unsigned ShiftWords = Amt.getZExtValue() / TargetBits;
6664 const unsigned ShiftBits = Amt.getZExtValue() % TargetBits;
6665
6666 // Generate constants and values needed by all shift types
6667 Params.WordShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftWords).getReg(0);
6668 Params.BitShift = MIRBuilder.buildConstant(ShiftAmtTy, ShiftBits).getReg(0);
6669 Params.InvBitShift =
6670 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - ShiftBits).getReg(0);
6671 Params.Zero = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6672
6673 // For ASHR, we need the sign-extended value to fill shifted-out positions
6674 if (MI.getOpcode() == TargetOpcode::G_ASHR)
6675 Params.SignBit =
6677 .buildAShr(TargetTy, SrcParts[SrcParts.size() - 1],
6678 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1))
6679 .getReg(0);
6680
6681 SmallVector<Register, 8> DstParts(NumParts);
6682 for (unsigned I = 0; I < NumParts; ++I)
6683 DstParts[I] = buildConstantShiftPart(MI.getOpcode(), I, NumParts, SrcParts,
6684 Params, TargetTy, ShiftAmtTy);
6685
6686 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6687 MI.eraseFromParent();
6688 return Legalized;
6689}
6690
6693 Register DstReg = MI.getOperand(0).getReg();
6694 Register SrcReg = MI.getOperand(1).getReg();
6695 Register AmtReg = MI.getOperand(2).getReg();
6696 LLT DstTy = MRI.getType(DstReg);
6697 LLT ShiftAmtTy = MRI.getType(AmtReg);
6698
6699 const unsigned DstBits = DstTy.getScalarSizeInBits();
6700 const unsigned TargetBits = TargetTy.getScalarSizeInBits();
6701 const unsigned NumParts = DstBits / TargetBits;
6702
6703 assert(DstBits % TargetBits == 0 && "Target type must evenly divide source");
6704 assert(isPowerOf2_32(TargetBits) && "Target bit width must be power of 2");
6705
6706 // If the shift amount is known at compile time, we can use direct indexing
6707 // instead of generating select chains in the general case.
6708 if (auto VRegAndVal = getIConstantVRegValWithLookThrough(AmtReg, MRI))
6709 return narrowScalarShiftByConstantMultiway(MI, VRegAndVal->Value, TargetTy,
6710 ShiftAmtTy);
6711
6712 // For runtime-variable shift amounts, we must generate a more complex
6713 // sequence that handles all possible shift values using select chains.
6714
6715 // Split the input into target-sized pieces
6716 SmallVector<Register, 8> SrcParts;
6717 extractParts(SrcReg, TargetTy, NumParts, SrcParts, MIRBuilder, MRI);
6718
6719 // Shifting by zero should be a no-op.
6720 auto ZeroAmtConst = MIRBuilder.buildConstant(ShiftAmtTy, 0);
6721 LLT BoolTy = LLT::scalar(1);
6722 auto IsZeroShift =
6723 MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy, AmtReg, ZeroAmtConst);
6724
6725 // Any wide shift can be decomposed into two components:
6726 // 1. WordShift: number of complete target-sized words to shift
6727 // 2. BitShift: number of bits to shift within each word
6728 //
6729 // Example: 128-bit >> 50 with 32-bit target:
6730 // WordShift = 50 / 32 = 1 (shift right by 1 complete word)
6731 // BitShift = 50 % 32 = 18 (shift each word right by 18 bits)
6732 unsigned TargetBitsLog2 = Log2_32(TargetBits);
6733 auto TargetBitsLog2Const =
6734 MIRBuilder.buildConstant(ShiftAmtTy, TargetBitsLog2);
6735 auto TargetBitsMask = MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6736
6737 Register WordShift =
6738 MIRBuilder.buildLShr(ShiftAmtTy, AmtReg, TargetBitsLog2Const).getReg(0);
6739 Register BitShift =
6740 MIRBuilder.buildAnd(ShiftAmtTy, AmtReg, TargetBitsMask).getReg(0);
6741
6742 // Fill values:
6743 // - SHL/LSHR: fill with zeros
6744 // - ASHR: fill with sign-extended MSB
6745 Register ZeroReg = MIRBuilder.buildConstant(TargetTy, 0).getReg(0);
6746
6747 Register FillValue;
6748 if (MI.getOpcode() == TargetOpcode::G_ASHR) {
6749 auto TargetBitsMinusOneConst =
6750 MIRBuilder.buildConstant(ShiftAmtTy, TargetBits - 1);
6751 FillValue = MIRBuilder
6752 .buildAShr(TargetTy, SrcParts[NumParts - 1],
6753 TargetBitsMinusOneConst)
6754 .getReg(0);
6755 } else {
6756 FillValue = ZeroReg;
6757 }
6758
6759 SmallVector<Register, 8> DstParts(NumParts);
6760
6761 // For each output part, generate a select chain that chooses the correct
6762 // result based on the runtime WordShift value. This handles all possible
6763 // word shift amounts by pre-calculating what each would produce.
6764 for (unsigned I = 0; I < NumParts; ++I) {
6765 // Initialize with appropriate default value for this shift type
6766 Register InBoundsResult = FillValue;
6767
6768 // clang-format off
6769 // Build a branchless select chain by pre-computing results for all possible
6770 // WordShift values (0 to NumParts-1). Each iteration nests a new select:
6771 //
6772 // K=0: select(WordShift==0, result0, FillValue)
6773 // K=1: select(WordShift==1, result1, select(WordShift==0, result0, FillValue))
6774 // K=2: select(WordShift==2, result2, select(WordShift==1, result1, select(...)))
6775 // clang-format on
6776 for (unsigned K = 0; K < NumParts; ++K) {
6777 auto WordShiftKConst = MIRBuilder.buildConstant(ShiftAmtTy, K);
6778 auto IsWordShiftK = MIRBuilder.buildICmp(ICmpInst::ICMP_EQ, BoolTy,
6779 WordShift, WordShiftKConst);
6780
6781 // Calculate source indices for this word shift
6782 //
6783 // For 4-part 128-bit value with K=1 word shift:
6784 // SHL: [3][2][1][0] << K => [2][1][0][Z]
6785 // -> (MainIdx = I-K, CarryIdx = I-K-1)
6786 // LSHR: [3][2][1][0] >> K => [Z][3][2][1]
6787 // -> (MainIdx = I+K, CarryIdx = I+K+1)
6788 int MainSrcIdx;
6789 int CarrySrcIdx; // Index for the word that provides the carried-in bits.
6790
6791 switch (MI.getOpcode()) {
6792 case TargetOpcode::G_SHL:
6793 MainSrcIdx = (int)I - (int)K;
6794 CarrySrcIdx = MainSrcIdx - 1;
6795 break;
6796 case TargetOpcode::G_LSHR:
6797 case TargetOpcode::G_ASHR:
6798 MainSrcIdx = (int)I + (int)K;
6799 CarrySrcIdx = MainSrcIdx + 1;
6800 break;
6801 default:
6802 llvm_unreachable("Not a shift");
6803 }
6804
6805 // Check bounds and build the result for this word shift
6806 Register ResultForK;
6807 if (MainSrcIdx >= 0 && MainSrcIdx < (int)NumParts) {
6808 Register MainOp = SrcParts[MainSrcIdx];
6809 Register CarryOp;
6810
6811 // Determine carry operand with bounds checking
6812 if (CarrySrcIdx >= 0 && CarrySrcIdx < (int)NumParts)
6813 CarryOp = SrcParts[CarrySrcIdx];
6814 else if (MI.getOpcode() == TargetOpcode::G_ASHR &&
6815 CarrySrcIdx >= (int)NumParts)
6816 CarryOp = FillValue; // Use sign extension
6817
6818 ResultForK = buildVariableShiftPart(MI.getOpcode(), MainOp, BitShift,
6819 TargetTy, CarryOp);
6820 } else {
6821 // Out of bounds - use fill value for this k
6822 ResultForK = FillValue;
6823 }
6824
6825 // Select this result if WordShift equals k
6826 InBoundsResult =
6828 .buildSelect(TargetTy, IsWordShiftK, ResultForK, InBoundsResult)
6829 .getReg(0);
6830 }
6831
6832 // Handle zero-shift special case: if shift is 0, use original input
6833 DstParts[I] =
6835 .buildSelect(TargetTy, IsZeroShift, SrcParts[I], InBoundsResult)
6836 .getReg(0);
6837 }
6838
6839 MIRBuilder.buildMergeLikeInstr(DstReg, DstParts);
6840 MI.eraseFromParent();
6841 return Legalized;
6842}
6843
6846 LLT MoreTy) {
6847 assert(TypeIdx == 0 && "Expecting only Idx 0");
6848
6849 Observer.changingInstr(MI);
6850 for (unsigned I = 1, E = MI.getNumOperands(); I != E; I += 2) {
6851 MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
6852 MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
6853 moreElementsVectorSrc(MI, MoreTy, I);
6854 }
6855
6856 MachineBasicBlock &MBB = *MI.getParent();
6857 MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
6858 moreElementsVectorDst(MI, MoreTy, 0);
6859 Observer.changedInstr(MI);
6860 return Legalized;
6861}
6862
6863MachineInstrBuilder LegalizerHelper::getNeutralElementForVecReduce(
6864 unsigned Opcode, MachineIRBuilder &MIRBuilder, LLT Ty) {
6865 assert(Ty.isScalar() && "Expected scalar type to make neutral element for");
6866
6867 switch (Opcode) {
6868 default:
6870 "getNeutralElementForVecReduce called with invalid opcode!");
6871 case TargetOpcode::G_VECREDUCE_ADD:
6872 case TargetOpcode::G_VECREDUCE_OR:
6873 case TargetOpcode::G_VECREDUCE_XOR:
6874 case TargetOpcode::G_VECREDUCE_UMAX:
6875 return MIRBuilder.buildConstant(Ty, 0);
6876 case TargetOpcode::G_VECREDUCE_MUL:
6877 return MIRBuilder.buildConstant(Ty, 1);
6878 case TargetOpcode::G_VECREDUCE_AND:
6879 case TargetOpcode::G_VECREDUCE_UMIN:
6881 Ty, APInt::getAllOnes(Ty.getScalarSizeInBits()));
6882 case TargetOpcode::G_VECREDUCE_SMAX:
6884 Ty, APInt::getSignedMinValue(Ty.getSizeInBits()));
6885 case TargetOpcode::G_VECREDUCE_SMIN:
6887 Ty, APInt::getSignedMaxValue(Ty.getSizeInBits()));
6888 case TargetOpcode::G_VECREDUCE_FADD:
6889 return MIRBuilder.buildFConstant(Ty, -0.0);
6890 case TargetOpcode::G_VECREDUCE_FMUL:
6891 return MIRBuilder.buildFConstant(Ty, 1.0);
6892 case TargetOpcode::G_VECREDUCE_FMINIMUM:
6893 case TargetOpcode::G_VECREDUCE_FMAXIMUM:
6894 assert(false && "getNeutralElementForVecReduce unimplemented for "
6895 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6896 }
6897 llvm_unreachable("switch expected to return!");
6898}
6899
6902 LLT MoreTy) {
6903 unsigned Opc = MI.getOpcode();
6904 switch (Opc) {
6905 case TargetOpcode::G_IMPLICIT_DEF:
6906 case TargetOpcode::G_LOAD: {
6907 if (TypeIdx != 0)
6908 return UnableToLegalize;
6909 Observer.changingInstr(MI);
6910 moreElementsVectorDst(MI, MoreTy, 0);
6911 Observer.changedInstr(MI);
6912 return Legalized;
6913 }
6914 case TargetOpcode::G_STORE:
6915 if (TypeIdx != 0)
6916 return UnableToLegalize;
6917 Observer.changingInstr(MI);
6918 moreElementsVectorSrc(MI, MoreTy, 0);
6919 Observer.changedInstr(MI);
6920 return Legalized;
6921 case TargetOpcode::G_AND:
6922 case TargetOpcode::G_OR:
6923 case TargetOpcode::G_XOR:
6924 case TargetOpcode::G_ADD:
6925 case TargetOpcode::G_SUB:
6926 case TargetOpcode::G_MUL:
6927 case TargetOpcode::G_FADD:
6928 case TargetOpcode::G_FSUB:
6929 case TargetOpcode::G_FMUL:
6930 case TargetOpcode::G_FDIV:
6931 case TargetOpcode::G_FCOPYSIGN:
6932 case TargetOpcode::G_UADDSAT:
6933 case TargetOpcode::G_USUBSAT:
6934 case TargetOpcode::G_SADDSAT:
6935 case TargetOpcode::G_SSUBSAT:
6936 case TargetOpcode::G_SMIN:
6937 case TargetOpcode::G_SMAX:
6938 case TargetOpcode::G_UMIN:
6939 case TargetOpcode::G_UMAX:
6940 case TargetOpcode::G_FMINNUM:
6941 case TargetOpcode::G_FMAXNUM:
6942 case TargetOpcode::G_FMINNUM_IEEE:
6943 case TargetOpcode::G_FMAXNUM_IEEE:
6944 case TargetOpcode::G_FMINIMUM:
6945 case TargetOpcode::G_FMAXIMUM:
6946 case TargetOpcode::G_FMINIMUMNUM:
6947 case TargetOpcode::G_FMAXIMUMNUM:
6948 case TargetOpcode::G_STRICT_FADD:
6949 case TargetOpcode::G_STRICT_FSUB:
6950 case TargetOpcode::G_STRICT_FMUL: {
6951 Observer.changingInstr(MI);
6952 moreElementsVectorSrc(MI, MoreTy, 1);
6953 moreElementsVectorSrc(MI, MoreTy, 2);
6954 moreElementsVectorDst(MI, MoreTy, 0);
6955 Observer.changedInstr(MI);
6956 return Legalized;
6957 }
6958 case TargetOpcode::G_SHL:
6959 case TargetOpcode::G_ASHR:
6960 case TargetOpcode::G_LSHR: {
6961 Observer.changingInstr(MI);
6962 moreElementsVectorSrc(MI, MoreTy, 1);
6963 // The shift operand may have a different scalar type from the source and
6964 // destination operands.
6965 LLT ShiftMoreTy = MoreTy.changeElementType(
6966 MRI.getType(MI.getOperand(2).getReg()).getElementType());
6967 moreElementsVectorSrc(MI, ShiftMoreTy, 2);
6968 moreElementsVectorDst(MI, MoreTy, 0);
6969 Observer.changedInstr(MI);
6970 return Legalized;
6971 }
6972 case TargetOpcode::G_FMA:
6973 case TargetOpcode::G_STRICT_FMA:
6974 case TargetOpcode::G_FSHR:
6975 case TargetOpcode::G_FSHL: {
6976 Observer.changingInstr(MI);
6977 moreElementsVectorSrc(MI, MoreTy, 1);
6978 moreElementsVectorSrc(MI, MoreTy, 2);
6979 moreElementsVectorSrc(MI, MoreTy, 3);
6980 moreElementsVectorDst(MI, MoreTy, 0);
6981 Observer.changedInstr(MI);
6982 return Legalized;
6983 }
6984 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
6985 case TargetOpcode::G_EXTRACT:
6986 if (TypeIdx != 1)
6987 return UnableToLegalize;
6988 Observer.changingInstr(MI);
6989 moreElementsVectorSrc(MI, MoreTy, 1);
6990 Observer.changedInstr(MI);
6991 return Legalized;
6992 case TargetOpcode::G_INSERT:
6993 case TargetOpcode::G_INSERT_VECTOR_ELT:
6994 case TargetOpcode::G_FREEZE:
6995 case TargetOpcode::G_FNEG:
6996 case TargetOpcode::G_FABS:
6997 case TargetOpcode::G_FSQRT:
6998 case TargetOpcode::G_FCEIL:
6999 case TargetOpcode::G_FFLOOR:
7000 case TargetOpcode::G_FNEARBYINT:
7001 case TargetOpcode::G_FRINT:
7002 case TargetOpcode::G_INTRINSIC_ROUND:
7003 case TargetOpcode::G_INTRINSIC_ROUNDEVEN:
7004 case TargetOpcode::G_INTRINSIC_TRUNC:
7005 case TargetOpcode::G_BITREVERSE:
7006 case TargetOpcode::G_BSWAP:
7007 case TargetOpcode::G_FCANONICALIZE:
7008 case TargetOpcode::G_SEXT_INREG:
7009 case TargetOpcode::G_ABS:
7010 case TargetOpcode::G_CTLZ:
7011 case TargetOpcode::G_CTPOP:
7012 if (TypeIdx != 0)
7013 return UnableToLegalize;
7014 Observer.changingInstr(MI);
7015 moreElementsVectorSrc(MI, MoreTy, 1);
7016 moreElementsVectorDst(MI, MoreTy, 0);
7017 Observer.changedInstr(MI);
7018 return Legalized;
7019 case TargetOpcode::G_SELECT: {
7020 auto [DstReg, DstTy, CondReg, CondTy] = MI.getFirst2RegLLTs();
7021 if (TypeIdx == 1) {
7022 if (!CondTy.isScalar() ||
7023 DstTy.getElementCount() != MoreTy.getElementCount())
7024 return UnableToLegalize;
7025
7026 // This is turning a scalar select of vectors into a vector
7027 // select. Broadcast the select condition.
7028 auto ShufSplat = MIRBuilder.buildShuffleSplat(MoreTy, CondReg);
7029 Observer.changingInstr(MI);
7030 MI.getOperand(1).setReg(ShufSplat.getReg(0));
7031 Observer.changedInstr(MI);
7032 return Legalized;
7033 }
7034
7035 if (CondTy.isVector())
7036 return UnableToLegalize;
7037
7038 Observer.changingInstr(MI);
7039 moreElementsVectorSrc(MI, MoreTy, 2);
7040 moreElementsVectorSrc(MI, MoreTy, 3);
7041 moreElementsVectorDst(MI, MoreTy, 0);
7042 Observer.changedInstr(MI);
7043 return Legalized;
7044 }
7045 case TargetOpcode::G_UNMERGE_VALUES:
7046 return UnableToLegalize;
7047 case TargetOpcode::G_PHI:
7048 return moreElementsVectorPhi(MI, TypeIdx, MoreTy);
7049 case TargetOpcode::G_SHUFFLE_VECTOR:
7050 return moreElementsVectorShuffle(MI, TypeIdx, MoreTy);
7051 case TargetOpcode::G_BUILD_VECTOR: {
7053 for (auto Op : MI.uses()) {
7054 Elts.push_back(Op.getReg());
7055 }
7056
7057 for (unsigned i = Elts.size(); i < MoreTy.getNumElements(); ++i) {
7058 Elts.push_back(MIRBuilder.buildUndef(MoreTy.getScalarType()));
7059 }
7060
7061 MIRBuilder.buildDeleteTrailingVectorElements(
7062 MI.getOperand(0).getReg(), MIRBuilder.buildInstr(Opc, {MoreTy}, Elts));
7063 MI.eraseFromParent();
7064 return Legalized;
7065 }
7066 case TargetOpcode::G_SEXT:
7067 case TargetOpcode::G_ZEXT:
7068 case TargetOpcode::G_ANYEXT:
7069 case TargetOpcode::G_TRUNC:
7070 case TargetOpcode::G_FPTRUNC:
7071 case TargetOpcode::G_FPEXT:
7072 case TargetOpcode::G_FPTOSI:
7073 case TargetOpcode::G_FPTOUI:
7074 case TargetOpcode::G_FPTOSI_SAT:
7075 case TargetOpcode::G_FPTOUI_SAT:
7076 case TargetOpcode::G_SITOFP:
7077 case TargetOpcode::G_UITOFP:
7078 case TargetOpcode::G_TRUNC_SSAT_S:
7079 case TargetOpcode::G_TRUNC_SSAT_U:
7080 case TargetOpcode::G_TRUNC_USAT_U: {
7081 Observer.changingInstr(MI);
7082 LLT SrcExtTy;
7083 LLT DstExtTy;
7084 if (TypeIdx == 0) {
7085 DstExtTy = MoreTy;
7086 SrcExtTy = MoreTy.changeElementType(
7087 MRI.getType(MI.getOperand(1).getReg()).getElementType());
7088 } else {
7089 DstExtTy = MoreTy.changeElementType(
7090 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7091 SrcExtTy = MoreTy;
7092 }
7093 moreElementsVectorSrc(MI, SrcExtTy, 1);
7094 moreElementsVectorDst(MI, DstExtTy, 0);
7095 Observer.changedInstr(MI);
7096 return Legalized;
7097 }
7098 case TargetOpcode::G_ICMP:
7099 case TargetOpcode::G_FCMP: {
7100 if (TypeIdx != 1)
7101 return UnableToLegalize;
7102
7103 Observer.changingInstr(MI);
7104 moreElementsVectorSrc(MI, MoreTy, 2);
7105 moreElementsVectorSrc(MI, MoreTy, 3);
7106 LLT CondTy = MoreTy.changeVectorElementType(
7107 MRI.getType(MI.getOperand(0).getReg()).getElementType());
7108 moreElementsVectorDst(MI, CondTy, 0);
7109 Observer.changedInstr(MI);
7110 return Legalized;
7111 }
7112 case TargetOpcode::G_BITCAST: {
7113 if (TypeIdx != 0)
7114 return UnableToLegalize;
7115
7116 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg());
7117 LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
7118
7119 unsigned coefficient = SrcTy.getNumElements() * MoreTy.getNumElements();
7120 if (coefficient % DstTy.getNumElements() != 0)
7121 return UnableToLegalize;
7122
7123 coefficient = coefficient / DstTy.getNumElements();
7124
7125 LLT NewTy = SrcTy.changeElementCount(
7126 ElementCount::get(coefficient, MoreTy.isScalable()));
7127 Observer.changingInstr(MI);
7128 moreElementsVectorSrc(MI, NewTy, 1);
7129 moreElementsVectorDst(MI, MoreTy, 0);
7130 Observer.changedInstr(MI);
7131 return Legalized;
7132 }
7133 case TargetOpcode::G_VECREDUCE_FADD:
7134 case TargetOpcode::G_VECREDUCE_FMUL:
7135 case TargetOpcode::G_VECREDUCE_ADD:
7136 case TargetOpcode::G_VECREDUCE_MUL:
7137 case TargetOpcode::G_VECREDUCE_AND:
7138 case TargetOpcode::G_VECREDUCE_OR:
7139 case TargetOpcode::G_VECREDUCE_XOR:
7140 case TargetOpcode::G_VECREDUCE_SMAX:
7141 case TargetOpcode::G_VECREDUCE_SMIN:
7142 case TargetOpcode::G_VECREDUCE_UMAX:
7143 case TargetOpcode::G_VECREDUCE_UMIN: {
7144 LLT OrigTy = MRI.getType(MI.getOperand(1).getReg());
7145 MachineOperand &MO = MI.getOperand(1);
7146 auto NewVec = MIRBuilder.buildPadVectorWithUndefElements(MoreTy, MO);
7147 auto NeutralElement = getNeutralElementForVecReduce(
7148 MI.getOpcode(), MIRBuilder, MoreTy.getElementType());
7149
7150 LLT IdxTy(TLI.getVectorIdxLLT(MIRBuilder.getDataLayout()));
7151 for (size_t i = OrigTy.getNumElements(), e = MoreTy.getNumElements();
7152 i != e; i++) {
7153 auto Idx = MIRBuilder.buildConstant(IdxTy, i);
7154 NewVec = MIRBuilder.buildInsertVectorElement(MoreTy, NewVec,
7155 NeutralElement, Idx);
7156 }
7157
7158 Observer.changingInstr(MI);
7159 MO.setReg(NewVec.getReg(0));
7160 Observer.changedInstr(MI);
7161 return Legalized;
7162 }
7163
7164 default:
7165 return UnableToLegalize;
7166 }
7167}
7168
7171 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7172 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7173 unsigned MaskNumElts = Mask.size();
7174 unsigned SrcNumElts = SrcTy.getNumElements();
7175 LLT DestEltTy = DstTy.getElementType();
7176
7177 if (MaskNumElts == SrcNumElts)
7178 return Legalized;
7179
7180 if (MaskNumElts < SrcNumElts) {
7181 // Extend mask to match new destination vector size with
7182 // undef values.
7183 SmallVector<int, 16> NewMask(SrcNumElts, -1);
7184 llvm::copy(Mask, NewMask.begin());
7185
7186 moreElementsVectorDst(MI, SrcTy, 0);
7187 MIRBuilder.setInstrAndDebugLoc(MI);
7188 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7189 MI.getOperand(1).getReg(),
7190 MI.getOperand(2).getReg(), NewMask);
7191 MI.eraseFromParent();
7192
7193 return Legalized;
7194 }
7195
7196 unsigned PaddedMaskNumElts = alignTo(MaskNumElts, SrcNumElts);
7197 unsigned NumConcat = PaddedMaskNumElts / SrcNumElts;
7198 LLT PaddedTy =
7199 DstTy.changeVectorElementCount(ElementCount::getFixed(PaddedMaskNumElts));
7200
7201 // Create new source vectors by concatenating the initial
7202 // source vectors with undefined vectors of the same size.
7203 auto Undef = MIRBuilder.buildUndef(SrcTy);
7204 SmallVector<Register, 8> MOps1(NumConcat, Undef.getReg(0));
7205 SmallVector<Register, 8> MOps2(NumConcat, Undef.getReg(0));
7206 MOps1[0] = MI.getOperand(1).getReg();
7207 MOps2[0] = MI.getOperand(2).getReg();
7208
7209 auto Src1 = MIRBuilder.buildConcatVectors(PaddedTy, MOps1);
7210 auto Src2 = MIRBuilder.buildConcatVectors(PaddedTy, MOps2);
7211
7212 // Readjust mask for new input vector length.
7213 SmallVector<int, 8> MappedOps(PaddedMaskNumElts, -1);
7214 for (unsigned I = 0; I != MaskNumElts; ++I) {
7215 int Idx = Mask[I];
7216 if (Idx >= static_cast<int>(SrcNumElts))
7217 Idx += PaddedMaskNumElts - SrcNumElts;
7218 MappedOps[I] = Idx;
7219 }
7220
7221 // If we got more elements than required, extract subvector.
7222 if (MaskNumElts != PaddedMaskNumElts) {
7223 auto Shuffle =
7224 MIRBuilder.buildShuffleVector(PaddedTy, Src1, Src2, MappedOps);
7225
7226 SmallVector<Register, 16> Elts(MaskNumElts);
7227 for (unsigned I = 0; I < MaskNumElts; ++I) {
7228 Elts[I] =
7229 MIRBuilder.buildExtractVectorElementConstant(DestEltTy, Shuffle, I)
7230 .getReg(0);
7231 }
7232 MIRBuilder.buildBuildVector(DstReg, Elts);
7233 } else {
7234 MIRBuilder.buildShuffleVector(DstReg, Src1, Src2, MappedOps);
7235 }
7236
7237 MI.eraseFromParent();
7239}
7240
7243 unsigned int TypeIdx, LLT MoreTy) {
7244 auto [DstTy, Src1Ty, Src2Ty] = MI.getFirst3LLTs();
7245 ArrayRef<int> Mask = MI.getOperand(3).getShuffleMask();
7246 unsigned NumElts = DstTy.getNumElements();
7247 unsigned WidenNumElts = MoreTy.getNumElements();
7248
7249 if (DstTy.isVector() && Src1Ty.isVector() &&
7250 DstTy.getNumElements() != Src1Ty.getNumElements()) {
7252 }
7253
7254 if (TypeIdx != 0)
7255 return UnableToLegalize;
7256
7257 // Expect a canonicalized shuffle.
7258 if (DstTy != Src1Ty || DstTy != Src2Ty)
7259 return UnableToLegalize;
7260
7261 moreElementsVectorSrc(MI, MoreTy, 1);
7262 moreElementsVectorSrc(MI, MoreTy, 2);
7263
7264 // Adjust mask based on new input vector length.
7265 SmallVector<int, 16> NewMask(WidenNumElts, -1);
7266 for (unsigned I = 0; I != NumElts; ++I) {
7267 int Idx = Mask[I];
7268 if (Idx < static_cast<int>(NumElts))
7269 NewMask[I] = Idx;
7270 else
7271 NewMask[I] = Idx - NumElts + WidenNumElts;
7272 }
7273 moreElementsVectorDst(MI, MoreTy, 0);
7274 MIRBuilder.setInstrAndDebugLoc(MI);
7275 MIRBuilder.buildShuffleVector(MI.getOperand(0).getReg(),
7276 MI.getOperand(1).getReg(),
7277 MI.getOperand(2).getReg(), NewMask);
7278 MI.eraseFromParent();
7279 return Legalized;
7280}
7281
7282void LegalizerHelper::multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
7283 ArrayRef<Register> Src1Regs,
7284 ArrayRef<Register> Src2Regs,
7285 LLT NarrowTy) {
7287 unsigned SrcParts = Src1Regs.size();
7288 unsigned DstParts = DstRegs.size();
7289
7290 unsigned DstIdx = 0; // Low bits of the result.
7291 Register FactorSum =
7292 B.buildMul(NarrowTy, Src1Regs[DstIdx], Src2Regs[DstIdx]).getReg(0);
7293 DstRegs[DstIdx] = FactorSum;
7294
7295 Register CarrySumPrevDstIdx;
7297
7298 for (DstIdx = 1; DstIdx < DstParts; DstIdx++) {
7299 // Collect high parts of muls from previous DstIdx.
7300 for (unsigned i = DstIdx < SrcParts ? 0 : DstIdx - SrcParts;
7301 i <= std::min(DstIdx - 1, SrcParts - 1); ++i) {
7302 MachineInstrBuilder Umulh =
7303 B.buildUMulH(NarrowTy, Src1Regs[DstIdx - 1 - i], Src2Regs[i]);
7304 Factors.push_back(Umulh.getReg(0));
7305 }
7306 // Collect low parts of muls for DstIdx. Visit the diagonal starting with
7307 // the low Src1 part, so multiply-add selectors can use it as the first
7308 // accumulated cross product.
7309 unsigned LowStart = DstIdx + 1 < SrcParts ? 0 : DstIdx - SrcParts + 1;
7310 unsigned LowEnd = std::min(DstIdx, SrcParts - 1);
7311 for (unsigned RevI = LowEnd + 1; RevI != LowStart; --RevI) {
7312 unsigned i = RevI - 1;
7314 B.buildMul(NarrowTy, Src1Regs[DstIdx - i], Src2Regs[i]);
7315 Factors.push_back(Mul.getReg(0));
7316 }
7317 // Add CarrySum from additions calculated for previous DstIdx.
7318 if (DstIdx != 1) {
7319 Factors.push_back(CarrySumPrevDstIdx);
7320 }
7321
7322 Register CarrySum;
7323 // Add all factors and accumulate all carries into CarrySum.
7324 if (DstIdx != DstParts - 1) {
7325 MachineInstrBuilder Uaddo =
7326 B.buildUAddo(NarrowTy, LLT::integer(1), Factors[0], Factors[1]);
7327 FactorSum = Uaddo.getReg(0);
7328 CarrySum = B.buildZExt(NarrowTy, Uaddo.getReg(1)).getReg(0);
7329 for (unsigned i = 2; i < Factors.size(); ++i) {
7330 MachineInstrBuilder Uaddo =
7331 B.buildUAddo(NarrowTy, LLT::integer(1), FactorSum, Factors[i]);
7332 FactorSum = Uaddo.getReg(0);
7333 MachineInstrBuilder Carry = B.buildZExt(NarrowTy, Uaddo.getReg(1));
7334 CarrySum = B.buildAdd(NarrowTy, CarrySum, Carry).getReg(0);
7335 }
7336 } else {
7337 // Since value for the next index is not calculated, neither is CarrySum.
7338 FactorSum = B.buildAdd(NarrowTy, Factors[0], Factors[1]).getReg(0);
7339 for (unsigned i = 2; i < Factors.size(); ++i)
7340 FactorSum = B.buildAdd(NarrowTy, FactorSum, Factors[i]).getReg(0);
7341 }
7342
7343 CarrySumPrevDstIdx = CarrySum;
7344 DstRegs[DstIdx] = FactorSum;
7345 Factors.clear();
7346 }
7347}
7348
7351 LLT NarrowTy) {
7352 if (TypeIdx != 0)
7353 return UnableToLegalize;
7354
7355 Register DstReg = MI.getOperand(0).getReg();
7356 LLT DstType = MRI.getType(DstReg);
7357 // FIXME: add support for vector types
7358 if (DstType.isVector())
7359 return UnableToLegalize;
7360
7361 unsigned Opcode = MI.getOpcode();
7362 unsigned OpO, OpE, OpF;
7363 switch (Opcode) {
7364 case TargetOpcode::G_SADDO:
7365 case TargetOpcode::G_SADDE:
7366 case TargetOpcode::G_UADDO:
7367 case TargetOpcode::G_UADDE:
7368 case TargetOpcode::G_ADD:
7369 OpO = TargetOpcode::G_UADDO;
7370 OpE = TargetOpcode::G_UADDE;
7371 OpF = TargetOpcode::G_UADDE;
7372 if (Opcode == TargetOpcode::G_SADDO || Opcode == TargetOpcode::G_SADDE)
7373 OpF = TargetOpcode::G_SADDE;
7374 break;
7375 case TargetOpcode::G_SSUBO:
7376 case TargetOpcode::G_SSUBE:
7377 case TargetOpcode::G_USUBO:
7378 case TargetOpcode::G_USUBE:
7379 case TargetOpcode::G_SUB:
7380 OpO = TargetOpcode::G_USUBO;
7381 OpE = TargetOpcode::G_USUBE;
7382 OpF = TargetOpcode::G_USUBE;
7383 if (Opcode == TargetOpcode::G_SSUBO || Opcode == TargetOpcode::G_SSUBE)
7384 OpF = TargetOpcode::G_SSUBE;
7385 break;
7386 default:
7387 llvm_unreachable("Unexpected add/sub opcode!");
7388 }
7389
7390 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
7391 unsigned NumDefs = MI.getNumExplicitDefs();
7392 Register Src1 = MI.getOperand(NumDefs).getReg();
7393 Register Src2 = MI.getOperand(NumDefs + 1).getReg();
7394 Register CarryDst, CarryIn;
7395 if (NumDefs == 2)
7396 CarryDst = MI.getOperand(1).getReg();
7397 if (MI.getNumOperands() == NumDefs + 3)
7398 CarryIn = MI.getOperand(NumDefs + 2).getReg();
7399
7400 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7401 LLT LeftoverTy, DummyTy;
7402 SmallVector<Register, 2> Src1Regs, Src2Regs, Src1Left, Src2Left, DstRegs;
7403 extractParts(Src1, RegTy, NarrowTy, LeftoverTy, Src1Regs, Src1Left,
7404 MIRBuilder, MRI);
7405 extractParts(Src2, RegTy, NarrowTy, DummyTy, Src2Regs, Src2Left, MIRBuilder,
7406 MRI);
7407
7408 int NarrowParts = Src1Regs.size();
7409 Src1Regs.append(Src1Left);
7410 Src2Regs.append(Src2Left);
7411 DstRegs.reserve(Src1Regs.size());
7412
7413 for (int i = 0, e = Src1Regs.size(); i != e; ++i) {
7414 Register DstReg =
7415 MRI.createGenericVirtualRegister(MRI.getType(Src1Regs[i]));
7416 Register CarryOut;
7417 // Forward the final carry-out to the destination register
7418 if (i == e - 1 && CarryDst)
7419 CarryOut = CarryDst;
7420 else
7421 CarryOut = MRI.createGenericVirtualRegister(LLT::integer(1));
7422
7423 if (!CarryIn) {
7424 MIRBuilder.buildInstr(OpO, {DstReg, CarryOut},
7425 {Src1Regs[i], Src2Regs[i]});
7426 } else if (i == e - 1) {
7427 MIRBuilder.buildInstr(OpF, {DstReg, CarryOut},
7428 {Src1Regs[i], Src2Regs[i], CarryIn});
7429 } else {
7430 MIRBuilder.buildInstr(OpE, {DstReg, CarryOut},
7431 {Src1Regs[i], Src2Regs[i], CarryIn});
7432 }
7433
7434 DstRegs.push_back(DstReg);
7435 CarryIn = CarryOut;
7436 }
7437 insertParts(MI.getOperand(0).getReg(), RegTy, NarrowTy,
7438 ArrayRef(DstRegs).take_front(NarrowParts), LeftoverTy,
7439 ArrayRef(DstRegs).drop_front(NarrowParts));
7440
7441 MI.eraseFromParent();
7442 return Legalized;
7443}
7444
7447 auto [DstReg, Src1, Src2] = MI.getFirst3Regs();
7448
7449 LLT Ty = MRI.getType(DstReg);
7450 if (Ty.isVector())
7451 return UnableToLegalize;
7452
7453 unsigned Size = Ty.getSizeInBits();
7454 unsigned NarrowSize = NarrowTy.getSizeInBits();
7455 if (Size % NarrowSize != 0)
7456 return UnableToLegalize;
7457
7458 unsigned NumParts = Size / NarrowSize;
7459 bool IsMulHigh = MI.getOpcode() == TargetOpcode::G_UMULH;
7460 unsigned DstTmpParts = NumParts * (IsMulHigh ? 2 : 1);
7461
7462 SmallVector<Register, 2> Src1Parts, Src2Parts;
7463 SmallVector<Register, 2> DstTmpRegs(DstTmpParts);
7464 extractParts(Src1, NarrowTy, NumParts, Src1Parts, MIRBuilder, MRI);
7465 extractParts(Src2, NarrowTy, NumParts, Src2Parts, MIRBuilder, MRI);
7466 multiplyRegisters(DstTmpRegs, Src1Parts, Src2Parts, NarrowTy);
7467
7468 // Take only high half of registers if this is high mul.
7469 ArrayRef<Register> DstRegs(&DstTmpRegs[DstTmpParts - NumParts], NumParts);
7470 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7471 MI.eraseFromParent();
7472 return Legalized;
7473}
7474
7477 LLT NarrowTy) {
7478 if (TypeIdx != 0)
7479 return UnableToLegalize;
7480
7481 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI;
7482
7483 Register Src = MI.getOperand(1).getReg();
7484 LLT SrcTy = MRI.getType(Src);
7485
7486 // If all finite floats fit into the narrowed integer type, we can just swap
7487 // out the result type. This is practically only useful for conversions from
7488 // half to at least 16-bits, so just handle the one case.
7489 if (SrcTy.getScalarType() != LLT::scalar(16) ||
7490 NarrowTy.getScalarSizeInBits() < (IsSigned ? 17u : 16u))
7491 return UnableToLegalize;
7492
7493 Observer.changingInstr(MI);
7494 narrowScalarDst(MI, NarrowTy, 0,
7495 IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT);
7496 Observer.changedInstr(MI);
7497 return Legalized;
7498}
7499
7502 LLT NarrowTy) {
7503 if (TypeIdx != 1)
7504 return UnableToLegalize;
7505
7506 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7507
7508 int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
7509 // FIXME: add support for when SizeOp1 isn't an exact multiple of
7510 // NarrowSize.
7511 if (SizeOp1 % NarrowSize != 0)
7512 return UnableToLegalize;
7513 int NumParts = SizeOp1 / NarrowSize;
7514
7515 SmallVector<Register, 2> SrcRegs, DstRegs;
7516 extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs,
7517 MIRBuilder, MRI);
7518
7519 Register OpReg = MI.getOperand(0).getReg();
7520 uint64_t OpStart = MI.getOperand(2).getImm();
7521 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7522 for (int i = 0; i < NumParts; ++i) {
7523 unsigned SrcStart = i * NarrowSize;
7524
7525 if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
7526 // No part of the extract uses this subregister, ignore it.
7527 continue;
7528 } else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7529 // The entire subregister is extracted, forward the value.
7530 DstRegs.push_back(SrcRegs[i]);
7531 continue;
7532 }
7533
7534 // OpSegStart is where this destination segment would start in OpReg if it
7535 // extended infinitely in both directions.
7536 int64_t ExtractOffset;
7537 uint64_t SegSize;
7538 if (OpStart < SrcStart) {
7539 ExtractOffset = 0;
7540 SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
7541 } else {
7542 ExtractOffset = OpStart - SrcStart;
7543 SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
7544 }
7545
7546 Register SegReg = SrcRegs[i];
7547 if (ExtractOffset != 0 || SegSize != NarrowSize) {
7548 // A genuine extract is needed.
7549 SegReg = MRI.createGenericVirtualRegister(LLT::integer(SegSize));
7550 MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
7551 }
7552
7553 DstRegs.push_back(SegReg);
7554 }
7555
7556 Register DstReg = MI.getOperand(0).getReg();
7557 if (MRI.getType(DstReg).isVector())
7558 MIRBuilder.buildBuildVector(DstReg, DstRegs);
7559 else if (DstRegs.size() > 1)
7560 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7561 else
7562 MIRBuilder.buildCopy(DstReg, DstRegs[0]);
7563 MI.eraseFromParent();
7564 return Legalized;
7565}
7566
7569 LLT NarrowTy) {
7570 // FIXME: Don't know how to handle secondary types yet.
7571 if (TypeIdx != 0)
7572 return UnableToLegalize;
7573
7574 SmallVector<Register, 2> SrcRegs, LeftoverRegs, DstRegs;
7575 LLT RegTy = MRI.getType(MI.getOperand(0).getReg());
7576 LLT LeftoverTy;
7577 extractParts(MI.getOperand(1).getReg(), RegTy, NarrowTy, LeftoverTy, SrcRegs,
7578 LeftoverRegs, MIRBuilder, MRI);
7579
7580 SrcRegs.append(LeftoverRegs);
7581
7582 uint64_t NarrowSize = NarrowTy.getSizeInBits();
7583 Register OpReg = MI.getOperand(2).getReg();
7584 uint64_t OpStart = MI.getOperand(3).getImm();
7585 uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
7586 for (int I = 0, E = SrcRegs.size(); I != E; ++I) {
7587 unsigned DstStart = I * NarrowSize;
7588
7589 if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
7590 // The entire subregister is defined by this insert, forward the new
7591 // value.
7592 DstRegs.push_back(OpReg);
7593 continue;
7594 }
7595
7596 Register SrcReg = SrcRegs[I];
7597 if (MRI.getType(SrcRegs[I]) == LeftoverTy) {
7598 // The leftover reg is smaller than NarrowTy, so we need to extend it.
7599 SrcReg = MRI.createGenericVirtualRegister(NarrowTy);
7600 MIRBuilder.buildAnyExt(SrcReg, SrcRegs[I]);
7601 }
7602
7603 if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
7604 // No part of the insert affects this subregister, forward the original.
7605 DstRegs.push_back(SrcReg);
7606 continue;
7607 }
7608
7609 // OpSegStart is where this destination segment would start in OpReg if it
7610 // extended infinitely in both directions.
7611 int64_t ExtractOffset, InsertOffset;
7612 uint64_t SegSize;
7613 if (OpStart < DstStart) {
7614 InsertOffset = 0;
7615 ExtractOffset = DstStart - OpStart;
7616 SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
7617 } else {
7618 InsertOffset = OpStart - DstStart;
7619 ExtractOffset = 0;
7620 SegSize =
7621 std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
7622 }
7623
7624 Register SegReg = OpReg;
7625 if (ExtractOffset != 0 || SegSize != OpSize) {
7626 // A genuine extract is needed.
7627 SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
7628 MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
7629 }
7630
7631 Register DstReg = MRI.createGenericVirtualRegister(NarrowTy);
7632 MIRBuilder.buildInsert(DstReg, SrcReg, SegReg, InsertOffset);
7633 DstRegs.push_back(DstReg);
7634 }
7635
7636 uint64_t WideSize = DstRegs.size() * NarrowSize;
7637 Register DstReg = MI.getOperand(0).getReg();
7638 if (WideSize > RegTy.getSizeInBits()) {
7639 Register MergeReg = MRI.createGenericVirtualRegister(LLT::scalar(WideSize));
7640 MIRBuilder.buildMergeLikeInstr(MergeReg, DstRegs);
7641 MIRBuilder.buildTrunc(DstReg, MergeReg);
7642 } else
7643 MIRBuilder.buildMergeLikeInstr(DstReg, DstRegs);
7644
7645 MI.eraseFromParent();
7646 return Legalized;
7647}
7648
7651 LLT NarrowTy) {
7652 Register DstReg = MI.getOperand(0).getReg();
7653 LLT DstTy = MRI.getType(DstReg);
7654
7655 assert(MI.getNumOperands() == 3 && TypeIdx == 0);
7656
7657 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7658 SmallVector<Register, 4> Src0Regs, Src0LeftoverRegs;
7659 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7660 LLT LeftoverTy;
7661 if (!extractParts(MI.getOperand(1).getReg(), DstTy, NarrowTy, LeftoverTy,
7662 Src0Regs, Src0LeftoverRegs, MIRBuilder, MRI))
7663 return UnableToLegalize;
7664
7665 LLT Unused;
7666 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, Unused,
7667 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7668 llvm_unreachable("inconsistent extractParts result");
7669
7670 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7671 auto Inst = MIRBuilder.buildInstr(MI.getOpcode(), {NarrowTy},
7672 {Src0Regs[I], Src1Regs[I]});
7673 DstRegs.push_back(Inst.getReg(0));
7674 }
7675
7676 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7677 auto Inst = MIRBuilder.buildInstr(
7678 MI.getOpcode(),
7679 {LeftoverTy}, {Src0LeftoverRegs[I], Src1LeftoverRegs[I]});
7680 DstLeftoverRegs.push_back(Inst.getReg(0));
7681 }
7682
7683 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7684 LeftoverTy, DstLeftoverRegs);
7685
7686 MI.eraseFromParent();
7687 return Legalized;
7688}
7689
7692 LLT NarrowTy) {
7693 if (TypeIdx != 0)
7694 return UnableToLegalize;
7695
7696 auto [DstReg, SrcReg] = MI.getFirst2Regs();
7697
7698 LLT DstTy = MRI.getType(DstReg);
7699 if (DstTy.isVector())
7700 return UnableToLegalize;
7701
7703 LLT GCDTy = extractGCDType(Parts, DstTy, NarrowTy, SrcReg);
7704 LLT LCMTy = buildLCMMergePieces(DstTy, NarrowTy, GCDTy, Parts, MI.getOpcode());
7705 buildWidenedRemergeToDst(DstReg, LCMTy, Parts);
7706
7707 MI.eraseFromParent();
7708 return Legalized;
7709}
7710
7713 LLT NarrowTy) {
7714 if (TypeIdx != 0)
7715 return UnableToLegalize;
7716
7717 Register CondReg = MI.getOperand(1).getReg();
7718 LLT CondTy = MRI.getType(CondReg);
7719 if (CondTy.isVector()) // TODO: Handle vselect
7720 return UnableToLegalize;
7721
7722 Register DstReg = MI.getOperand(0).getReg();
7723 LLT DstTy = MRI.getType(DstReg);
7724
7725 SmallVector<Register, 4> DstRegs, DstLeftoverRegs;
7726 SmallVector<Register, 4> Src1Regs, Src1LeftoverRegs;
7727 SmallVector<Register, 4> Src2Regs, Src2LeftoverRegs;
7728 LLT LeftoverTy;
7729 if (!extractParts(MI.getOperand(2).getReg(), DstTy, NarrowTy, LeftoverTy,
7730 Src1Regs, Src1LeftoverRegs, MIRBuilder, MRI))
7731 return UnableToLegalize;
7732
7733 LLT Unused;
7734 if (!extractParts(MI.getOperand(3).getReg(), DstTy, NarrowTy, Unused,
7735 Src2Regs, Src2LeftoverRegs, MIRBuilder, MRI))
7736 llvm_unreachable("inconsistent extractParts result");
7737
7738 for (unsigned I = 0, E = Src1Regs.size(); I != E; ++I) {
7739 auto Select = MIRBuilder.buildSelect(NarrowTy,
7740 CondReg, Src1Regs[I], Src2Regs[I]);
7741 DstRegs.push_back(Select.getReg(0));
7742 }
7743
7744 for (unsigned I = 0, E = Src1LeftoverRegs.size(); I != E; ++I) {
7745 auto Select = MIRBuilder.buildSelect(
7746 LeftoverTy, CondReg, Src1LeftoverRegs[I], Src2LeftoverRegs[I]);
7747 DstLeftoverRegs.push_back(Select.getReg(0));
7748 }
7749
7750 insertParts(DstReg, DstTy, NarrowTy, DstRegs,
7751 LeftoverTy, DstLeftoverRegs);
7752
7753 MI.eraseFromParent();
7754 return Legalized;
7755}
7756
7759 LLT NarrowTy) {
7760 if (TypeIdx != 1)
7761 return UnableToLegalize;
7762
7763 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7764 unsigned NarrowSize = NarrowTy.getSizeInBits();
7765
7766 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7767 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_POISON;
7768
7770 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7771 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
7772 auto C_0 = B.buildConstant(NarrowTy, 0);
7773 auto HiIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7774 UnmergeSrc.getReg(1), C_0);
7775 auto LoCTLZ = IsUndef ? B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0))
7776 : B.buildCTLZ(DstTy, UnmergeSrc.getReg(0));
7777 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7778 auto HiIsZeroCTLZ = B.buildAdd(DstTy, LoCTLZ, C_NarrowSize);
7779 auto HiCTLZ = B.buildCTLZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1));
7780 B.buildSelect(DstReg, HiIsZero, HiIsZeroCTLZ, HiCTLZ);
7781
7782 MI.eraseFromParent();
7783 return Legalized;
7784 }
7785
7786 return UnableToLegalize;
7787}
7788
7791 LLT NarrowTy) {
7792 if (TypeIdx != 1)
7793 return UnableToLegalize;
7794
7795 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7796 unsigned NarrowSize = NarrowTy.getSizeInBits();
7797
7798 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7799 const bool IsUndef = MI.getOpcode() == TargetOpcode::G_CTTZ_ZERO_POISON;
7800
7802 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7803 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
7804 auto C_0 = B.buildConstant(NarrowTy, 0);
7805 auto LoIsZero = B.buildICmp(CmpInst::ICMP_EQ, LLT::integer(1),
7806 UnmergeSrc.getReg(0), C_0);
7807 auto HiCTTZ = IsUndef ? B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(1))
7808 : B.buildCTTZ(DstTy, UnmergeSrc.getReg(1));
7809 auto C_NarrowSize = B.buildConstant(DstTy, NarrowSize);
7810 auto LoIsZeroCTTZ = B.buildAdd(DstTy, HiCTTZ, C_NarrowSize);
7811 auto LoCTTZ = B.buildCTTZ_ZERO_POISON(DstTy, UnmergeSrc.getReg(0));
7812 B.buildSelect(DstReg, LoIsZero, LoIsZeroCTTZ, LoCTTZ);
7813
7814 MI.eraseFromParent();
7815 return Legalized;
7816 }
7817
7818 return UnableToLegalize;
7819}
7820
7823 LLT NarrowTy) {
7824 if (TypeIdx != 1)
7825 return UnableToLegalize;
7826
7827 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7828 unsigned NarrowSize = NarrowTy.getSizeInBits();
7829
7830 if (!SrcTy.isScalar() || SrcTy.getSizeInBits() != 2 * NarrowSize)
7831 return UnableToLegalize;
7832
7834
7835 auto UnmergeSrc = B.buildUnmerge(NarrowTy, SrcReg);
7836 Register Lo = UnmergeSrc.getReg(0);
7837 Register Hi = UnmergeSrc.getReg(1);
7838
7839 auto ShAmt = B.buildConstant(NarrowTy, NarrowSize - 1);
7840 auto Sign = B.buildAShr(NarrowTy, Hi, ShAmt);
7841
7842 auto HiIsSign = B.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1), Hi, Sign);
7843
7844 // Invert Lo if Hi is negative. Then count the leading zeros. If there are no
7845 // leading zeros, then the MSB of Lo is different than the MSB of Hi.
7846 // Otherwise the leading zeros represent additional sign bits of the original
7847 // value.
7848 auto LoInv = B.buildXor(DstTy, Lo, Sign);
7849 auto LoCTLZ = B.buildCTLZ(DstTy, LoInv);
7850
7851 // Add NarrowSize-1 to LoCTLZ. This is the full CTLS if Hi is all sign bits.
7852 auto C_NarrowSizeM1 = B.buildConstant(DstTy, NarrowSize - 1);
7853 auto HiIsSignCTLS = B.buildAdd(DstTy, LoCTLZ, C_NarrowSizeM1);
7854
7855 auto HiCTLS = B.buildCTLS(DstTy, Hi);
7856
7857 B.buildSelect(DstReg, HiIsSign, HiIsSignCTLS, HiCTLS);
7858
7859 MI.eraseFromParent();
7860 return Legalized;
7861}
7862
7865 LLT NarrowTy) {
7866 if (TypeIdx != 1)
7867 return UnableToLegalize;
7868
7869 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7870 unsigned NarrowSize = NarrowTy.getSizeInBits();
7871
7872 if (SrcTy.isScalar() && SrcTy.getSizeInBits() == 2 * NarrowSize) {
7873 auto UnmergeSrc = MIRBuilder.buildUnmerge(NarrowTy, MI.getOperand(1));
7874
7875 auto LoCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(0));
7876 auto HiCTPOP = MIRBuilder.buildCTPOP(DstTy, UnmergeSrc.getReg(1));
7877 MIRBuilder.buildAdd(DstReg, HiCTPOP, LoCTPOP);
7878
7879 MI.eraseFromParent();
7880 return Legalized;
7881 }
7882
7883 return UnableToLegalize;
7884}
7885
7888 LLT NarrowTy) {
7889 if (TypeIdx != 1)
7890 return UnableToLegalize;
7891
7893 Register ExpReg = MI.getOperand(2).getReg();
7894 LLT ExpTy = MRI.getType(ExpReg);
7895
7896 unsigned ClampSize = NarrowTy.getScalarSizeInBits();
7897
7898 // Clamp the exponent to the range of the target type.
7899 auto MinExp = B.buildConstant(ExpTy, minIntN(ClampSize));
7900 auto ClampMin = B.buildSMax(ExpTy, ExpReg, MinExp);
7901 auto MaxExp = B.buildConstant(ExpTy, maxIntN(ClampSize));
7902 auto Clamp = B.buildSMin(ExpTy, ClampMin, MaxExp);
7903
7904 auto Trunc = B.buildTrunc(NarrowTy, Clamp);
7905 Observer.changingInstr(MI);
7906 MI.getOperand(2).setReg(Trunc.getReg(0));
7907 Observer.changedInstr(MI);
7908 return Legalized;
7909}
7910
7913 unsigned Opc = MI.getOpcode();
7914 const auto &TII = MIRBuilder.getTII();
7915 auto isSupported = [this](const LegalityQuery &Q) {
7916 auto QAction = LI.getAction(Q).Action;
7917 return QAction == Legal || QAction == Libcall || QAction == Custom;
7918 };
7919 switch (Opc) {
7920 default:
7921 return UnableToLegalize;
7922 case TargetOpcode::G_CTLZ_ZERO_POISON: {
7923 // This trivially expands to CTLZ.
7924 Observer.changingInstr(MI);
7925 MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
7926 Observer.changedInstr(MI);
7927 return Legalized;
7928 }
7929 case TargetOpcode::G_CTLZ: {
7930 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7931 unsigned Len = SrcTy.getScalarSizeInBits();
7932
7933 if (isSupported({TargetOpcode::G_CTLZ_ZERO_POISON, {DstTy, SrcTy}})) {
7934 // If CTLZ_ZERO_POISON is supported, emit that and a select for zero.
7935 auto CtlzZU = MIRBuilder.buildCTLZ_ZERO_POISON(DstTy, SrcReg);
7936 auto ZeroSrc = MIRBuilder.buildConstant(SrcTy, 0);
7937 auto ICmp = MIRBuilder.buildICmp(
7938 CmpInst::ICMP_EQ, SrcTy.changeElementSize(1), SrcReg, ZeroSrc);
7939 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7940 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CtlzZU);
7941 MI.eraseFromParent();
7942 return Legalized;
7943 }
7944 // for now, we do this:
7945 // NewLen = NextPowerOf2(Len);
7946 // x = x | (x >> 1);
7947 // x = x | (x >> 2);
7948 // ...
7949 // x = x | (x >>16);
7950 // x = x | (x >>32); // for 64-bit input
7951 // Upto NewLen/2
7952 // return Len - popcount(x);
7953 //
7954 // Ref: "Hacker's Delight" by Henry Warren
7955 Register Op = SrcReg;
7956 unsigned NewLen = PowerOf2Ceil(Len);
7957 for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
7958 auto MIBShiftAmt = MIRBuilder.buildConstant(SrcTy, 1ULL << i);
7959 auto MIBOp = MIRBuilder.buildOr(
7960 SrcTy, Op, MIRBuilder.buildLShr(SrcTy, Op, MIBShiftAmt));
7961 Op = MIBOp.getReg(0);
7962 }
7963 auto MIBPop = MIRBuilder.buildCTPOP(DstTy, Op);
7964 MIRBuilder.buildSub(MI.getOperand(0), MIRBuilder.buildConstant(DstTy, Len),
7965 MIBPop);
7966 MI.eraseFromParent();
7967 return Legalized;
7968 }
7969 case TargetOpcode::G_CTTZ_ZERO_POISON: {
7970 // This trivially expands to CTTZ.
7971 Observer.changingInstr(MI);
7972 MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
7973 Observer.changedInstr(MI);
7974 return Legalized;
7975 }
7976 case TargetOpcode::G_CTTZ: {
7977 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
7978
7979 unsigned Len = SrcTy.getScalarSizeInBits();
7980 if (isSupported({TargetOpcode::G_CTTZ_ZERO_POISON, {DstTy, SrcTy}})) {
7981 // If CTTZ_ZERO_POISON is legal or custom, emit that and a select with
7982 // zero.
7983 auto CttzZU = MIRBuilder.buildCTTZ_ZERO_POISON(DstTy, SrcReg);
7984 auto Zero = MIRBuilder.buildConstant(SrcTy, 0);
7985 auto ICmp = MIRBuilder.buildICmp(
7986 CmpInst::ICMP_EQ, DstTy.changeElementSize(1), SrcReg, Zero);
7987 auto LenConst = MIRBuilder.buildConstant(DstTy, Len);
7988 MIRBuilder.buildSelect(DstReg, ICmp, LenConst, CttzZU);
7989 MI.eraseFromParent();
7990 return Legalized;
7991 }
7992 // for now, we use: { return popcount(~x & (x - 1)); }
7993 // unless the target has ctlz but not ctpop, in which case we use:
7994 // { return 32 - nlz(~x & (x-1)); }
7995 // Ref: "Hacker's Delight" by Henry Warren
7996 auto MIBCstNeg1 = MIRBuilder.buildConstant(SrcTy, -1);
7997 auto MIBNot = MIRBuilder.buildXor(SrcTy, SrcReg, MIBCstNeg1);
7998 auto MIBTmp = MIRBuilder.buildAnd(
7999 SrcTy, MIBNot, MIRBuilder.buildAdd(SrcTy, SrcReg, MIBCstNeg1));
8000 if (!isSupported({TargetOpcode::G_CTPOP, {SrcTy, SrcTy}}) &&
8001 isSupported({TargetOpcode::G_CTLZ, {SrcTy, SrcTy}})) {
8002 auto MIBCstLen = MIRBuilder.buildConstant(SrcTy, Len);
8003 MIRBuilder.buildSub(MI.getOperand(0), MIBCstLen,
8004 MIRBuilder.buildCTLZ(SrcTy, MIBTmp));
8005 MI.eraseFromParent();
8006 return Legalized;
8007 }
8008 Observer.changingInstr(MI);
8009 MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
8010 MI.getOperand(1).setReg(MIBTmp.getReg(0));
8011 Observer.changedInstr(MI);
8012 return Legalized;
8013 }
8014 case TargetOpcode::G_CTPOP: {
8015 Register SrcReg = MI.getOperand(1).getReg();
8016 LLT Ty = MRI.getType(SrcReg);
8017 unsigned Size = Ty.getScalarSizeInBits();
8019
8020 // Bail out on irregular type lengths.
8021 if (Size > 128 || Size % 8 != 0)
8022 return UnableToLegalize;
8023
8024 // Count set bits in blocks of 2 bits. Default approach would be
8025 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
8026 // We use following formula instead:
8027 // B2Count = val - { (val >> 1) & 0x55555555 }
8028 // since it gives same result in blocks of 2 with one instruction less.
8029 auto C_1 = B.buildConstant(Ty, 1);
8030 auto B2Set1LoTo1Hi = B.buildLShr(Ty, SrcReg, C_1);
8031 APInt B2Mask1HiTo0 = APInt::getSplat(Size, APInt(8, 0x55));
8032 auto C_B2Mask1HiTo0 = B.buildConstant(Ty, B2Mask1HiTo0);
8033 auto B2Count1Hi = B.buildAnd(Ty, B2Set1LoTo1Hi, C_B2Mask1HiTo0);
8034 auto B2Count = B.buildSub(Ty, SrcReg, B2Count1Hi);
8035
8036 // In order to get count in blocks of 4 add values from adjacent block of 2.
8037 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
8038 auto C_2 = B.buildConstant(Ty, 2);
8039 auto B4Set2LoTo2Hi = B.buildLShr(Ty, B2Count, C_2);
8040 APInt B4Mask2HiTo0 = APInt::getSplat(Size, APInt(8, 0x33));
8041 auto C_B4Mask2HiTo0 = B.buildConstant(Ty, B4Mask2HiTo0);
8042 auto B4HiB2Count = B.buildAnd(Ty, B4Set2LoTo2Hi, C_B4Mask2HiTo0);
8043 auto B4LoB2Count = B.buildAnd(Ty, B2Count, C_B4Mask2HiTo0);
8044 auto B4Count = B.buildAdd(Ty, B4HiB2Count, B4LoB2Count);
8045
8046 // For count in blocks of 8 bits we don't have to mask high 4 bits before
8047 // addition since count value sits in range {0,...,8} and 4 bits are enough
8048 // to hold such binary values. After addition high 4 bits still hold count
8049 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
8050 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
8051 auto C_4 = B.buildConstant(Ty, 4);
8052 auto B8HiB4Count = B.buildLShr(Ty, B4Count, C_4);
8053 auto B8CountDirty4Hi = B.buildAdd(Ty, B8HiB4Count, B4Count);
8054 APInt B8Mask4HiTo0 = APInt::getSplat(Size, APInt(8, 0x0F));
8055 auto C_B8Mask4HiTo0 = B.buildConstant(Ty, B8Mask4HiTo0);
8056 auto B8Count = B.buildAnd(Ty, B8CountDirty4Hi, C_B8Mask4HiTo0);
8057
8058 assert(Size <= 128 && "Scalar size is too large for CTPOP lower algorithm");
8059
8060 // Avoid the multiply when shift-add is cheaper.
8061 if (Size == 16 && !Ty.isVector()) {
8062 // v = (v + (v >> 8)) & 0xFF;
8063 auto C_8 = B.buildConstant(Ty, 8);
8064 auto HighSum = B.buildLShr(Ty, B8Count, C_8);
8065 auto Res = B.buildAdd(Ty, B8Count, HighSum);
8066 B.buildAnd(MI.getOperand(0).getReg(), Res, B.buildConstant(Ty, 0xFF));
8067 MI.eraseFromParent();
8068 return Legalized;
8069 }
8070
8071 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
8072 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
8073 auto MulMask = B.buildConstant(Ty, APInt::getSplat(Size, APInt(8, 0x01)));
8074
8075 // Shift count result from 8 high bits to low bits.
8076 auto C_SizeM8 = B.buildConstant(Ty, Size - 8);
8077
8078 auto IsMulSupported = [this](const LLT Ty) {
8079 auto Action = LI.getAction({TargetOpcode::G_MUL, {Ty}}).Action;
8080 return Action == Legal || Action == WidenScalar || Action == Custom;
8081 };
8082 if (IsMulSupported(Ty)) {
8083 auto ResTmp = B.buildMul(Ty, B8Count, MulMask);
8084 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8085 } else {
8086 auto ResTmp = B8Count;
8087 for (unsigned Shift = 8; Shift < Size; Shift *= 2) {
8088 auto ShiftC = B.buildConstant(Ty, Shift);
8089 auto Shl = B.buildShl(Ty, ResTmp, ShiftC);
8090 ResTmp = B.buildAdd(Ty, ResTmp, Shl);
8091 }
8092 B.buildLShr(MI.getOperand(0).getReg(), ResTmp, C_SizeM8);
8093 }
8094 MI.eraseFromParent();
8095 return Legalized;
8096 }
8097 case TargetOpcode::G_CTLS: {
8098 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8099
8100 // ctls(x) -> ctlz(x ^ (x >> (N - 1))) - 1
8101 auto SignIdxC =
8102 MIRBuilder.buildConstant(SrcTy, SrcTy.getScalarSizeInBits() - 1);
8103 auto OneC = MIRBuilder.buildConstant(DstTy, 1);
8104
8105 auto Shr = MIRBuilder.buildAShr(SrcTy, SrcReg, SignIdxC);
8106
8107 auto Xor = MIRBuilder.buildXor(SrcTy, SrcReg, Shr);
8108 auto Ctlz = MIRBuilder.buildCTLZ(DstTy, Xor);
8109
8110 MIRBuilder.buildSub(DstReg, Ctlz, OneC);
8111 MI.eraseFromParent();
8112 return Legalized;
8113 }
8114 }
8115}
8116
8117// Check that (every element of) Reg is undef or not an exact multiple of BW.
8119 Register Reg, unsigned BW) {
8120 return matchUnaryPredicate(
8121 MRI, Reg,
8122 [=](const Constant *C) {
8123 // Null constant here means an undef.
8125 return !CI || CI->getValue().urem(BW) != 0;
8126 },
8127 /*AllowUndefs*/ true);
8128}
8129
8132 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8133 LLT Ty = MRI.getType(Dst);
8134 LLT ShTy = MRI.getType(Z);
8135
8136 unsigned BW = Ty.getScalarSizeInBits();
8137
8138 if (!isPowerOf2_32(BW))
8139 return UnableToLegalize;
8140
8141 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8142 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8143
8144 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8145 // fshl X, Y, Z -> fshr X, Y, -Z
8146 // fshr X, Y, Z -> fshl X, Y, -Z
8147 auto Zero = MIRBuilder.buildConstant(ShTy, 0);
8148 Z = MIRBuilder.buildSub(Ty, Zero, Z).getReg(0);
8149 } else {
8150 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
8151 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
8152 auto One = MIRBuilder.buildConstant(ShTy, 1);
8153 if (IsFSHL) {
8154 Y = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8155 X = MIRBuilder.buildLShr(Ty, X, One).getReg(0);
8156 } else {
8157 X = MIRBuilder.buildInstr(RevOpcode, {Ty}, {X, Y, One}).getReg(0);
8158 Y = MIRBuilder.buildShl(Ty, Y, One).getReg(0);
8159 }
8160
8161 Z = MIRBuilder.buildNot(ShTy, Z).getReg(0);
8162 }
8163
8164 MIRBuilder.buildInstr(RevOpcode, {Dst}, {X, Y, Z});
8165 MI.eraseFromParent();
8166 return Legalized;
8167}
8168
8171 auto [Dst, X, Y, Z] = MI.getFirst4Regs();
8172 LLT Ty = MRI.getType(Dst);
8173 LLT ShTy = MRI.getType(Z);
8174
8175 const unsigned BW = Ty.getScalarSizeInBits();
8176 const bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8177
8178 Register ShX, ShY;
8179 Register ShAmt, InvShAmt;
8180
8181 // FIXME: Emit optimized urem by constant instead of letting it expand later.
8182 if (isNonZeroModBitWidthOrUndef(MRI, Z, BW)) {
8183 // fshl: X << C | Y >> (BW - C)
8184 // fshr: X << (BW - C) | Y >> C
8185 // where C = Z % BW is not zero
8186 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8187 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8188 InvShAmt = MIRBuilder.buildSub(ShTy, BitWidthC, ShAmt).getReg(0);
8189 ShX = MIRBuilder.buildShl(Ty, X, IsFSHL ? ShAmt : InvShAmt).getReg(0);
8190 ShY = MIRBuilder.buildLShr(Ty, Y, IsFSHL ? InvShAmt : ShAmt).getReg(0);
8191 } else {
8192 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
8193 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
8194 auto Mask = MIRBuilder.buildConstant(ShTy, BW - 1);
8195 if (isPowerOf2_32(BW)) {
8196 // Z % BW -> Z & (BW - 1)
8197 ShAmt = MIRBuilder.buildAnd(ShTy, Z, Mask).getReg(0);
8198 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
8199 auto NotZ = MIRBuilder.buildNot(ShTy, Z);
8200 InvShAmt = MIRBuilder.buildAnd(ShTy, NotZ, Mask).getReg(0);
8201 } else {
8202 auto BitWidthC = MIRBuilder.buildConstant(ShTy, BW);
8203 ShAmt = MIRBuilder.buildURem(ShTy, Z, BitWidthC).getReg(0);
8204 InvShAmt = MIRBuilder.buildSub(ShTy, Mask, ShAmt).getReg(0);
8205 }
8206
8207 auto One = MIRBuilder.buildConstant(ShTy, 1);
8208 if (IsFSHL) {
8209 ShX = MIRBuilder.buildShl(Ty, X, ShAmt).getReg(0);
8210 auto ShY1 = MIRBuilder.buildLShr(Ty, Y, One);
8211 ShY = MIRBuilder.buildLShr(Ty, ShY1, InvShAmt).getReg(0);
8212 } else {
8213 auto ShX1 = MIRBuilder.buildShl(Ty, X, One);
8214 ShX = MIRBuilder.buildShl(Ty, ShX1, InvShAmt).getReg(0);
8215 ShY = MIRBuilder.buildLShr(Ty, Y, ShAmt).getReg(0);
8216 }
8217 }
8218
8219 MIRBuilder.buildOr(Dst, ShX, ShY, MachineInstr::Disjoint);
8220 MI.eraseFromParent();
8221 return Legalized;
8222}
8223
8226 // These operations approximately do the following (while avoiding undefined
8227 // shifts by BW):
8228 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
8229 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
8230 Register Dst = MI.getOperand(0).getReg();
8231 LLT Ty = MRI.getType(Dst);
8232 LLT ShTy = MRI.getType(MI.getOperand(3).getReg());
8233
8234 bool IsFSHL = MI.getOpcode() == TargetOpcode::G_FSHL;
8235 unsigned RevOpcode = IsFSHL ? TargetOpcode::G_FSHR : TargetOpcode::G_FSHL;
8236
8237 // TODO: Use smarter heuristic that accounts for vector legalization.
8238 if (LI.getAction({RevOpcode, {Ty, ShTy}}).Action == Lower)
8239 return lowerFunnelShiftAsShifts(MI);
8240
8241 // This only works for powers of 2, fallback to shifts if it fails.
8242 LegalizerHelper::LegalizeResult Result = lowerFunnelShiftWithInverse(MI);
8243 if (Result == UnableToLegalize)
8244 return lowerFunnelShiftAsShifts(MI);
8245 return Result;
8246}
8247
8249 auto [Dst, Src] = MI.getFirst2Regs();
8250 LLT DstTy = MRI.getType(Dst);
8251 LLT SrcTy = MRI.getType(Src);
8252
8253 uint32_t DstTySize = DstTy.getSizeInBits();
8254 uint32_t DstTyScalarSize = DstTy.getScalarSizeInBits();
8255 uint32_t SrcTyScalarSize = SrcTy.getScalarSizeInBits();
8256
8257 if (!isPowerOf2_32(DstTySize) || !isPowerOf2_32(DstTyScalarSize) ||
8258 !isPowerOf2_32(SrcTyScalarSize))
8259 return UnableToLegalize;
8260
8261 // The step between extend is too large, split it by creating an intermediate
8262 // extend instruction
8263 if (SrcTyScalarSize * 2 < DstTyScalarSize) {
8264 LLT MidTy = SrcTy.changeElementSize(SrcTyScalarSize * 2);
8265 // If the destination type is illegal, split it into multiple statements
8266 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
8267 auto NewExt = MIRBuilder.buildInstr(MI.getOpcode(), {MidTy}, {Src});
8268 // Unmerge the vector
8269 LLT EltTy = MidTy.changeElementCount(
8271 auto UnmergeSrc = MIRBuilder.buildUnmerge(EltTy, NewExt);
8272
8273 // ZExt the vectors
8274 LLT ZExtResTy = DstTy.changeElementCount(
8276 auto ZExtRes1 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8277 {UnmergeSrc.getReg(0)});
8278 auto ZExtRes2 = MIRBuilder.buildInstr(MI.getOpcode(), {ZExtResTy},
8279 {UnmergeSrc.getReg(1)});
8280
8281 // Merge the ending vectors
8282 MIRBuilder.buildMergeLikeInstr(Dst, {ZExtRes1, ZExtRes2});
8283
8284 MI.eraseFromParent();
8285 return Legalized;
8286 }
8287 return UnableToLegalize;
8288}
8289
8291 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
8292 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
8293 // Similar to how operand splitting is done in SelectiondDAG, we can handle
8294 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
8295 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
8296 // %lo16(<4 x s16>) = G_TRUNC %inlo
8297 // %hi16(<4 x s16>) = G_TRUNC %inhi
8298 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
8299 // %res(<8 x s8>) = G_TRUNC %in16
8300
8301 assert(MI.getOpcode() == TargetOpcode::G_TRUNC);
8302
8303 Register DstReg = MI.getOperand(0).getReg();
8304 Register SrcReg = MI.getOperand(1).getReg();
8305 LLT DstTy = MRI.getType(DstReg);
8306 LLT SrcTy = MRI.getType(SrcReg);
8307
8308 if (DstTy.isVector() && isPowerOf2_32(DstTy.getNumElements()) &&
8310 isPowerOf2_32(SrcTy.getNumElements()) &&
8311 isPowerOf2_32(SrcTy.getScalarSizeInBits())) {
8312 // Split input type.
8313 LLT SplitSrcTy = SrcTy.changeElementCount(
8314 SrcTy.getElementCount().divideCoefficientBy(2));
8315
8316 // First, split the source into two smaller vectors.
8317 SmallVector<Register, 2> SplitSrcs;
8318 extractParts(SrcReg, SplitSrcTy, 2, SplitSrcs, MIRBuilder, MRI);
8319
8320 // Truncate the splits into intermediate narrower elements.
8321 LLT InterTy;
8322 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8323 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits() * 2);
8324 else
8325 InterTy = SplitSrcTy.changeElementSize(DstTy.getScalarSizeInBits());
8326 for (Register &Src : SplitSrcs)
8327 Src = MIRBuilder.buildTrunc(InterTy, Src).getReg(0);
8328
8329 // Combine the new truncates into one vector
8330 auto Merge = MIRBuilder.buildMergeLikeInstr(
8331 DstTy.changeElementSize(InterTy.getScalarSizeInBits()), SplitSrcs);
8332
8333 // Truncate the new vector to the final result type
8334 if (DstTy.getScalarSizeInBits() * 2 < SrcTy.getScalarSizeInBits())
8335 MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), Merge.getReg(0));
8336 else
8337 MIRBuilder.buildCopy(MI.getOperand(0).getReg(), Merge.getReg(0));
8338
8339 MI.eraseFromParent();
8340
8341 return Legalized;
8342 }
8343 return UnableToLegalize;
8344}
8345
8348 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8349 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8350 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8351 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8352 auto Neg = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8353 MIRBuilder.buildInstr(RevRot, {Dst}, {Src, Neg});
8354 MI.eraseFromParent();
8355 return Legalized;
8356}
8357
8359 auto [Dst, DstTy, Src, SrcTy, Amt, AmtTy] = MI.getFirst3RegLLTs();
8360
8361 unsigned EltSizeInBits = DstTy.getScalarSizeInBits();
8362 bool IsLeft = MI.getOpcode() == TargetOpcode::G_ROTL;
8363
8364 MIRBuilder.setInstrAndDebugLoc(MI);
8365
8366 // If a rotate in the other direction is supported, use it.
8367 unsigned RevRot = IsLeft ? TargetOpcode::G_ROTR : TargetOpcode::G_ROTL;
8368 if (LI.isLegalOrCustom({RevRot, {DstTy, SrcTy}}) &&
8369 isPowerOf2_32(EltSizeInBits))
8370 return lowerRotateWithReverseRotate(MI);
8371
8372 // If a funnel shift is supported, use it.
8373 unsigned FShOpc = IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8374 unsigned RevFsh = !IsLeft ? TargetOpcode::G_FSHL : TargetOpcode::G_FSHR;
8375 bool IsFShLegal = false;
8376 if ((IsFShLegal = LI.isLegalOrCustom({FShOpc, {DstTy, AmtTy}})) ||
8377 LI.isLegalOrCustom({RevFsh, {DstTy, AmtTy}})) {
8378 auto buildFunnelShift = [&](unsigned Opc, Register R1, Register R2,
8379 Register R3) {
8380 MIRBuilder.buildInstr(Opc, {R1}, {R2, R2, R3});
8381 MI.eraseFromParent();
8382 return Legalized;
8383 };
8384 // If a funnel shift in the other direction is supported, use it.
8385 if (IsFShLegal) {
8386 return buildFunnelShift(FShOpc, Dst, Src, Amt);
8387 } else if (isPowerOf2_32(EltSizeInBits)) {
8388 Amt = MIRBuilder.buildNeg(DstTy, Amt).getReg(0);
8389 return buildFunnelShift(RevFsh, Dst, Src, Amt);
8390 }
8391 }
8392
8393 auto Zero = MIRBuilder.buildConstant(AmtTy, 0);
8394 unsigned ShOpc = IsLeft ? TargetOpcode::G_SHL : TargetOpcode::G_LSHR;
8395 unsigned RevShiftOpc = IsLeft ? TargetOpcode::G_LSHR : TargetOpcode::G_SHL;
8396 auto BitWidthMinusOneC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits - 1);
8397 Register ShVal;
8398 Register RevShiftVal;
8399 if (isPowerOf2_32(EltSizeInBits)) {
8400 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
8401 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
8402 auto NegAmt = MIRBuilder.buildSub(AmtTy, Zero, Amt);
8403 auto ShAmt = MIRBuilder.buildAnd(AmtTy, Amt, BitWidthMinusOneC);
8404 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8405 auto RevAmt = MIRBuilder.buildAnd(AmtTy, NegAmt, BitWidthMinusOneC);
8406 RevShiftVal =
8407 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, RevAmt}).getReg(0);
8408 } else {
8409 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
8410 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
8411 auto BitWidthC = MIRBuilder.buildConstant(AmtTy, EltSizeInBits);
8412 auto ShAmt = MIRBuilder.buildURem(AmtTy, Amt, BitWidthC);
8413 ShVal = MIRBuilder.buildInstr(ShOpc, {DstTy}, {Src, ShAmt}).getReg(0);
8414 auto RevAmt = MIRBuilder.buildSub(AmtTy, BitWidthMinusOneC, ShAmt);
8415 auto One = MIRBuilder.buildConstant(AmtTy, 1);
8416 auto Inner = MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Src, One});
8417 RevShiftVal =
8418 MIRBuilder.buildInstr(RevShiftOpc, {DstTy}, {Inner, RevAmt}).getReg(0);
8419 }
8420 MIRBuilder.buildOr(Dst, ShVal, RevShiftVal, MachineInstr::Disjoint);
8421 MI.eraseFromParent();
8422 return Legalized;
8423}
8424
8425// Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
8426// representation.
8429 auto [Dst, Src] = MI.getFirst2Regs();
8430 const LLT S64 = LLT::scalar(64);
8431 const LLT S32 = LLT::scalar(32);
8432 const LLT S1 = LLT::scalar(1);
8433
8434 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8435
8436 // unsigned cul2f(ulong u) {
8437 // uint lz = clz(u);
8438 // uint e = (u != 0) ? 127U + 63U - lz : 0;
8439 // u = (u << lz) & 0x7fffffffffffffffUL;
8440 // ulong t = u & 0xffffffffffUL;
8441 // uint v = (e << 23) | (uint)(u >> 40);
8442 // uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
8443 // return as_float(v + r);
8444 // }
8445
8446 auto Zero32 = MIRBuilder.buildConstant(S32, 0);
8447 auto Zero64 = MIRBuilder.buildConstant(S64, 0);
8448
8449 auto LZ = MIRBuilder.buildCTLZ_ZERO_POISON(S32, Src);
8450
8451 auto K = MIRBuilder.buildConstant(S32, 127U + 63U);
8452 auto Sub = MIRBuilder.buildSub(S32, K, LZ);
8453
8454 auto NotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, Src, Zero64);
8455 auto E = MIRBuilder.buildSelect(S32, NotZero, Sub, Zero32);
8456
8457 auto Mask0 = MIRBuilder.buildConstant(S64, (-1ULL) >> 1);
8458 auto ShlLZ = MIRBuilder.buildShl(S64, Src, LZ);
8459
8460 auto U = MIRBuilder.buildAnd(S64, ShlLZ, Mask0);
8461
8462 auto Mask1 = MIRBuilder.buildConstant(S64, 0xffffffffffULL);
8463 auto T = MIRBuilder.buildAnd(S64, U, Mask1);
8464
8465 auto UShl = MIRBuilder.buildLShr(S64, U, MIRBuilder.buildConstant(S64, 40));
8466 auto ShlE = MIRBuilder.buildShl(S32, E, MIRBuilder.buildConstant(S32, 23));
8467 auto V = MIRBuilder.buildOr(S32, ShlE, MIRBuilder.buildTrunc(S32, UShl));
8468
8469 auto C = MIRBuilder.buildConstant(S64, 0x8000000000ULL);
8470 auto RCmp = MIRBuilder.buildICmp(CmpInst::ICMP_UGT, S1, T, C);
8471 auto TCmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, T, C);
8472 auto One = MIRBuilder.buildConstant(S32, 1);
8473
8474 auto VTrunc1 = MIRBuilder.buildAnd(S32, V, One);
8475 auto Select0 = MIRBuilder.buildSelect(S32, TCmp, VTrunc1, Zero32);
8476 auto R = MIRBuilder.buildSelect(S32, RCmp, One, Select0);
8477 MIRBuilder.buildAdd(Dst, V, R);
8478
8479 MI.eraseFromParent();
8480 return Legalized;
8481}
8482
8483// Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
8484// operations and G_SITOFP
8487 auto [Dst, Src] = MI.getFirst2Regs();
8488 const LLT S64 = LLT::scalar(64);
8489 const LLT S32 = LLT::scalar(32);
8490 const LLT S1 = LLT::scalar(1);
8491
8492 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S32);
8493
8494 // For i64 < INT_MAX we simply reuse SITOFP.
8495 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
8496 // saved before division, convert to float by SITOFP, multiply the result
8497 // by 2.
8498 auto One = MIRBuilder.buildConstant(S64, 1);
8499 auto Zero = MIRBuilder.buildConstant(S64, 0);
8500 // Result if Src < INT_MAX
8501 auto SmallResult = MIRBuilder.buildSITOFP(S32, Src);
8502 // Result if Src >= INT_MAX
8503 auto Halved = MIRBuilder.buildLShr(S64, Src, One);
8504 auto LowerBit = MIRBuilder.buildAnd(S64, Src, One);
8505 auto RoundedHalved = MIRBuilder.buildOr(S64, Halved, LowerBit);
8506 auto HalvedFP = MIRBuilder.buildSITOFP(S32, RoundedHalved);
8507 auto LargeResult = MIRBuilder.buildFAdd(S32, HalvedFP, HalvedFP);
8508 // Check if the original value is larger than INT_MAX by comparing with
8509 // zero to pick one of the two conversions.
8510 auto IsLarge =
8511 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_SLT, S1, Src, Zero);
8512 MIRBuilder.buildSelect(Dst, IsLarge, LargeResult, SmallResult);
8513
8514 MI.eraseFromParent();
8515 return Legalized;
8516}
8517
8518// Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
8519// IEEE double representation.
8522 auto [Dst, Src] = MI.getFirst2Regs();
8523 const LLT S64 = LLT::scalar(64);
8524 const LLT S32 = LLT::scalar(32);
8525
8526 assert(MRI.getType(Src) == S64 && MRI.getType(Dst) == S64);
8527
8528 // We create double value from 32 bit parts with 32 exponent difference.
8529 // Note that + and - are float operations that adjust the implicit leading
8530 // one, the bases 2^52 and 2^84 are for illustrative purposes.
8531 //
8532 // X = 2^52 * 1.0...LowBits
8533 // Y = 2^84 * 1.0...HighBits
8534 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
8535 // = - 2^52 * 1.0...HighBits
8536 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
8537 auto TwoP52 = MIRBuilder.buildConstant(S64, UINT64_C(0x4330000000000000));
8538 auto TwoP84 = MIRBuilder.buildConstant(S64, UINT64_C(0x4530000000000000));
8539 auto TwoP52P84 = llvm::bit_cast<double>(UINT64_C(0x4530000000100000));
8540 auto TwoP52P84FP = MIRBuilder.buildFConstant(S64, TwoP52P84);
8541 auto HalfWidth = MIRBuilder.buildConstant(S64, 32);
8542
8543 auto LowBits = MIRBuilder.buildTrunc(S32, Src);
8544 LowBits = MIRBuilder.buildZExt(S64, LowBits);
8545 auto LowBitsFP = MIRBuilder.buildOr(S64, TwoP52, LowBits);
8546 auto HighBits = MIRBuilder.buildLShr(S64, Src, HalfWidth);
8547 auto HighBitsFP = MIRBuilder.buildOr(S64, TwoP84, HighBits);
8548 auto Scratch = MIRBuilder.buildFSub(S64, HighBitsFP, TwoP52P84FP);
8549 MIRBuilder.buildFAdd(Dst, Scratch, LowBitsFP);
8550
8551 MI.eraseFromParent();
8552 return Legalized;
8553}
8554
8555/// i64->fp16 itofp can be lowered to i64->f64,f64->f32,f32->f16. We cannot
8556/// convert fpround f64->f16 without double-rounding, so we manually perform the
8557/// lowering here where we know it is valid.
8560 LLT SrcTy, MachineIRBuilder &MIRBuilder) {
8561 auto DstFpTy =
8562 SrcTy.changeElementType(LLT::floatIEEE(SrcTy.getScalarSizeInBits()));
8563 auto M1 = MI.getOpcode() == TargetOpcode::G_UITOFP
8564 ? MIRBuilder.buildUITOFP(DstFpTy, Src)
8565 : MIRBuilder.buildSITOFP(DstFpTy, Src);
8566 LLT F32Ty = DstFpTy.changeElementSize(32);
8567 auto M2 = MIRBuilder.buildFPTrunc(F32Ty, M1);
8568 MIRBuilder.buildFPTrunc(Dst, M2);
8569 MI.eraseFromParent();
8571}
8572
8574 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8575
8576 if (SrcTy == LLT::scalar(1)) {
8577 auto True = MIRBuilder.buildFConstant(DstTy, 1.0);
8578 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8579 MIRBuilder.buildSelect(Dst, Src, True, False);
8580 MI.eraseFromParent();
8581 return Legalized;
8582 }
8583
8584 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8585 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8586
8587 if (SrcTy != LLT::scalar(64))
8588 return UnableToLegalize;
8589
8590 if (DstTy == LLT::scalar(32))
8591 // TODO: SelectionDAG has several alternative expansions to port which may
8592 // be more reasonable depending on the available instructions. We also need
8593 // a more advanced mechanism to choose an optimal version depending on
8594 // target features such as sitofp or CTLZ availability.
8596
8597 if (DstTy == LLT::scalar(64))
8599
8600 return UnableToLegalize;
8601}
8602
8604 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8605
8606 const LLT I64 = LLT::integer(64);
8607 const LLT I32 = LLT::integer(32);
8608 const LLT I1 = LLT::integer(1);
8609
8610 if (SrcTy == I1) {
8611 auto True = MIRBuilder.buildFConstant(DstTy, -1.0);
8612 auto False = MIRBuilder.buildFConstant(DstTy, 0.0);
8613 MIRBuilder.buildSelect(Dst, Src, True, False);
8614 MI.eraseFromParent();
8615 return Legalized;
8616 }
8617
8618 if (DstTy.getScalarSizeInBits() == 16 && SrcTy.getScalarSizeInBits() == 64)
8619 return loweri64tof16ITOFP(MI, Dst, DstTy, Src, SrcTy, MIRBuilder);
8620
8621 if (SrcTy != I64)
8622 return UnableToLegalize;
8623
8624 if (DstTy.getScalarSizeInBits() == 32) {
8625 // signed cl2f(long l) {
8626 // long s = l >> 63;
8627 // float r = cul2f((l + s) ^ s);
8628 // return s ? -r : r;
8629 // }
8630 Register L = Src;
8631 auto SignBit = MIRBuilder.buildConstant(I64, 63);
8632 auto S = MIRBuilder.buildAShr(I64, L, SignBit);
8633
8634 auto LPlusS = MIRBuilder.buildAdd(I64, L, S);
8635 auto Xor = MIRBuilder.buildXor(I64, LPlusS, S);
8636 auto R = MIRBuilder.buildUITOFP(I32, Xor);
8637
8638 auto RNeg = MIRBuilder.buildFNeg(I32, R);
8639 auto SignNotZero = MIRBuilder.buildICmp(CmpInst::ICMP_NE, I1, S,
8640 MIRBuilder.buildConstant(I64, 0));
8641 MIRBuilder.buildSelect(Dst, SignNotZero, RNeg, R);
8642 MI.eraseFromParent();
8643 return Legalized;
8644 }
8645
8646 return UnableToLegalize;
8647}
8648
8650 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8651 const LLT S64 = LLT::scalar(64);
8652 const LLT S32 = LLT::scalar(32);
8653
8654 if (SrcTy != S64 && SrcTy != S32)
8655 return UnableToLegalize;
8656 if (DstTy != S32 && DstTy != S64)
8657 return UnableToLegalize;
8658
8659 // FPTOSI gives same result as FPTOUI for positive signed integers.
8660 // FPTOUI needs to deal with fp values that convert to unsigned integers
8661 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
8662
8663 APInt TwoPExpInt = APInt::getSignMask(DstTy.getSizeInBits());
8664 APFloat TwoPExpFP(SrcTy.getSizeInBits() == 32 ? APFloat::IEEEsingle()
8666 APInt::getZero(SrcTy.getSizeInBits()));
8667 TwoPExpFP.convertFromAPInt(TwoPExpInt, false, APFloat::rmNearestTiesToEven);
8668
8669 MachineInstrBuilder FPTOSI = MIRBuilder.buildFPTOSI(DstTy, Src);
8670
8671 MachineInstrBuilder Threshold = MIRBuilder.buildFConstant(SrcTy, TwoPExpFP);
8672 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
8673 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
8674 MachineInstrBuilder FSub = MIRBuilder.buildFSub(SrcTy, Src, Threshold);
8675 MachineInstrBuilder ResLowBits = MIRBuilder.buildFPTOSI(DstTy, FSub);
8676 MachineInstrBuilder ResHighBit = MIRBuilder.buildConstant(DstTy, TwoPExpInt);
8677 MachineInstrBuilder Res = MIRBuilder.buildXor(DstTy, ResLowBits, ResHighBit);
8678
8679 const LLT S1 = LLT::scalar(1);
8680
8681 MachineInstrBuilder FCMP =
8682 MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, S1, Src, Threshold);
8683 MIRBuilder.buildSelect(Dst, FCMP, FPTOSI, Res);
8684
8685 MI.eraseFromParent();
8686 return Legalized;
8687}
8688
8690 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8691 const LLT S64 = LLT::scalar(64);
8692 const LLT S32 = LLT::scalar(32);
8693
8694 // FIXME: Only f32 to i64 conversions are supported.
8695 if (SrcTy.getScalarType() != S32 || DstTy.getScalarType() != S64)
8696 return UnableToLegalize;
8697
8698 // Expand f32 -> i64 conversion
8699 // This algorithm comes from compiler-rt's implementation of fixsfdi:
8700 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
8701
8702 unsigned SrcEltBits = SrcTy.getScalarSizeInBits();
8703
8704 auto ExponentMask = MIRBuilder.buildConstant(SrcTy, 0x7F800000);
8705 auto ExponentLoBit = MIRBuilder.buildConstant(SrcTy, 23);
8706
8707 auto AndExpMask = MIRBuilder.buildAnd(SrcTy, Src, ExponentMask);
8708 auto ExponentBits = MIRBuilder.buildLShr(SrcTy, AndExpMask, ExponentLoBit);
8709
8710 auto SignMask = MIRBuilder.buildConstant(SrcTy,
8711 APInt::getSignMask(SrcEltBits));
8712 auto AndSignMask = MIRBuilder.buildAnd(SrcTy, Src, SignMask);
8713 auto SignLowBit = MIRBuilder.buildConstant(SrcTy, SrcEltBits - 1);
8714 auto Sign = MIRBuilder.buildAShr(SrcTy, AndSignMask, SignLowBit);
8715 Sign = MIRBuilder.buildSExt(DstTy, Sign);
8716
8717 auto MantissaMask = MIRBuilder.buildConstant(SrcTy, 0x007FFFFF);
8718 auto AndMantissaMask = MIRBuilder.buildAnd(SrcTy, Src, MantissaMask);
8719 auto K = MIRBuilder.buildConstant(SrcTy, 0x00800000);
8720
8721 auto R = MIRBuilder.buildOr(SrcTy, AndMantissaMask, K);
8722 R = MIRBuilder.buildZExt(DstTy, R);
8723
8724 auto Bias = MIRBuilder.buildConstant(SrcTy, 127);
8725 auto Exponent = MIRBuilder.buildSub(SrcTy, ExponentBits, Bias);
8726 auto SubExponent = MIRBuilder.buildSub(SrcTy, Exponent, ExponentLoBit);
8727 auto ExponentSub = MIRBuilder.buildSub(SrcTy, ExponentLoBit, Exponent);
8728
8729 auto Shl = MIRBuilder.buildShl(DstTy, R, SubExponent);
8730 auto Srl = MIRBuilder.buildLShr(DstTy, R, ExponentSub);
8731
8732 const LLT S1 = LLT::scalar(1);
8733 auto CmpGt = MIRBuilder.buildICmp(CmpInst::ICMP_SGT,
8734 S1, Exponent, ExponentLoBit);
8735
8736 R = MIRBuilder.buildSelect(DstTy, CmpGt, Shl, Srl);
8737
8738 auto XorSign = MIRBuilder.buildXor(DstTy, R, Sign);
8739 auto Ret = MIRBuilder.buildSub(DstTy, XorSign, Sign);
8740
8741 auto ZeroSrcTy = MIRBuilder.buildConstant(SrcTy, 0);
8742
8743 auto ExponentLt0 = MIRBuilder.buildICmp(CmpInst::ICMP_SLT,
8744 S1, Exponent, ZeroSrcTy);
8745
8746 auto ZeroDstTy = MIRBuilder.buildConstant(DstTy, 0);
8747 MIRBuilder.buildSelect(Dst, ExponentLt0, ZeroDstTy, Ret);
8748
8749 MI.eraseFromParent();
8750 return Legalized;
8751}
8752
8755 auto [Dst, DstTy, Src, SrcTy] = MI.getFirst2RegLLTs();
8756
8757 bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI_SAT;
8758 unsigned SatWidth = DstTy.getScalarSizeInBits();
8759
8760 // Determine minimum and maximum integer values and their corresponding
8761 // floating-point values.
8762 APInt MinInt, MaxInt;
8763 if (IsSigned) {
8764 MinInt = APInt::getSignedMinValue(SatWidth);
8765 MaxInt = APInt::getSignedMaxValue(SatWidth);
8766 } else {
8767 MinInt = APInt::getMinValue(SatWidth);
8768 MaxInt = APInt::getMaxValue(SatWidth);
8769 }
8770
8771 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
8772 APFloat MinFloat(Semantics);
8773 APFloat MaxFloat(Semantics);
8774
8775 APFloat::opStatus MinStatus =
8776 MinFloat.convertFromAPInt(MinInt, IsSigned, APFloat::rmTowardZero);
8777 APFloat::opStatus MaxStatus =
8778 MaxFloat.convertFromAPInt(MaxInt, IsSigned, APFloat::rmTowardZero);
8779 bool AreExactFloatBounds = !(MinStatus & APFloat::opStatus::opInexact) &&
8780 !(MaxStatus & APFloat::opStatus::opInexact);
8781
8782 // If the integer bounds are exactly representable as floats, emit a
8783 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
8784 // and selects.
8785 if (AreExactFloatBounds) {
8786 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
8787 auto MaxC = MIRBuilder.buildFConstant(SrcTy, MinFloat);
8788 auto MaxP =
8789 MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src, MaxC);
8790 auto Max = MIRBuilder.buildSelect(SrcTy, MaxP, Src, MaxC);
8791 // Clamp by MaxFloat from above. NaN cannot occur.
8792 auto MinC = MIRBuilder.buildFConstant(SrcTy, MaxFloat);
8793 auto MinP = MIRBuilder.buildFCmp(CmpInst::FCMP_OLT, LLT::integer(1), Max,
8795 auto Min =
8796 MIRBuilder.buildSelect(SrcTy, MinP, Max, MinC, MachineInstr::FmNoNans);
8797 // Convert clamped value to integer. In the unsigned case we're done,
8798 // because we mapped NaN to MinFloat, which will cast to zero.
8799 if (!IsSigned) {
8800 MIRBuilder.buildFPTOUI(Dst, Min);
8801 MI.eraseFromParent();
8802 return Legalized;
8803 }
8804
8805 // Otherwise, select 0 if Src is NaN.
8806 auto FpToInt = MIRBuilder.buildFPTOSI(DstTy, Min);
8807 auto IsZero =
8808 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8809 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0),
8810 FpToInt);
8811 MI.eraseFromParent();
8812 return Legalized;
8813 }
8814
8815 // Result of direct conversion. The assumption here is that the operation is
8816 // non-trapping and it's fine to apply it to an out-of-range value if we
8817 // select it away later.
8818 auto FpToInt = IsSigned ? MIRBuilder.buildFPTOSI(DstTy, Src)
8819 : MIRBuilder.buildFPTOUI(DstTy, Src);
8820
8821 // If Src ULT MinFloat, select MinInt. In particular, this also selects
8822 // MinInt if Src is NaN.
8823 auto ULT = MIRBuilder.buildFCmp(CmpInst::FCMP_ULT, LLT::integer(1), Src,
8824 MIRBuilder.buildFConstant(SrcTy, MinFloat));
8825 auto Max = MIRBuilder.buildSelect(
8826 DstTy, ULT, MIRBuilder.buildConstant(DstTy, MinInt), FpToInt);
8827 // If Src OGT MaxFloat, select MaxInt.
8828 auto OGT = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, LLT::integer(1), Src,
8829 MIRBuilder.buildFConstant(SrcTy, MaxFloat));
8830
8831 // In the unsigned case we are done, because we mapped NaN to MinInt, which
8832 // is already zero.
8833 if (!IsSigned) {
8834 MIRBuilder.buildSelect(Dst, OGT, MIRBuilder.buildConstant(DstTy, MaxInt),
8835 Max);
8836 MI.eraseFromParent();
8837 return Legalized;
8838 }
8839
8840 // Otherwise, select 0 if Src is NaN.
8841 auto Min = MIRBuilder.buildSelect(
8842 DstTy, OGT, MIRBuilder.buildConstant(DstTy, MaxInt), Max);
8843 auto IsZero =
8844 MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, LLT::integer(1), Src, Src);
8845 MIRBuilder.buildSelect(Dst, IsZero, MIRBuilder.buildConstant(DstTy, 0), Min);
8846 MI.eraseFromParent();
8847 return Legalized;
8848}
8849
8850// Floating-point conversions using truncating and extending loads and stores.
8853 assert((MI.getOpcode() == TargetOpcode::G_FPEXT ||
8854 MI.getOpcode() == TargetOpcode::G_FPTRUNC) &&
8855 "Only G_FPEXT and G_FPTRUNC are expected");
8856
8857 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8858 MachinePointerInfo PtrInfo;
8859 unsigned StoreOpc;
8860 unsigned LoadOpc;
8861 LLT StackTy;
8862 if (MI.getOpcode() == TargetOpcode::G_FPEXT) {
8863 StackTy = SrcTy;
8864 StoreOpc = TargetOpcode::G_STORE;
8865 LoadOpc = TargetOpcode::G_FPEXTLOAD;
8866 } else {
8867 StackTy = DstTy;
8868 StoreOpc = TargetOpcode::G_FPTRUNCSTORE;
8869 LoadOpc = TargetOpcode::G_LOAD;
8870 }
8871
8872 Align StackTyAlign = getStackTemporaryAlignment(StackTy);
8873 auto StackTemp =
8874 createStackTemporary(StackTy.getSizeInBytes(), StackTyAlign, PtrInfo);
8875
8876 MachineFunction &MF = MIRBuilder.getMF();
8877 auto *StoreMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOStore,
8878 StackTy, StackTyAlign);
8879 MIRBuilder.buildStoreInstr(StoreOpc, SrcReg, StackTemp, *StoreMMO);
8880
8881 auto *LoadMMO = MF.getMachineMemOperand(PtrInfo, MachineMemOperand::MOLoad,
8882 StackTy, StackTyAlign);
8883 MIRBuilder.buildLoadInstr(LoadOpc, DstReg, StackTemp, *LoadMMO);
8884
8885 MI.eraseFromParent();
8886 return Legalized;
8887}
8888
8889// Expand a bf16 -> f32/f64 fpext with a shift and bitcast. This is based on the
8890// SDAG ISD::BF16_TO_FP lowering.
8893 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
8894 assert(SrcTy.getScalarType().isBFloat16() &&
8895 "expected a bf16 source for bf16 fpext lowering");
8896
8897 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
8898 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
8899 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
8900
8901 auto SrcI =
8902 MIRBuilder.buildAnyExt(I32Ty, MIRBuilder.buildBitcast(I16Ty, SrcReg));
8903 auto Shl =
8904 MIRBuilder.buildShl(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
8905
8906 if (DstTy.getScalarType().isFloat32())
8907 MIRBuilder.buildBitcast(DstReg, Shl);
8908 else
8909 MIRBuilder.buildFPExt(DstReg, MIRBuilder.buildBitcast(F32Ty, Shl));
8910
8911 MI.eraseFromParent();
8912 return Legalized;
8913}
8914
8916 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
8917 if (SrcTy.getScalarType().isBFloat16() &&
8918 (DstTy.getScalarType().isFloat32() || DstTy.getScalarType().isFloat64()))
8919 return lowerFPEXT_BF16(MI);
8920
8921 return lowerFPExtAndTruncMem(MI);
8922}
8923
8924// f64 -> f16 conversion using round-to-nearest-even rounding mode.
8927 const LLT S1 = LLT::scalar(1);
8928 const LLT I32 = LLT::integer(32);
8929
8930 auto [Dst, Src] = MI.getFirst2Regs();
8931 assert(MRI.getType(Dst).getScalarType() == LLT::float16() &&
8932 MRI.getType(Src).getScalarType() == LLT::float64());
8933
8934 if (MRI.getType(Src).isVector()) // TODO: Handle vectors directly.
8935 return UnableToLegalize;
8936
8937 if (MI.getFlag(MachineInstr::FmAfn)) {
8938 unsigned Flags = MI.getFlags();
8939 auto Src32 = MIRBuilder.buildFPTrunc(LLT::float32(), Src, Flags);
8940 MIRBuilder.buildFPTrunc(Dst, Src32, Flags);
8941 MI.eraseFromParent();
8942 return Legalized;
8943 }
8944
8945 const unsigned ExpMask = 0x7ff;
8946 const unsigned ExpBiasf64 = 1023;
8947 const unsigned ExpBiasf16 = 15;
8948
8949 auto Unmerge = MIRBuilder.buildUnmerge(I32, Src);
8950 Register U = Unmerge.getReg(0);
8951 Register UH = Unmerge.getReg(1);
8952
8953 auto E = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 20));
8954 E = MIRBuilder.buildAnd(I32, E, MIRBuilder.buildConstant(I32, ExpMask));
8955
8956 // Subtract the fp64 exponent bias (1023) to get the real exponent and
8957 // add the f16 bias (15) to get the biased exponent for the f16 format.
8958 E = MIRBuilder.buildAdd(
8959 I32, E, MIRBuilder.buildConstant(I32, -ExpBiasf64 + ExpBiasf16));
8960
8961 auto M = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 8));
8962 M = MIRBuilder.buildAnd(I32, M, MIRBuilder.buildConstant(I32, 0xffe));
8963
8964 auto MaskedSig =
8965 MIRBuilder.buildAnd(I32, UH, MIRBuilder.buildConstant(I32, 0x1ff));
8966 MaskedSig = MIRBuilder.buildOr(I32, MaskedSig, U);
8967
8968 auto Zero = MIRBuilder.buildConstant(I32, 0);
8969 auto SigCmpNE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, MaskedSig, Zero);
8970 auto Lo40Set = MIRBuilder.buildZExt(I32, SigCmpNE0);
8971 M = MIRBuilder.buildOr(I32, M, Lo40Set);
8972
8973 // (M != 0 ? 0x0200 : 0) | 0x7c00;
8974 auto Bits0x200 = MIRBuilder.buildConstant(I32, 0x0200);
8975 auto CmpM_NE0 = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1, M, Zero);
8976 auto SelectCC = MIRBuilder.buildSelect(I32, CmpM_NE0, Bits0x200, Zero);
8977
8978 auto Bits0x7c00 = MIRBuilder.buildConstant(I32, 0x7c00);
8979 auto I = MIRBuilder.buildOr(I32, SelectCC, Bits0x7c00);
8980
8981 // N = M | (E << 12);
8982 auto EShl12 = MIRBuilder.buildShl(I32, E, MIRBuilder.buildConstant(I32, 12));
8983 auto N = MIRBuilder.buildOr(I32, M, EShl12);
8984
8985 // B = clamp(1-E, 0, 13);
8986 auto One = MIRBuilder.buildConstant(I32, 1);
8987 auto OneSubExp = MIRBuilder.buildSub(I32, One, E);
8988 auto B = MIRBuilder.buildSMax(I32, OneSubExp, Zero);
8989 B = MIRBuilder.buildSMin(I32, B, MIRBuilder.buildConstant(I32, 13));
8990
8991 auto SigSetHigh =
8992 MIRBuilder.buildOr(I32, M, MIRBuilder.buildConstant(I32, 0x1000));
8993
8994 auto D = MIRBuilder.buildLShr(I32, SigSetHigh, B);
8995 auto D0 = MIRBuilder.buildShl(I32, D, B);
8996
8997 auto D0_NE_SigSetHigh = MIRBuilder.buildICmp(CmpInst::ICMP_NE, S1,
8998 D0, SigSetHigh);
8999 auto D1 = MIRBuilder.buildZExt(I32, D0_NE_SigSetHigh);
9000 D = MIRBuilder.buildOr(I32, D, D1);
9001
9002 auto CmpELtOne = MIRBuilder.buildICmp(CmpInst::ICMP_SLT, S1, E, One);
9003 auto V = MIRBuilder.buildSelect(I32, CmpELtOne, D, N);
9004
9005 auto VLow3 = MIRBuilder.buildAnd(I32, V, MIRBuilder.buildConstant(I32, 7));
9006 V = MIRBuilder.buildLShr(I32, V, MIRBuilder.buildConstant(I32, 2));
9007
9008 auto VLow3Eq3 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, VLow3,
9009 MIRBuilder.buildConstant(I32, 3));
9010 auto V0 = MIRBuilder.buildZExt(I32, VLow3Eq3);
9011
9012 auto VLow3Gt5 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, VLow3,
9013 MIRBuilder.buildConstant(I32, 5));
9014 auto V1 = MIRBuilder.buildZExt(I32, VLow3Gt5);
9015
9016 V1 = MIRBuilder.buildOr(I32, V0, V1);
9017 V = MIRBuilder.buildAdd(I32, V, V1);
9018
9019 auto CmpEGt30 = MIRBuilder.buildICmp(CmpInst::ICMP_SGT, S1, E,
9020 MIRBuilder.buildConstant(I32, 30));
9021 V = MIRBuilder.buildSelect(I32, CmpEGt30,
9022 MIRBuilder.buildConstant(I32, 0x7c00), V);
9023
9024 auto CmpEGt1039 = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, S1, E,
9025 MIRBuilder.buildConstant(I32, 1039));
9026 V = MIRBuilder.buildSelect(I32, CmpEGt1039, I, V);
9027
9028 // Extract the sign bit.
9029 auto Sign = MIRBuilder.buildLShr(I32, UH, MIRBuilder.buildConstant(I32, 16));
9030 Sign = MIRBuilder.buildAnd(I32, Sign, MIRBuilder.buildConstant(I32, 0x8000));
9031
9032 // Insert the sign bit
9033 V = MIRBuilder.buildOr(I32, Sign, V);
9034
9035 MIRBuilder.buildTrunc(Dst, V);
9036 MI.eraseFromParent();
9037 return Legalized;
9038}
9039
9040// f32 -> bf16 conversion using round-to-nearest-even rounding mode.
9043 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9044 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9045 SrcTy.getScalarType() == LLT::float32());
9046
9047 LLT I1Ty = SrcTy.changeElementType(LLT::integer(1));
9048 LLT I16Ty = SrcTy.changeElementType(LLT::integer(16));
9049 LLT I32Ty = SrcTy.changeElementType(LLT::integer(32));
9050
9051 auto SrcI = MIRBuilder.buildBitcast(I32Ty, SrcReg);
9052
9053 // Conversions should set NaN's quiet bit. This also prevents NaNs from
9054 // turning into infinities.
9055 auto NaN = MIRBuilder.buildOr(I32Ty, SrcI,
9056 MIRBuilder.buildConstant(I32Ty, 0x400000));
9057
9058 // Factor in the contribution of the low 16 bits.
9059 auto Lsb =
9060 MIRBuilder.buildLShr(I32Ty, SrcI, MIRBuilder.buildConstant(I32Ty, 16));
9061 Lsb = MIRBuilder.buildAnd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 1));
9062 auto RoundingBias =
9063 MIRBuilder.buildAdd(I32Ty, Lsb, MIRBuilder.buildConstant(I32Ty, 0x7fff));
9064 auto Add = MIRBuilder.buildAdd(I32Ty, SrcI, RoundingBias);
9065
9066 // Don't round if we had a NaN, we don't want to turn 0x7fffffff into
9067 // 0x80000000.
9068 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9069 auto IsNaN = MIRBuilder.buildFCmp(CmpInst::FCMP_UNO, I1Ty, SrcReg,
9070 MIRBuilder.buildFConstant(SrcTy, 0));
9071 Add = MIRBuilder.buildSelect(I32Ty, IsNaN, NaN, Add);
9072 }
9073
9074 // Now that we have rounded, shift the bits into position.
9075 auto Srl =
9076 MIRBuilder.buildLShr(I32Ty, Add, MIRBuilder.buildConstant(I32Ty, 16));
9077 auto Trunc = MIRBuilder.buildTrunc(I16Ty, Srl);
9078 MIRBuilder.buildBitcast(DstReg, Trunc);
9079 MI.eraseFromParent();
9080 return Legalized;
9081}
9082
9083// Round a wide fp value to ResultTy's element size, forcing inexact
9084// results to the odd value so a subsequent narrowing round is correct. This
9085// avoids double-rounding when narrowing e.g. f64 -> f32 -> bf16. See Boldo &
9086// Melquiond, "When double rounding is odd" (2005).
9088 LLT OperandTy = MRI.getType(Op);
9089 if (OperandTy.getScalarType() == ResultTy.getScalarType())
9090 return Op;
9091
9092 LLT ResultIntTy =
9094 LLT ResultCCTy = ResultTy.changeElementType(LLT::integer(1));
9095 LLT OperandCCTy = OperandTy.changeElementType(LLT::integer(1));
9096
9097 auto Narrow = MIRBuilder.buildFPTrunc(ResultTy, Op);
9098 auto NarrowAsWide = MIRBuilder.buildFPExt(OperandTy, Narrow);
9099
9100 auto NarrowBits = MIRBuilder.buildBitcast(ResultIntTy, Narrow);
9101 auto One = MIRBuilder.buildConstant(ResultIntTy, 1);
9102 auto NegativeOne = MIRBuilder.buildConstant(ResultIntTy, -1);
9103 auto Zero = MIRBuilder.buildConstant(ResultIntTy, 0);
9104 auto And = MIRBuilder.buildAnd(ResultIntTy, NarrowBits, One);
9105 // The result is already odd so we don't need to do anything.
9106 auto AlreadyOdd =
9107 MIRBuilder.buildICmp(CmpInst::ICMP_NE, ResultCCTy, And, Zero);
9108
9109 // We keep results which are exact, odd or NaN.
9110 auto KeepNarrow =
9111 MIRBuilder.buildFCmp(CmpInst::FCMP_UEQ, OperandCCTy, Op, NarrowAsWide);
9112 KeepNarrow = MIRBuilder.buildOr(OperandCCTy, KeepNarrow, AlreadyOdd);
9113 // We morally performed a round-down if AbsNarrow is smaller than AbsWide.
9114 auto AbsWide = MIRBuilder.buildFAbs(OperandTy, Op);
9115 auto AbsNarrowAsWide = MIRBuilder.buildFAbs(OperandTy, NarrowAsWide);
9116 auto NarrowIsRd = MIRBuilder.buildFCmp(CmpInst::FCMP_OGT, OperandCCTy,
9117 AbsWide, AbsNarrowAsWide);
9118 // If narrow is the rounded-down value, pick the rounded-up value as it will
9119 // be odd; otherwise adjust down.
9120 auto Adjust =
9121 MIRBuilder.buildSelect(ResultIntTy, NarrowIsRd, One, NegativeOne);
9122 auto Adjusted = MIRBuilder.buildAdd(ResultIntTy, NarrowBits, Adjust);
9123 auto Res =
9124 MIRBuilder.buildSelect(ResultIntTy, KeepNarrow, NarrowBits, Adjusted);
9125 return MIRBuilder.buildBitcast(ResultTy, Res).getReg(0);
9126}
9127
9128// f64 -> bf16 conversion, correcting for double rounding.
9131 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
9132 assert(DstTy.getScalarType() == LLT::bfloat16() &&
9133 SrcTy.getScalarType() == LLT::float64());
9134
9135 LLT F32Ty = SrcTy.changeElementType(LLT::float32());
9136 Register OddF32 = lowerRoundInexactToOdd(F32Ty, SrcReg);
9137 MIRBuilder.buildFPTrunc(DstReg, OddF32, MI.getFlags());
9138 MI.eraseFromParent();
9139 return Legalized;
9140}
9141
9144 auto [DstTy, SrcTy] = MI.getFirst2LLTs();
9145 if (DstTy.getScalarType().isFloat16() && SrcTy.getScalarType().isFloat64())
9147
9148 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat32())
9150
9151 if (DstTy.getScalarType().isBFloat16() && SrcTy.getScalarType().isFloat64())
9153
9154 return lowerFPExtAndTruncMem(MI);
9155}
9156
9158 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9159 LLT Ty = MRI.getType(Dst);
9160
9161 auto CvtSrc1 = MIRBuilder.buildSITOFP(Ty, Src1);
9162 MIRBuilder.buildFPow(Dst, Src0, CvtSrc1, MI.getFlags());
9163 MI.eraseFromParent();
9164 return Legalized;
9165}
9166
9168 auto [DstFrac, DstInt, Src] = MI.getFirst3Regs();
9169 LLT Ty = MRI.getType(Src);
9170 auto Flags = MI.getFlags();
9171 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9172
9173 auto IntPart = MIRBuilder.buildIntrinsicTrunc(Ty, Src, Flags);
9174 auto FracPart = MIRBuilder.buildFSub(Ty, Src, IntPart, Flags);
9175
9176 Register FracToUse;
9177 if (MI.getFlag(MachineInstr::FmNoInfs)) {
9178 FracToUse = FracPart.getReg(0);
9179 } else {
9180 auto Abs = MIRBuilder.buildFAbs(Ty, Src, Flags);
9181 const fltSemantics &Semantics = getFltSemanticForLLT(Ty.getScalarType());
9182 auto Inf = MIRBuilder.buildFConstant(Ty, APFloat::getInf(Semantics));
9183 auto IsInf = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CondTy, Abs, Inf);
9184 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9185 auto Select = MIRBuilder.buildSelect(Ty, IsInf, Zero, FracPart);
9186 FracToUse = Select.getReg(0);
9187 }
9188
9189 MIRBuilder.buildFCopysign(DstFrac, FracToUse, Src, Flags);
9190 MIRBuilder.buildCopy(DstInt, IntPart.getReg(0));
9191
9192 MI.eraseFromParent();
9193 return Legalized;
9194}
9195
9197 switch (Opc) {
9198 case TargetOpcode::G_SMIN:
9199 return CmpInst::ICMP_SLT;
9200 case TargetOpcode::G_SMAX:
9201 return CmpInst::ICMP_SGT;
9202 case TargetOpcode::G_UMIN:
9203 return CmpInst::ICMP_ULT;
9204 case TargetOpcode::G_UMAX:
9205 return CmpInst::ICMP_UGT;
9206 default:
9207 llvm_unreachable("not in integer min/max");
9208 }
9209}
9210
9212 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9213
9214 const CmpInst::Predicate Pred = minMaxToCompare(MI.getOpcode());
9215 LLT CmpType = MRI.getType(Dst).changeElementType(LLT::integer(1));
9216
9217 auto Cmp = MIRBuilder.buildICmp(Pred, CmpType, Src0, Src1);
9218 MIRBuilder.buildSelect(Dst, Cmp, Src0, Src1);
9219
9220 MI.eraseFromParent();
9221 return Legalized;
9222}
9223
9226 GSUCmp *Cmp = cast<GSUCmp>(&MI);
9227
9228 Register Dst = Cmp->getReg(0);
9229 LLT DstTy = MRI.getType(Dst);
9230 LLT SrcTy = MRI.getType(Cmp->getReg(1));
9231 LLT CmpTy = DstTy.changeElementSize(1);
9232
9233 CmpInst::Predicate LTPredicate = Cmp->isSigned()
9236 CmpInst::Predicate GTPredicate = Cmp->isSigned()
9239
9240 auto Zero = MIRBuilder.buildConstant(DstTy, 0);
9241 auto IsGT = MIRBuilder.buildICmp(GTPredicate, CmpTy, Cmp->getLHSReg(),
9242 Cmp->getRHSReg());
9243 auto IsLT = MIRBuilder.buildICmp(LTPredicate, CmpTy, Cmp->getLHSReg(),
9244 Cmp->getRHSReg());
9245
9246 auto &Ctx = MIRBuilder.getMF().getFunction().getContext();
9247 auto BC = TLI.getBooleanContents(DstTy.isVector(), /*isFP=*/false);
9248 if (TLI.preferSelectsOverBooleanArithmetic(
9249 getApproximateEVTForLLT(SrcTy, Ctx)) ||
9251 auto One = MIRBuilder.buildConstant(DstTy, 1);
9252 auto SelectZeroOrOne = MIRBuilder.buildSelect(DstTy, IsGT, One, Zero);
9253
9254 auto MinusOne = MIRBuilder.buildConstant(DstTy, -1);
9255 MIRBuilder.buildSelect(Dst, IsLT, MinusOne, SelectZeroOrOne);
9256 } else {
9258 std::swap(IsGT, IsLT);
9259 // Extend boolean results to DstTy, which is at least i2, before subtracting
9260 // them.
9261 unsigned BoolExtOp =
9262 MIRBuilder.getBoolExtOp(DstTy.isVector(), /*isFP=*/false);
9263 IsGT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsGT});
9264 IsLT = MIRBuilder.buildInstr(BoolExtOp, {DstTy}, {IsLT});
9265 MIRBuilder.buildSub(Dst, IsGT, IsLT);
9266 }
9267
9268 MI.eraseFromParent();
9269 return Legalized;
9270}
9271
9274 auto [Dst, DstTy, Src0, Src0Ty, Src1, Src1Ty] = MI.getFirst3RegLLTs();
9275 const int Src0Size = Src0Ty.getScalarSizeInBits();
9276 const int Src1Size = Src1Ty.getScalarSizeInBits();
9277
9278 LLT DstIntTy =
9279 DstTy.changeElementType(LLT::integer(DstTy.getScalarSizeInBits()));
9280 LLT Src0IntTy = Src0Ty.changeElementType(LLT::integer(Src0Size));
9281 LLT Src1IntTy = Src1Ty.changeElementType(LLT::integer(Src1Size));
9282
9283 Register Src0Int = Src0;
9284 Register Src1Int = Src1;
9285
9286 if (!(Src0Ty.getScalarType().isAnyScalar() ||
9287 Src0Ty.getScalarType().isInteger()))
9288 Src0Int = MIRBuilder.buildBitcast(Src0IntTy, Src0).getReg(0);
9289
9290 if (!(Src1Ty.getScalarType().isAnyScalar() ||
9291 Src1Ty.getScalarType().isInteger()))
9292 Src1Int = MIRBuilder.buildBitcast(Src1IntTy, Src1).getReg(0);
9293
9294 auto SignBitMask =
9295 MIRBuilder.buildConstant(Src0IntTy, APInt::getSignMask(Src0Size));
9296
9297 auto NotSignBitMask = MIRBuilder.buildConstant(
9298 Src0IntTy, APInt::getLowBitsSet(Src0Size, Src0Size - 1));
9299
9300 Register And0 =
9301 MIRBuilder.buildAnd(Src0IntTy, Src0Int, NotSignBitMask).getReg(0);
9302 Register And1;
9303 if (Src0Ty == Src1Ty) {
9304 And1 = MIRBuilder.buildAnd(Src1IntTy, Src1Int, SignBitMask).getReg(0);
9305 } else if (Src0Size > Src1Size) {
9306 auto ShiftAmt = MIRBuilder.buildConstant(Src0IntTy, Src0Size - Src1Size);
9307 auto Zext = MIRBuilder.buildZExt(Src0IntTy, Src1Int);
9308 auto Shift = MIRBuilder.buildShl(Src0IntTy, Zext, ShiftAmt);
9309 And1 = MIRBuilder.buildAnd(Src0IntTy, Shift, SignBitMask).getReg(0);
9310 } else {
9311 auto ShiftAmt = MIRBuilder.buildConstant(Src1IntTy, Src1Size - Src0Size);
9312 auto Shift = MIRBuilder.buildLShr(Src1IntTy, Src1Int, ShiftAmt);
9313 auto Trunc = MIRBuilder.buildTrunc(Src0IntTy, Shift);
9314 And1 = MIRBuilder.buildAnd(Src0IntTy, Trunc, SignBitMask).getReg(0);
9315 }
9316
9317 // Be careful about setting nsz/nnan/ninf on every instruction, since the
9318 // constants are a nan and -0.0, but the final result should preserve
9319 // everything.
9320 unsigned Flags = MI.getFlags();
9321
9322 // We masked the sign bit and the not-sign bit, so these are disjoint.
9323 Flags |= MachineInstr::Disjoint;
9324
9325 if (DstTy == DstIntTy)
9326 MIRBuilder.buildOr(Dst, And0, And1, Flags).getReg(0);
9327 else {
9328 Register NewDst = MIRBuilder.buildOr(DstIntTy, And0, And1, Flags).getReg(0);
9329 MIRBuilder.buildBitcast(Dst, NewDst);
9330 }
9331
9332 MI.eraseFromParent();
9333 return Legalized;
9334}
9335
9338 // FIXME: fminnum/fmaxnum and fminimumnum/fmaximumnum should not have
9339 // identical handling. fminimumnum/fmaximumnum also need a path that do not
9340 // depend on fminnum/fmaxnum.
9341
9342 unsigned NewOp;
9343 switch (MI.getOpcode()) {
9344 case TargetOpcode::G_FMINNUM:
9345 NewOp = TargetOpcode::G_FMINNUM_IEEE;
9346 break;
9347 case TargetOpcode::G_FMINIMUMNUM:
9348 NewOp = TargetOpcode::G_FMINNUM;
9349 break;
9350 case TargetOpcode::G_FMAXNUM:
9351 NewOp = TargetOpcode::G_FMAXNUM_IEEE;
9352 break;
9353 case TargetOpcode::G_FMAXIMUMNUM:
9354 NewOp = TargetOpcode::G_FMAXNUM;
9355 break;
9356 default:
9357 llvm_unreachable("unexpected min/max opcode");
9358 }
9359
9360 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9361 LLT Ty = MRI.getType(Dst);
9362
9363 if (!MI.getFlag(MachineInstr::FmNoNans)) {
9364 // Insert canonicalizes if it's possible we need to quiet to get correct
9365 // sNaN behavior.
9366
9367 // Note this must be done here, and not as an optimization combine in the
9368 // absence of a dedicate quiet-snan instruction as we're using an
9369 // omni-purpose G_FCANONICALIZE.
9370 if (!VT->isKnownNeverSNaN(Src0))
9371 Src0 = MIRBuilder.buildFCanonicalize(Ty, Src0, MI.getFlags()).getReg(0);
9372
9373 if (!VT->isKnownNeverSNaN(Src1))
9374 Src1 = MIRBuilder.buildFCanonicalize(Ty, Src1, MI.getFlags()).getReg(0);
9375 }
9376
9377 // If there are no nans, it's safe to simply replace this with the non-IEEE
9378 // version.
9379 MIRBuilder.buildInstr(NewOp, {Dst}, {Src0, Src1}, MI.getFlags());
9380 MI.eraseFromParent();
9381 return Legalized;
9382}
9383
9386 unsigned Opc = MI.getOpcode();
9387 auto [Dst, Src0, Src1] = MI.getFirst3Regs();
9388 LLT Ty = MRI.getType(Dst);
9389 const LLT CmpTy = Ty.changeElementType(LLT::integer(1));
9390
9391 bool IsMax = (Opc == TargetOpcode::G_FMAXIMUM);
9392 unsigned OpcIeee =
9393 IsMax ? TargetOpcode::G_FMAXNUM_IEEE : TargetOpcode::G_FMINNUM_IEEE;
9394 unsigned OpcNonIeee =
9395 IsMax ? TargetOpcode::G_FMAXNUM : TargetOpcode::G_FMINNUM;
9396 bool MinMaxMustRespectOrderedZero = false;
9397 Register Res;
9398
9399 // IEEE variants don't need canonicalization
9400 if (LI.isLegalOrCustom({OpcIeee, Ty})) {
9401 Res = MIRBuilder.buildInstr(OpcIeee, {Ty}, {Src0, Src1}).getReg(0);
9402 MinMaxMustRespectOrderedZero = true;
9403 } else if (LI.isLegalOrCustom({OpcNonIeee, Ty})) {
9404 Res = MIRBuilder.buildInstr(OpcNonIeee, {Ty}, {Src0, Src1}).getReg(0);
9405 } else {
9406 auto Compare = MIRBuilder.buildFCmp(
9407 IsMax ? CmpInst::FCMP_OGT : CmpInst::FCMP_OLT, CmpTy, Src0, Src1);
9408 Res = MIRBuilder.buildSelect(Ty, Compare, Src0, Src1).getReg(0);
9409 }
9410
9411 // Propagate any NaN of both operands
9412 if (!MI.getFlag(MachineInstr::FmNoNans) &&
9413 (!VT->isKnownNeverNaN(Src0) || !VT->isKnownNeverNaN(Src1))) {
9414 auto IsOrdered = MIRBuilder.buildFCmp(CmpInst::FCMP_ORD, CmpTy, Src0, Src1);
9415
9416 LLT ElementTy = Ty.isScalar() ? Ty : Ty.getElementType();
9417 APFloat NaNValue = APFloat::getNaN(getFltSemanticForLLT(ElementTy));
9418 Register NaN = MIRBuilder.buildFConstant(ElementTy, NaNValue).getReg(0);
9419 if (Ty.isVector())
9420 NaN = MIRBuilder.buildSplatBuildVector(Ty, NaN).getReg(0);
9421
9422 Res = MIRBuilder.buildSelect(Ty, IsOrdered, Res, NaN).getReg(0);
9423 }
9424
9425 // fminimum/fmaximum requires -0.0 less than +0.0
9426 if (!MinMaxMustRespectOrderedZero && !MI.getFlag(MachineInstr::FmNsz)) {
9427 GISelValueTracking VT(MIRBuilder.getMF());
9428 KnownFPClass Src0Info = VT.computeKnownFPClass(Src0, fcZero);
9429 KnownFPClass Src1Info = VT.computeKnownFPClass(Src1, fcZero);
9430
9431 if (!Src0Info.isKnownNeverZero() && !Src1Info.isKnownNeverZero()) {
9432 const unsigned Flags = MI.getFlags();
9433 Register Zero = MIRBuilder.buildFConstant(Ty, 0.0).getReg(0);
9434 auto IsZero = MIRBuilder.buildFCmp(CmpInst::FCMP_OEQ, CmpTy, Res, Zero);
9435
9436 unsigned TestClass = IsMax ? fcPosZero : fcNegZero;
9437
9438 auto LHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src0, TestClass);
9439 auto LHSSelect =
9440 MIRBuilder.buildSelect(Ty, LHSTestZero, Src0, Res, Flags);
9441
9442 auto RHSTestZero = MIRBuilder.buildIsFPClass(CmpTy, Src1, TestClass);
9443 auto RHSSelect =
9444 MIRBuilder.buildSelect(Ty, RHSTestZero, Src1, LHSSelect, Flags);
9445
9446 Res = MIRBuilder.buildSelect(Ty, IsZero, RHSSelect, Res, Flags).getReg(0);
9447 }
9448 }
9449
9450 MIRBuilder.buildCopy(Dst, Res);
9451 MI.eraseFromParent();
9452 return Legalized;
9453}
9454
9456 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
9457 Register DstReg = MI.getOperand(0).getReg();
9458 LLT Ty = MRI.getType(DstReg);
9459 unsigned Flags = MI.getFlags();
9460
9461 auto Mul = MIRBuilder.buildFMul(Ty, MI.getOperand(1), MI.getOperand(2),
9462 Flags);
9463 MIRBuilder.buildFAdd(DstReg, Mul, MI.getOperand(3), Flags);
9464 MI.eraseFromParent();
9465 return Legalized;
9466}
9467
9470 auto [DstReg, X] = MI.getFirst2Regs();
9471 const unsigned Flags = MI.getFlags();
9472 const LLT Ty = MRI.getType(DstReg);
9473 const LLT CondTy = Ty.changeElementType(LLT::integer(1));
9474
9475 // round(x) =>
9476 // t = trunc(x);
9477 // d = fabs(x - t);
9478 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
9479 // return t + o;
9480
9481 auto T = MIRBuilder.buildIntrinsicTrunc(Ty, X, Flags);
9482
9483 auto Diff = MIRBuilder.buildFSub(Ty, X, T, Flags);
9484 auto AbsDiff = MIRBuilder.buildFAbs(Ty, Diff, Flags);
9485
9486 auto Half = MIRBuilder.buildFConstant(Ty, 0.5);
9487 auto Cmp =
9488 MIRBuilder.buildFCmp(CmpInst::FCMP_OGE, CondTy, AbsDiff, Half, Flags);
9489
9490 // Could emit G_UITOFP instead
9491 auto One = MIRBuilder.buildFConstant(Ty, 1.0);
9492 auto Zero = MIRBuilder.buildFConstant(Ty, 0.0);
9493 auto BoolFP = MIRBuilder.buildSelect(Ty, Cmp, One, Zero);
9494 auto SignedOffset = MIRBuilder.buildFCopysign(Ty, BoolFP, X);
9495
9496 MIRBuilder.buildFAdd(DstReg, T, SignedOffset, Flags);
9497
9498 MI.eraseFromParent();
9499 return Legalized;
9500}
9501