1 //===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
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
7 //===----------------------------------------------------------------------===//
9 /// \file This file implements the LegalizerHelper class to legalize
10 /// individual instructions and the LegalizeMachineIR wrapper pass for the
11 /// primary legalization.
13 //===----------------------------------------------------------------------===//
15 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
16 #include "llvm/CodeGen/GlobalISel/CallLowering.h"
17 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
18 #include "llvm/CodeGen/GlobalISel/GISelKnownBits.h"
19 #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
20 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
21 #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h"
22 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
23 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
24 #include "llvm/CodeGen/GlobalISel/Utils.h"
25 #include "llvm/CodeGen/LowLevelTypeUtils.h"
26 #include "llvm/CodeGen/MachineConstantPool.h"
27 #include "llvm/CodeGen/MachineFrameInfo.h"
28 #include "llvm/CodeGen/MachineRegisterInfo.h"
29 #include "llvm/CodeGen/RuntimeLibcallUtil.h"
30 #include "llvm/CodeGen/TargetFrameLowering.h"
31 #include "llvm/CodeGen/TargetInstrInfo.h"
32 #include "llvm/CodeGen/TargetLowering.h"
33 #include "llvm/CodeGen/TargetOpcodes.h"
34 #include "llvm/CodeGen/TargetSubtargetInfo.h"
35 #include "llvm/IR/Instructions.h"
36 #include "llvm/Support/Debug.h"
37 #include "llvm/Support/MathExtras.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Target/TargetMachine.h"
43 #define DEBUG_TYPE "legalizer"
46 using namespace LegalizeActions
;
47 using namespace MIPatternMatch
;
49 /// Try to break down \p OrigTy into \p NarrowTy sized pieces.
51 /// Returns the number of \p NarrowTy elements needed to reconstruct \p OrigTy,
52 /// with any leftover piece as type \p LeftoverTy
54 /// Returns -1 in the first element of the pair if the breakdown is not
56 static std::pair
<int, int>
57 getNarrowTypeBreakDown(LLT OrigTy
, LLT NarrowTy
, LLT
&LeftoverTy
) {
58 assert(!LeftoverTy
.isValid() && "this is an out argument");
60 unsigned Size
= OrigTy
.getSizeInBits();
61 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
62 unsigned NumParts
= Size
/ NarrowSize
;
63 unsigned LeftoverSize
= Size
- NumParts
* NarrowSize
;
64 assert(Size
> NarrowSize
);
66 if (LeftoverSize
== 0)
69 if (NarrowTy
.isVector()) {
70 unsigned EltSize
= OrigTy
.getScalarSizeInBits();
71 if (LeftoverSize
% EltSize
!= 0)
74 LLT::scalarOrVector(ElementCount::getFixed(LeftoverSize
/ EltSize
),
75 OrigTy
.getElementType());
77 LeftoverTy
= LLT::scalar(LeftoverSize
);
80 int NumLeftover
= LeftoverSize
/ LeftoverTy
.getSizeInBits();
81 return std::make_pair(NumParts
, NumLeftover
);
84 static Type
*getFloatTypeForLLT(LLVMContext
&Ctx
, LLT Ty
) {
89 switch (Ty
.getSizeInBits()) {
91 return Type::getHalfTy(Ctx
);
93 return Type::getFloatTy(Ctx
);
95 return Type::getDoubleTy(Ctx
);
97 return Type::getX86_FP80Ty(Ctx
);
99 return Type::getFP128Ty(Ctx
);
105 LegalizerHelper::LegalizerHelper(MachineFunction
&MF
,
106 GISelChangeObserver
&Observer
,
107 MachineIRBuilder
&Builder
)
108 : MIRBuilder(Builder
), Observer(Observer
), MRI(MF
.getRegInfo()),
109 LI(*MF
.getSubtarget().getLegalizerInfo()),
110 TLI(*MF
.getSubtarget().getTargetLowering()), KB(nullptr) {}
112 LegalizerHelper::LegalizerHelper(MachineFunction
&MF
, const LegalizerInfo
&LI
,
113 GISelChangeObserver
&Observer
,
114 MachineIRBuilder
&B
, GISelKnownBits
*KB
)
115 : MIRBuilder(B
), Observer(Observer
), MRI(MF
.getRegInfo()), LI(LI
),
116 TLI(*MF
.getSubtarget().getTargetLowering()), KB(KB
) {}
118 LegalizerHelper::LegalizeResult
119 LegalizerHelper::legalizeInstrStep(MachineInstr
&MI
,
120 LostDebugLocObserver
&LocObserver
) {
121 LLVM_DEBUG(dbgs() << "Legalizing: " << MI
);
123 MIRBuilder
.setInstrAndDebugLoc(MI
);
125 if (isa
<GIntrinsic
>(MI
))
126 return LI
.legalizeIntrinsic(*this, MI
) ? Legalized
: UnableToLegalize
;
127 auto Step
= LI
.getAction(MI
, MRI
);
128 switch (Step
.Action
) {
130 LLVM_DEBUG(dbgs() << ".. Already legal\n");
133 LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
134 return libcall(MI
, LocObserver
);
136 LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
137 return narrowScalar(MI
, Step
.TypeIdx
, Step
.NewType
);
139 LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
140 return widenScalar(MI
, Step
.TypeIdx
, Step
.NewType
);
142 LLVM_DEBUG(dbgs() << ".. Bitcast type\n");
143 return bitcast(MI
, Step
.TypeIdx
, Step
.NewType
);
145 LLVM_DEBUG(dbgs() << ".. Lower\n");
146 return lower(MI
, Step
.TypeIdx
, Step
.NewType
);
148 LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
149 return fewerElementsVector(MI
, Step
.TypeIdx
, Step
.NewType
);
151 LLVM_DEBUG(dbgs() << ".. Increase number of elements\n");
152 return moreElementsVector(MI
, Step
.TypeIdx
, Step
.NewType
);
154 LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
155 return LI
.legalizeCustom(*this, MI
, LocObserver
) ? Legalized
158 LLVM_DEBUG(dbgs() << ".. Unable to legalize\n");
159 return UnableToLegalize
;
163 void LegalizerHelper::insertParts(Register DstReg
,
164 LLT ResultTy
, LLT PartTy
,
165 ArrayRef
<Register
> PartRegs
,
167 ArrayRef
<Register
> LeftoverRegs
) {
168 if (!LeftoverTy
.isValid()) {
169 assert(LeftoverRegs
.empty());
171 if (!ResultTy
.isVector()) {
172 MIRBuilder
.buildMergeLikeInstr(DstReg
, PartRegs
);
176 if (PartTy
.isVector())
177 MIRBuilder
.buildConcatVectors(DstReg
, PartRegs
);
179 MIRBuilder
.buildBuildVector(DstReg
, PartRegs
);
183 // Merge sub-vectors with different number of elements and insert into DstReg.
184 if (ResultTy
.isVector()) {
185 assert(LeftoverRegs
.size() == 1 && "Expected one leftover register");
186 SmallVector
<Register
, 8> AllRegs(PartRegs
.begin(), PartRegs
.end());
187 AllRegs
.append(LeftoverRegs
.begin(), LeftoverRegs
.end());
188 return mergeMixedSubvectors(DstReg
, AllRegs
);
191 SmallVector
<Register
> GCDRegs
;
192 LLT GCDTy
= getGCDType(getGCDType(ResultTy
, LeftoverTy
), PartTy
);
193 for (auto PartReg
: concat
<const Register
>(PartRegs
, LeftoverRegs
))
194 extractGCDType(GCDRegs
, GCDTy
, PartReg
);
195 LLT ResultLCMTy
= buildLCMMergePieces(ResultTy
, LeftoverTy
, GCDTy
, GCDRegs
);
196 buildWidenedRemergeToDst(DstReg
, ResultLCMTy
, GCDRegs
);
199 void LegalizerHelper::appendVectorElts(SmallVectorImpl
<Register
> &Elts
,
201 LLT Ty
= MRI
.getType(Reg
);
202 SmallVector
<Register
, 8> RegElts
;
203 extractParts(Reg
, Ty
.getScalarType(), Ty
.getNumElements(), RegElts
,
205 Elts
.append(RegElts
);
208 /// Merge \p PartRegs with different types into \p DstReg.
209 void LegalizerHelper::mergeMixedSubvectors(Register DstReg
,
210 ArrayRef
<Register
> PartRegs
) {
211 SmallVector
<Register
, 8> AllElts
;
212 for (unsigned i
= 0; i
< PartRegs
.size() - 1; ++i
)
213 appendVectorElts(AllElts
, PartRegs
[i
]);
215 Register Leftover
= PartRegs
[PartRegs
.size() - 1];
216 if (!MRI
.getType(Leftover
).isVector())
217 AllElts
.push_back(Leftover
);
219 appendVectorElts(AllElts
, Leftover
);
221 MIRBuilder
.buildMergeLikeInstr(DstReg
, AllElts
);
224 /// Append the result registers of G_UNMERGE_VALUES \p MI to \p Regs.
225 static void getUnmergeResults(SmallVectorImpl
<Register
> &Regs
,
226 const MachineInstr
&MI
) {
227 assert(MI
.getOpcode() == TargetOpcode::G_UNMERGE_VALUES
);
229 const int StartIdx
= Regs
.size();
230 const int NumResults
= MI
.getNumOperands() - 1;
231 Regs
.resize(Regs
.size() + NumResults
);
232 for (int I
= 0; I
!= NumResults
; ++I
)
233 Regs
[StartIdx
+ I
] = MI
.getOperand(I
).getReg();
236 void LegalizerHelper::extractGCDType(SmallVectorImpl
<Register
> &Parts
,
237 LLT GCDTy
, Register SrcReg
) {
238 LLT SrcTy
= MRI
.getType(SrcReg
);
239 if (SrcTy
== GCDTy
) {
240 // If the source already evenly divides the result type, we don't need to do
242 Parts
.push_back(SrcReg
);
244 // Need to split into common type sized pieces.
245 auto Unmerge
= MIRBuilder
.buildUnmerge(GCDTy
, SrcReg
);
246 getUnmergeResults(Parts
, *Unmerge
);
250 LLT
LegalizerHelper::extractGCDType(SmallVectorImpl
<Register
> &Parts
, LLT DstTy
,
251 LLT NarrowTy
, Register SrcReg
) {
252 LLT SrcTy
= MRI
.getType(SrcReg
);
253 LLT GCDTy
= getGCDType(getGCDType(SrcTy
, NarrowTy
), DstTy
);
254 extractGCDType(Parts
, GCDTy
, SrcReg
);
258 LLT
LegalizerHelper::buildLCMMergePieces(LLT DstTy
, LLT NarrowTy
, LLT GCDTy
,
259 SmallVectorImpl
<Register
> &VRegs
,
260 unsigned PadStrategy
) {
261 LLT LCMTy
= getLCMType(DstTy
, NarrowTy
);
263 int NumParts
= LCMTy
.getSizeInBits() / NarrowTy
.getSizeInBits();
264 int NumSubParts
= NarrowTy
.getSizeInBits() / GCDTy
.getSizeInBits();
265 int NumOrigSrc
= VRegs
.size();
269 // Get a value we can use to pad the source value if the sources won't evenly
270 // cover the result type.
271 if (NumOrigSrc
< NumParts
* NumSubParts
) {
272 if (PadStrategy
== TargetOpcode::G_ZEXT
)
273 PadReg
= MIRBuilder
.buildConstant(GCDTy
, 0).getReg(0);
274 else if (PadStrategy
== TargetOpcode::G_ANYEXT
)
275 PadReg
= MIRBuilder
.buildUndef(GCDTy
).getReg(0);
277 assert(PadStrategy
== TargetOpcode::G_SEXT
);
279 // Shift the sign bit of the low register through the high register.
281 MIRBuilder
.buildConstant(LLT::scalar(64), GCDTy
.getSizeInBits() - 1);
282 PadReg
= MIRBuilder
.buildAShr(GCDTy
, VRegs
.back(), ShiftAmt
).getReg(0);
286 // Registers for the final merge to be produced.
287 SmallVector
<Register
, 4> Remerge(NumParts
);
289 // Registers needed for intermediate merges, which will be merged into a
290 // source for Remerge.
291 SmallVector
<Register
, 4> SubMerge(NumSubParts
);
293 // Once we've fully read off the end of the original source bits, we can reuse
294 // the same high bits for remaining padding elements.
297 // Build merges to the LCM type to cover the original result type.
298 for (int I
= 0; I
!= NumParts
; ++I
) {
299 bool AllMergePartsArePadding
= true;
301 // Build the requested merges to the requested type.
302 for (int J
= 0; J
!= NumSubParts
; ++J
) {
303 int Idx
= I
* NumSubParts
+ J
;
304 if (Idx
>= NumOrigSrc
) {
305 SubMerge
[J
] = PadReg
;
309 SubMerge
[J
] = VRegs
[Idx
];
311 // There are meaningful bits here we can't reuse later.
312 AllMergePartsArePadding
= false;
315 // If we've filled up a complete piece with padding bits, we can directly
316 // emit the natural sized constant if applicable, rather than a merge of
317 // smaller constants.
318 if (AllMergePartsArePadding
&& !AllPadReg
) {
319 if (PadStrategy
== TargetOpcode::G_ANYEXT
)
320 AllPadReg
= MIRBuilder
.buildUndef(NarrowTy
).getReg(0);
321 else if (PadStrategy
== TargetOpcode::G_ZEXT
)
322 AllPadReg
= MIRBuilder
.buildConstant(NarrowTy
, 0).getReg(0);
324 // If this is a sign extension, we can't materialize a trivial constant
325 // with the right type and have to produce a merge.
329 // Avoid creating additional instructions if we're just adding additional
330 // copies of padding bits.
331 Remerge
[I
] = AllPadReg
;
335 if (NumSubParts
== 1)
336 Remerge
[I
] = SubMerge
[0];
338 Remerge
[I
] = MIRBuilder
.buildMergeLikeInstr(NarrowTy
, SubMerge
).getReg(0);
340 // In the sign extend padding case, re-use the first all-signbit merge.
341 if (AllMergePartsArePadding
&& !AllPadReg
)
342 AllPadReg
= Remerge
[I
];
345 VRegs
= std::move(Remerge
);
349 void LegalizerHelper::buildWidenedRemergeToDst(Register DstReg
, LLT LCMTy
,
350 ArrayRef
<Register
> RemergeRegs
) {
351 LLT DstTy
= MRI
.getType(DstReg
);
353 // Create the merge to the widened source, and extract the relevant bits into
356 if (DstTy
== LCMTy
) {
357 MIRBuilder
.buildMergeLikeInstr(DstReg
, RemergeRegs
);
361 auto Remerge
= MIRBuilder
.buildMergeLikeInstr(LCMTy
, RemergeRegs
);
362 if (DstTy
.isScalar() && LCMTy
.isScalar()) {
363 MIRBuilder
.buildTrunc(DstReg
, Remerge
);
367 if (LCMTy
.isVector()) {
368 unsigned NumDefs
= LCMTy
.getSizeInBits() / DstTy
.getSizeInBits();
369 SmallVector
<Register
, 8> UnmergeDefs(NumDefs
);
370 UnmergeDefs
[0] = DstReg
;
371 for (unsigned I
= 1; I
!= NumDefs
; ++I
)
372 UnmergeDefs
[I
] = MRI
.createGenericVirtualRegister(DstTy
);
374 MIRBuilder
.buildUnmerge(UnmergeDefs
,
375 MIRBuilder
.buildMergeLikeInstr(LCMTy
, RemergeRegs
));
379 llvm_unreachable("unhandled case");
382 static RTLIB::Libcall
getRTLibDesc(unsigned Opcode
, unsigned Size
) {
383 #define RTLIBCASE_INT(LibcallPrefix) \
387 return RTLIB::LibcallPrefix##32; \
389 return RTLIB::LibcallPrefix##64; \
391 return RTLIB::LibcallPrefix##128; \
393 llvm_unreachable("unexpected size"); \
397 #define RTLIBCASE(LibcallPrefix) \
401 return RTLIB::LibcallPrefix##32; \
403 return RTLIB::LibcallPrefix##64; \
405 return RTLIB::LibcallPrefix##80; \
407 return RTLIB::LibcallPrefix##128; \
409 llvm_unreachable("unexpected size"); \
414 case TargetOpcode::G_MUL
:
415 RTLIBCASE_INT(MUL_I
);
416 case TargetOpcode::G_SDIV
:
417 RTLIBCASE_INT(SDIV_I
);
418 case TargetOpcode::G_UDIV
:
419 RTLIBCASE_INT(UDIV_I
);
420 case TargetOpcode::G_SREM
:
421 RTLIBCASE_INT(SREM_I
);
422 case TargetOpcode::G_UREM
:
423 RTLIBCASE_INT(UREM_I
);
424 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
425 RTLIBCASE_INT(CTLZ_I
);
426 case TargetOpcode::G_FADD
:
428 case TargetOpcode::G_FSUB
:
430 case TargetOpcode::G_FMUL
:
432 case TargetOpcode::G_FDIV
:
434 case TargetOpcode::G_FEXP
:
436 case TargetOpcode::G_FEXP2
:
438 case TargetOpcode::G_FEXP10
:
440 case TargetOpcode::G_FREM
:
442 case TargetOpcode::G_FPOW
:
444 case TargetOpcode::G_FPOWI
:
446 case TargetOpcode::G_FMA
:
448 case TargetOpcode::G_FSIN
:
450 case TargetOpcode::G_FCOS
:
452 case TargetOpcode::G_FTAN
:
454 case TargetOpcode::G_FASIN
:
456 case TargetOpcode::G_FACOS
:
458 case TargetOpcode::G_FATAN
:
460 case TargetOpcode::G_FATAN2
:
462 case TargetOpcode::G_FSINH
:
464 case TargetOpcode::G_FCOSH
:
466 case TargetOpcode::G_FTANH
:
468 case TargetOpcode::G_FLOG10
:
470 case TargetOpcode::G_FLOG
:
472 case TargetOpcode::G_FLOG2
:
474 case TargetOpcode::G_FLDEXP
:
476 case TargetOpcode::G_FCEIL
:
478 case TargetOpcode::G_FFLOOR
:
480 case TargetOpcode::G_FMINNUM
:
482 case TargetOpcode::G_FMAXNUM
:
484 case TargetOpcode::G_FSQRT
:
486 case TargetOpcode::G_FRINT
:
488 case TargetOpcode::G_FNEARBYINT
:
489 RTLIBCASE(NEARBYINT_F
);
490 case TargetOpcode::G_INTRINSIC_TRUNC
:
492 case TargetOpcode::G_INTRINSIC_ROUND
:
494 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
:
495 RTLIBCASE(ROUNDEVEN_F
);
496 case TargetOpcode::G_INTRINSIC_LRINT
:
498 case TargetOpcode::G_INTRINSIC_LLRINT
:
501 llvm_unreachable("Unknown libcall function");
506 /// True if an instruction is in tail position in its caller. Intended for
507 /// legalizing libcalls as tail calls when possible.
508 static bool isLibCallInTailPosition(const CallLowering::ArgInfo
&Result
,
510 const TargetInstrInfo
&TII
,
511 MachineRegisterInfo
&MRI
) {
512 MachineBasicBlock
&MBB
= *MI
.getParent();
513 const Function
&F
= MBB
.getParent()->getFunction();
515 // Conservatively require the attributes of the call to match those of
516 // the return. Ignore NoAlias and NonNull because they don't affect the
518 AttributeList CallerAttrs
= F
.getAttributes();
519 if (AttrBuilder(F
.getContext(), CallerAttrs
.getRetAttrs())
520 .removeAttribute(Attribute::NoAlias
)
521 .removeAttribute(Attribute::NonNull
)
525 // It's not safe to eliminate the sign / zero extension of the return value.
526 if (CallerAttrs
.hasRetAttr(Attribute::ZExt
) ||
527 CallerAttrs
.hasRetAttr(Attribute::SExt
))
530 // Only tail call if the following instruction is a standard return or if we
531 // have a `thisreturn` callee, and a sequence like:
533 // G_MEMCPY %0, %1, %2
535 // RET_ReallyLR implicit $x0
536 auto Next
= next_nodbg(MI
.getIterator(), MBB
.instr_end());
537 if (Next
!= MBB
.instr_end() && Next
->isCopy()) {
538 if (MI
.getOpcode() == TargetOpcode::G_BZERO
)
541 // For MEMCPY/MOMMOVE/MEMSET these will be the first use (the dst), as the
542 // mempy/etc routines return the same parameter. For other it will be the
544 Register VReg
= MI
.getOperand(0).getReg();
545 if (!VReg
.isVirtual() || VReg
!= Next
->getOperand(1).getReg())
548 Register PReg
= Next
->getOperand(0).getReg();
549 if (!PReg
.isPhysical())
552 auto Ret
= next_nodbg(Next
, MBB
.instr_end());
553 if (Ret
== MBB
.instr_end() || !Ret
->isReturn())
556 if (Ret
->getNumImplicitOperands() != 1)
559 if (!Ret
->getOperand(0).isReg() || PReg
!= Ret
->getOperand(0).getReg())
562 // Skip over the COPY that we just validated.
566 if (Next
== MBB
.instr_end() || TII
.isTailCall(*Next
) || !Next
->isReturn())
572 LegalizerHelper::LegalizeResult
573 llvm::createLibcall(MachineIRBuilder
&MIRBuilder
, const char *Name
,
574 const CallLowering::ArgInfo
&Result
,
575 ArrayRef
<CallLowering::ArgInfo
> Args
,
576 const CallingConv::ID CC
, LostDebugLocObserver
&LocObserver
,
578 auto &CLI
= *MIRBuilder
.getMF().getSubtarget().getCallLowering();
580 CallLowering::CallLoweringInfo Info
;
582 Info
.Callee
= MachineOperand::CreateES(Name
);
583 Info
.OrigRet
= Result
;
586 (Result
.Ty
->isVoidTy() ||
587 Result
.Ty
== MIRBuilder
.getMF().getFunction().getReturnType()) &&
588 isLibCallInTailPosition(Result
, *MI
, MIRBuilder
.getTII(),
589 *MIRBuilder
.getMRI());
591 std::copy(Args
.begin(), Args
.end(), std::back_inserter(Info
.OrigArgs
));
592 if (!CLI
.lowerCall(MIRBuilder
, Info
))
593 return LegalizerHelper::UnableToLegalize
;
595 if (MI
&& Info
.LoweredTailCall
) {
596 assert(Info
.IsTailCall
&& "Lowered tail call when it wasn't a tail call?");
598 // Check debug locations before removing the return.
599 LocObserver
.checkpoint(true);
601 // We must have a return following the call (or debug insts) to get past
602 // isLibCallInTailPosition.
604 MachineInstr
*Next
= MI
->getNextNode();
606 (Next
->isCopy() || Next
->isReturn() || Next
->isDebugInstr()) &&
607 "Expected instr following MI to be return or debug inst?");
608 // We lowered a tail call, so the call is now the return from the block.
609 // Delete the old return.
610 Next
->eraseFromParent();
611 } while (MI
->getNextNode());
613 // We expect to lose the debug location from the return.
614 LocObserver
.checkpoint(false);
616 return LegalizerHelper::Legalized
;
619 LegalizerHelper::LegalizeResult
620 llvm::createLibcall(MachineIRBuilder
&MIRBuilder
, RTLIB::Libcall Libcall
,
621 const CallLowering::ArgInfo
&Result
,
622 ArrayRef
<CallLowering::ArgInfo
> Args
,
623 LostDebugLocObserver
&LocObserver
, MachineInstr
*MI
) {
624 auto &TLI
= *MIRBuilder
.getMF().getSubtarget().getTargetLowering();
625 const char *Name
= TLI
.getLibcallName(Libcall
);
627 return LegalizerHelper::UnableToLegalize
;
628 const CallingConv::ID CC
= TLI
.getLibcallCallingConv(Libcall
);
629 return createLibcall(MIRBuilder
, Name
, Result
, Args
, CC
, LocObserver
, MI
);
632 // Useful for libcalls where all operands have the same type.
633 static LegalizerHelper::LegalizeResult
634 simpleLibcall(MachineInstr
&MI
, MachineIRBuilder
&MIRBuilder
, unsigned Size
,
635 Type
*OpType
, LostDebugLocObserver
&LocObserver
) {
636 auto Libcall
= getRTLibDesc(MI
.getOpcode(), Size
);
638 // FIXME: What does the original arg index mean here?
639 SmallVector
<CallLowering::ArgInfo
, 3> Args
;
640 for (const MachineOperand
&MO
: llvm::drop_begin(MI
.operands()))
641 Args
.push_back({MO
.getReg(), OpType
, 0});
642 return createLibcall(MIRBuilder
, Libcall
,
643 {MI
.getOperand(0).getReg(), OpType
, 0}, Args
,
647 LegalizerHelper::LegalizeResult
648 llvm::createMemLibcall(MachineIRBuilder
&MIRBuilder
, MachineRegisterInfo
&MRI
,
649 MachineInstr
&MI
, LostDebugLocObserver
&LocObserver
) {
650 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
652 SmallVector
<CallLowering::ArgInfo
, 3> Args
;
653 // Add all the args, except for the last which is an imm denoting 'tail'.
654 for (unsigned i
= 0; i
< MI
.getNumOperands() - 1; ++i
) {
655 Register Reg
= MI
.getOperand(i
).getReg();
657 // Need derive an IR type for call lowering.
658 LLT OpLLT
= MRI
.getType(Reg
);
659 Type
*OpTy
= nullptr;
660 if (OpLLT
.isPointer())
661 OpTy
= PointerType::get(Ctx
, OpLLT
.getAddressSpace());
663 OpTy
= IntegerType::get(Ctx
, OpLLT
.getSizeInBits());
664 Args
.push_back({Reg
, OpTy
, 0});
667 auto &CLI
= *MIRBuilder
.getMF().getSubtarget().getCallLowering();
668 auto &TLI
= *MIRBuilder
.getMF().getSubtarget().getTargetLowering();
669 RTLIB::Libcall RTLibcall
;
670 unsigned Opc
= MI
.getOpcode();
672 case TargetOpcode::G_BZERO
:
673 RTLibcall
= RTLIB::BZERO
;
675 case TargetOpcode::G_MEMCPY
:
676 RTLibcall
= RTLIB::MEMCPY
;
677 Args
[0].Flags
[0].setReturned();
679 case TargetOpcode::G_MEMMOVE
:
680 RTLibcall
= RTLIB::MEMMOVE
;
681 Args
[0].Flags
[0].setReturned();
683 case TargetOpcode::G_MEMSET
:
684 RTLibcall
= RTLIB::MEMSET
;
685 Args
[0].Flags
[0].setReturned();
688 llvm_unreachable("unsupported opcode");
690 const char *Name
= TLI
.getLibcallName(RTLibcall
);
692 // Unsupported libcall on the target.
694 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
695 << MIRBuilder
.getTII().getName(Opc
) << "\n");
696 return LegalizerHelper::UnableToLegalize
;
699 CallLowering::CallLoweringInfo Info
;
700 Info
.CallConv
= TLI
.getLibcallCallingConv(RTLibcall
);
701 Info
.Callee
= MachineOperand::CreateES(Name
);
702 Info
.OrigRet
= CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx
), 0);
704 MI
.getOperand(MI
.getNumOperands() - 1).getImm() &&
705 isLibCallInTailPosition(Info
.OrigRet
, MI
, MIRBuilder
.getTII(), MRI
);
707 std::copy(Args
.begin(), Args
.end(), std::back_inserter(Info
.OrigArgs
));
708 if (!CLI
.lowerCall(MIRBuilder
, Info
))
709 return LegalizerHelper::UnableToLegalize
;
711 if (Info
.LoweredTailCall
) {
712 assert(Info
.IsTailCall
&& "Lowered tail call when it wasn't a tail call?");
714 // Check debug locations before removing the return.
715 LocObserver
.checkpoint(true);
717 // We must have a return following the call (or debug insts) to get past
718 // isLibCallInTailPosition.
720 MachineInstr
*Next
= MI
.getNextNode();
722 (Next
->isCopy() || Next
->isReturn() || Next
->isDebugInstr()) &&
723 "Expected instr following MI to be return or debug inst?");
724 // We lowered a tail call, so the call is now the return from the block.
725 // Delete the old return.
726 Next
->eraseFromParent();
727 } while (MI
.getNextNode());
729 // We expect to lose the debug location from the return.
730 LocObserver
.checkpoint(false);
733 return LegalizerHelper::Legalized
;
736 static RTLIB::Libcall
getOutlineAtomicLibcall(MachineInstr
&MI
) {
737 unsigned Opc
= MI
.getOpcode();
738 auto &AtomicMI
= cast
<GMemOperation
>(MI
);
739 auto &MMO
= AtomicMI
.getMMO();
740 auto Ordering
= MMO
.getMergedOrdering();
741 LLT MemType
= MMO
.getMemoryType();
742 uint64_t MemSize
= MemType
.getSizeInBytes();
743 if (MemType
.isVector())
744 return RTLIB::UNKNOWN_LIBCALL
;
746 #define LCALLS(A, B) {A##B##_RELAX, A##B##_ACQ, A##B##_REL, A##B##_ACQ_REL}
748 LCALLS(A, 1), LCALLS(A, 2), LCALLS(A, 4), LCALLS(A, 8), LCALLS(A, 16)
750 case TargetOpcode::G_ATOMIC_CMPXCHG
:
751 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
: {
752 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_CAS
)};
753 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
755 case TargetOpcode::G_ATOMICRMW_XCHG
: {
756 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_SWP
)};
757 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
759 case TargetOpcode::G_ATOMICRMW_ADD
:
760 case TargetOpcode::G_ATOMICRMW_SUB
: {
761 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDADD
)};
762 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
764 case TargetOpcode::G_ATOMICRMW_AND
: {
765 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDCLR
)};
766 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
768 case TargetOpcode::G_ATOMICRMW_OR
: {
769 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDSET
)};
770 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
772 case TargetOpcode::G_ATOMICRMW_XOR
: {
773 const RTLIB::Libcall LC
[5][4] = {LCALL5(RTLIB::OUTLINE_ATOMIC_LDEOR
)};
774 return getOutlineAtomicHelper(LC
, Ordering
, MemSize
);
777 return RTLIB::UNKNOWN_LIBCALL
;
783 static LegalizerHelper::LegalizeResult
784 createAtomicLibcall(MachineIRBuilder
&MIRBuilder
, MachineInstr
&MI
) {
785 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
788 SmallVector
<Register
> RetRegs
;
789 SmallVector
<CallLowering::ArgInfo
, 3> Args
;
790 unsigned Opc
= MI
.getOpcode();
792 case TargetOpcode::G_ATOMIC_CMPXCHG
:
793 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
: {
796 auto [Ret
, RetLLT
, Mem
, MemLLT
, Cmp
, CmpLLT
, New
, NewLLT
] =
797 MI
.getFirst4RegLLTs();
798 RetRegs
.push_back(Ret
);
799 RetTy
= IntegerType::get(Ctx
, RetLLT
.getSizeInBits());
800 if (Opc
== TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
) {
801 std::tie(Ret
, RetLLT
, Success
, SuccessLLT
, Mem
, MemLLT
, Cmp
, CmpLLT
, New
,
802 NewLLT
) = MI
.getFirst5RegLLTs();
803 RetRegs
.push_back(Success
);
804 RetTy
= StructType::get(
805 Ctx
, {RetTy
, IntegerType::get(Ctx
, SuccessLLT
.getSizeInBits())});
807 Args
.push_back({Cmp
, IntegerType::get(Ctx
, CmpLLT
.getSizeInBits()), 0});
808 Args
.push_back({New
, IntegerType::get(Ctx
, NewLLT
.getSizeInBits()), 0});
809 Args
.push_back({Mem
, PointerType::get(Ctx
, MemLLT
.getAddressSpace()), 0});
812 case TargetOpcode::G_ATOMICRMW_XCHG
:
813 case TargetOpcode::G_ATOMICRMW_ADD
:
814 case TargetOpcode::G_ATOMICRMW_SUB
:
815 case TargetOpcode::G_ATOMICRMW_AND
:
816 case TargetOpcode::G_ATOMICRMW_OR
:
817 case TargetOpcode::G_ATOMICRMW_XOR
: {
818 auto [Ret
, RetLLT
, Mem
, MemLLT
, Val
, ValLLT
] = MI
.getFirst3RegLLTs();
819 RetRegs
.push_back(Ret
);
820 RetTy
= IntegerType::get(Ctx
, RetLLT
.getSizeInBits());
821 if (Opc
== TargetOpcode::G_ATOMICRMW_AND
)
823 MIRBuilder
.buildXor(ValLLT
, MIRBuilder
.buildConstant(ValLLT
, -1), Val
)
825 else if (Opc
== TargetOpcode::G_ATOMICRMW_SUB
)
827 MIRBuilder
.buildSub(ValLLT
, MIRBuilder
.buildConstant(ValLLT
, 0), Val
)
829 Args
.push_back({Val
, IntegerType::get(Ctx
, ValLLT
.getSizeInBits()), 0});
830 Args
.push_back({Mem
, PointerType::get(Ctx
, MemLLT
.getAddressSpace()), 0});
834 llvm_unreachable("unsupported opcode");
837 auto &CLI
= *MIRBuilder
.getMF().getSubtarget().getCallLowering();
838 auto &TLI
= *MIRBuilder
.getMF().getSubtarget().getTargetLowering();
839 RTLIB::Libcall RTLibcall
= getOutlineAtomicLibcall(MI
);
840 const char *Name
= TLI
.getLibcallName(RTLibcall
);
842 // Unsupported libcall on the target.
844 LLVM_DEBUG(dbgs() << ".. .. Could not find libcall name for "
845 << MIRBuilder
.getTII().getName(Opc
) << "\n");
846 return LegalizerHelper::UnableToLegalize
;
849 CallLowering::CallLoweringInfo Info
;
850 Info
.CallConv
= TLI
.getLibcallCallingConv(RTLibcall
);
851 Info
.Callee
= MachineOperand::CreateES(Name
);
852 Info
.OrigRet
= CallLowering::ArgInfo(RetRegs
, RetTy
, 0);
854 std::copy(Args
.begin(), Args
.end(), std::back_inserter(Info
.OrigArgs
));
855 if (!CLI
.lowerCall(MIRBuilder
, Info
))
856 return LegalizerHelper::UnableToLegalize
;
858 return LegalizerHelper::Legalized
;
861 static RTLIB::Libcall
getConvRTLibDesc(unsigned Opcode
, Type
*ToType
,
863 auto ToMVT
= MVT::getVT(ToType
);
864 auto FromMVT
= MVT::getVT(FromType
);
867 case TargetOpcode::G_FPEXT
:
868 return RTLIB::getFPEXT(FromMVT
, ToMVT
);
869 case TargetOpcode::G_FPTRUNC
:
870 return RTLIB::getFPROUND(FromMVT
, ToMVT
);
871 case TargetOpcode::G_FPTOSI
:
872 return RTLIB::getFPTOSINT(FromMVT
, ToMVT
);
873 case TargetOpcode::G_FPTOUI
:
874 return RTLIB::getFPTOUINT(FromMVT
, ToMVT
);
875 case TargetOpcode::G_SITOFP
:
876 return RTLIB::getSINTTOFP(FromMVT
, ToMVT
);
877 case TargetOpcode::G_UITOFP
:
878 return RTLIB::getUINTTOFP(FromMVT
, ToMVT
);
880 llvm_unreachable("Unsupported libcall function");
883 static LegalizerHelper::LegalizeResult
884 conversionLibcall(MachineInstr
&MI
, MachineIRBuilder
&MIRBuilder
, Type
*ToType
,
885 Type
*FromType
, LostDebugLocObserver
&LocObserver
,
886 const TargetLowering
&TLI
, bool IsSigned
= false) {
887 CallLowering::ArgInfo Arg
= {MI
.getOperand(1).getReg(), FromType
, 0};
888 if (FromType
->isIntegerTy()) {
889 if (TLI
.shouldSignExtendTypeInLibCall(FromType
, IsSigned
))
890 Arg
.Flags
[0].setSExt();
892 Arg
.Flags
[0].setZExt();
895 RTLIB::Libcall Libcall
= getConvRTLibDesc(MI
.getOpcode(), ToType
, FromType
);
896 return createLibcall(MIRBuilder
, Libcall
,
897 {MI
.getOperand(0).getReg(), ToType
, 0}, Arg
, LocObserver
,
901 static RTLIB::Libcall
902 getStateLibraryFunctionFor(MachineInstr
&MI
, const TargetLowering
&TLI
) {
903 RTLIB::Libcall RTLibcall
;
904 switch (MI
.getOpcode()) {
905 case TargetOpcode::G_GET_FPENV
:
906 RTLibcall
= RTLIB::FEGETENV
;
908 case TargetOpcode::G_SET_FPENV
:
909 case TargetOpcode::G_RESET_FPENV
:
910 RTLibcall
= RTLIB::FESETENV
;
912 case TargetOpcode::G_GET_FPMODE
:
913 RTLibcall
= RTLIB::FEGETMODE
;
915 case TargetOpcode::G_SET_FPMODE
:
916 case TargetOpcode::G_RESET_FPMODE
:
917 RTLibcall
= RTLIB::FESETMODE
;
920 llvm_unreachable("Unexpected opcode");
925 // Some library functions that read FP state (fegetmode, fegetenv) write the
926 // state into a region in memory. IR intrinsics that do the same operations
927 // (get_fpmode, get_fpenv) return the state as integer value. To implement these
928 // intrinsics via the library functions, we need to use temporary variable,
931 // %0:_(s32) = G_GET_FPMODE
933 // is transformed to:
935 // %1:_(p0) = G_FRAME_INDEX %stack.0
937 // %0:_(s32) = G_LOAD % 1
939 LegalizerHelper::LegalizeResult
940 LegalizerHelper::createGetStateLibcall(MachineIRBuilder
&MIRBuilder
,
942 LostDebugLocObserver
&LocObserver
) {
943 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
944 auto &MF
= MIRBuilder
.getMF();
945 auto &MRI
= *MIRBuilder
.getMRI();
946 auto &Ctx
= MF
.getFunction().getContext();
948 // Create temporary, where library function will put the read state.
949 Register Dst
= MI
.getOperand(0).getReg();
950 LLT StateTy
= MRI
.getType(Dst
);
951 TypeSize StateSize
= StateTy
.getSizeInBytes();
952 Align TempAlign
= getStackTemporaryAlignment(StateTy
);
953 MachinePointerInfo TempPtrInfo
;
954 auto Temp
= createStackTemporary(StateSize
, TempAlign
, TempPtrInfo
);
956 // Create a call to library function, with the temporary as an argument.
957 unsigned TempAddrSpace
= DL
.getAllocaAddrSpace();
958 Type
*StatePtrTy
= PointerType::get(Ctx
, TempAddrSpace
);
959 RTLIB::Libcall RTLibcall
= getStateLibraryFunctionFor(MI
, TLI
);
961 createLibcall(MIRBuilder
, RTLibcall
,
962 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx
), 0),
963 CallLowering::ArgInfo({Temp
.getReg(0), StatePtrTy
, 0}),
964 LocObserver
, nullptr);
965 if (Res
!= LegalizerHelper::Legalized
)
968 // Create a load from the temporary.
969 MachineMemOperand
*MMO
= MF
.getMachineMemOperand(
970 TempPtrInfo
, MachineMemOperand::MOLoad
, StateTy
, TempAlign
);
971 MIRBuilder
.buildLoadInstr(TargetOpcode::G_LOAD
, Dst
, Temp
, *MMO
);
973 return LegalizerHelper::Legalized
;
976 // Similar to `createGetStateLibcall` the function calls a library function
977 // using transient space in stack. In this case the library function reads
978 // content of memory region.
979 LegalizerHelper::LegalizeResult
980 LegalizerHelper::createSetStateLibcall(MachineIRBuilder
&MIRBuilder
,
982 LostDebugLocObserver
&LocObserver
) {
983 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
984 auto &MF
= MIRBuilder
.getMF();
985 auto &MRI
= *MIRBuilder
.getMRI();
986 auto &Ctx
= MF
.getFunction().getContext();
988 // Create temporary, where library function will get the new state.
989 Register Src
= MI
.getOperand(0).getReg();
990 LLT StateTy
= MRI
.getType(Src
);
991 TypeSize StateSize
= StateTy
.getSizeInBytes();
992 Align TempAlign
= getStackTemporaryAlignment(StateTy
);
993 MachinePointerInfo TempPtrInfo
;
994 auto Temp
= createStackTemporary(StateSize
, TempAlign
, TempPtrInfo
);
996 // Put the new state into the temporary.
997 MachineMemOperand
*MMO
= MF
.getMachineMemOperand(
998 TempPtrInfo
, MachineMemOperand::MOStore
, StateTy
, TempAlign
);
999 MIRBuilder
.buildStore(Src
, Temp
, *MMO
);
1001 // Create a call to library function, with the temporary as an argument.
1002 unsigned TempAddrSpace
= DL
.getAllocaAddrSpace();
1003 Type
*StatePtrTy
= PointerType::get(Ctx
, TempAddrSpace
);
1004 RTLIB::Libcall RTLibcall
= getStateLibraryFunctionFor(MI
, TLI
);
1005 return createLibcall(MIRBuilder
, RTLibcall
,
1006 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx
), 0),
1007 CallLowering::ArgInfo({Temp
.getReg(0), StatePtrTy
, 0}),
1008 LocObserver
, nullptr);
1011 /// Returns the corresponding libcall for the given Pred and
1012 /// the ICMP predicate that should be generated to compare with #0
1013 /// after the libcall.
1014 static std::pair
<RTLIB::Libcall
, CmpInst::Predicate
>
1015 getFCMPLibcallDesc(const CmpInst::Predicate Pred
, unsigned Size
) {
1016 #define RTLIBCASE_CMP(LibcallPrefix, ICmpPred) \
1020 return {RTLIB::LibcallPrefix##32, ICmpPred}; \
1022 return {RTLIB::LibcallPrefix##64, ICmpPred}; \
1024 return {RTLIB::LibcallPrefix##128, ICmpPred}; \
1026 llvm_unreachable("unexpected size"); \
1031 case CmpInst::FCMP_OEQ
:
1032 RTLIBCASE_CMP(OEQ_F
, CmpInst::ICMP_EQ
);
1033 case CmpInst::FCMP_UNE
:
1034 RTLIBCASE_CMP(UNE_F
, CmpInst::ICMP_NE
);
1035 case CmpInst::FCMP_OGE
:
1036 RTLIBCASE_CMP(OGE_F
, CmpInst::ICMP_SGE
);
1037 case CmpInst::FCMP_OLT
:
1038 RTLIBCASE_CMP(OLT_F
, CmpInst::ICMP_SLT
);
1039 case CmpInst::FCMP_OLE
:
1040 RTLIBCASE_CMP(OLE_F
, CmpInst::ICMP_SLE
);
1041 case CmpInst::FCMP_OGT
:
1042 RTLIBCASE_CMP(OGT_F
, CmpInst::ICMP_SGT
);
1043 case CmpInst::FCMP_UNO
:
1044 RTLIBCASE_CMP(UO_F
, CmpInst::ICMP_NE
);
1046 return {RTLIB::UNKNOWN_LIBCALL
, CmpInst::BAD_ICMP_PREDICATE
};
1050 LegalizerHelper::LegalizeResult
1051 LegalizerHelper::createFCMPLibcall(MachineIRBuilder
&MIRBuilder
,
1053 LostDebugLocObserver
&LocObserver
) {
1054 auto &MF
= MIRBuilder
.getMF();
1055 auto &Ctx
= MF
.getFunction().getContext();
1056 const GFCmp
*Cmp
= cast
<GFCmp
>(&MI
);
1058 LLT OpLLT
= MRI
.getType(Cmp
->getLHSReg());
1059 unsigned Size
= OpLLT
.getSizeInBits();
1060 if ((Size
!= 32 && Size
!= 64 && Size
!= 128) ||
1061 OpLLT
!= MRI
.getType(Cmp
->getRHSReg()))
1062 return UnableToLegalize
;
1064 Type
*OpType
= getFloatTypeForLLT(Ctx
, OpLLT
);
1066 // DstReg type is s32
1067 const Register DstReg
= Cmp
->getReg(0);
1068 LLT DstTy
= MRI
.getType(DstReg
);
1069 const auto Cond
= Cmp
->getCond();
1072 // https://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Comparison-functions-1
1073 // Generates a libcall followed by ICMP.
1074 const auto BuildLibcall
= [&](const RTLIB::Libcall Libcall
,
1075 const CmpInst::Predicate ICmpPred
,
1076 const DstOp
&Res
) -> Register
{
1077 // FCMP libcall always returns an i32, and needs an ICMP with #0.
1078 constexpr LLT TempLLT
= LLT::scalar(32);
1079 Register Temp
= MRI
.createGenericVirtualRegister(TempLLT
);
1080 // Generate libcall, holding result in Temp
1081 const auto Status
= createLibcall(
1082 MIRBuilder
, Libcall
, {Temp
, Type::getInt32Ty(Ctx
), 0},
1083 {{Cmp
->getLHSReg(), OpType
, 0}, {Cmp
->getRHSReg(), OpType
, 1}},
1088 // Compare temp with #0 to get the final result.
1090 .buildICmp(ICmpPred
, Res
, Temp
, MIRBuilder
.buildConstant(TempLLT
, 0))
1094 // Simple case if we have a direct mapping from predicate to libcall
1095 if (const auto [Libcall
, ICmpPred
] = getFCMPLibcallDesc(Cond
, Size
);
1096 Libcall
!= RTLIB::UNKNOWN_LIBCALL
&&
1097 ICmpPred
!= CmpInst::BAD_ICMP_PREDICATE
) {
1098 if (BuildLibcall(Libcall
, ICmpPred
, DstReg
)) {
1101 return UnableToLegalize
;
1104 // No direct mapping found, should be generated as combination of libcalls.
1107 case CmpInst::FCMP_UEQ
: {
1108 // FCMP_UEQ: unordered or equal
1109 // Convert into (FCMP_OEQ || FCMP_UNO).
1111 const auto [OeqLibcall
, OeqPred
] =
1112 getFCMPLibcallDesc(CmpInst::FCMP_OEQ
, Size
);
1113 const auto Oeq
= BuildLibcall(OeqLibcall
, OeqPred
, DstTy
);
1115 const auto [UnoLibcall
, UnoPred
] =
1116 getFCMPLibcallDesc(CmpInst::FCMP_UNO
, Size
);
1117 const auto Uno
= BuildLibcall(UnoLibcall
, UnoPred
, DstTy
);
1119 MIRBuilder
.buildOr(DstReg
, Oeq
, Uno
);
1121 return UnableToLegalize
;
1125 case CmpInst::FCMP_ONE
: {
1126 // FCMP_ONE: ordered and operands are unequal
1127 // Convert into (!FCMP_OEQ && !FCMP_UNO).
1129 // We inverse the predicate instead of generating a NOT
1130 // to save one instruction.
1131 // On AArch64 isel can even select two cmp into a single ccmp.
1132 const auto [OeqLibcall
, OeqPred
] =
1133 getFCMPLibcallDesc(CmpInst::FCMP_OEQ
, Size
);
1135 BuildLibcall(OeqLibcall
, CmpInst::getInversePredicate(OeqPred
), DstTy
);
1137 const auto [UnoLibcall
, UnoPred
] =
1138 getFCMPLibcallDesc(CmpInst::FCMP_UNO
, Size
);
1140 BuildLibcall(UnoLibcall
, CmpInst::getInversePredicate(UnoPred
), DstTy
);
1142 if (NotOeq
&& NotUno
)
1143 MIRBuilder
.buildAnd(DstReg
, NotOeq
, NotUno
);
1145 return UnableToLegalize
;
1149 case CmpInst::FCMP_ULT
:
1150 case CmpInst::FCMP_UGE
:
1151 case CmpInst::FCMP_UGT
:
1152 case CmpInst::FCMP_ULE
:
1153 case CmpInst::FCMP_ORD
: {
1154 // Convert into: !(inverse(Pred))
1155 // E.g. FCMP_ULT becomes !FCMP_OGE
1156 // This is equivalent to the following, but saves some instructions.
1157 // MIRBuilder.buildNot(
1159 // MIRBuilder.buildFCmp(CmpInst::getInversePredicate(Pred), PredTy,
1161 const auto [InversedLibcall
, InversedPred
] =
1162 getFCMPLibcallDesc(CmpInst::getInversePredicate(Cond
), Size
);
1163 if (!BuildLibcall(InversedLibcall
,
1164 CmpInst::getInversePredicate(InversedPred
), DstReg
))
1165 return UnableToLegalize
;
1169 return UnableToLegalize
;
1175 // The function is used to legalize operations that set default environment
1176 // state. In C library a call like `fesetmode(FE_DFL_MODE)` is used for that.
1177 // On most targets supported in glibc FE_DFL_MODE is defined as
1178 // `((const femode_t *) -1)`. Such assumption is used here. If for some target
1179 // it is not true, the target must provide custom lowering.
1180 LegalizerHelper::LegalizeResult
1181 LegalizerHelper::createResetStateLibcall(MachineIRBuilder
&MIRBuilder
,
1183 LostDebugLocObserver
&LocObserver
) {
1184 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
1185 auto &MF
= MIRBuilder
.getMF();
1186 auto &Ctx
= MF
.getFunction().getContext();
1188 // Create an argument for the library function.
1189 unsigned AddrSpace
= DL
.getDefaultGlobalsAddressSpace();
1190 Type
*StatePtrTy
= PointerType::get(Ctx
, AddrSpace
);
1191 unsigned PtrSize
= DL
.getPointerSizeInBits(AddrSpace
);
1192 LLT MemTy
= LLT::pointer(AddrSpace
, PtrSize
);
1193 auto DefValue
= MIRBuilder
.buildConstant(LLT::scalar(PtrSize
), -1LL);
1194 DstOp
Dest(MRI
.createGenericVirtualRegister(MemTy
));
1195 MIRBuilder
.buildIntToPtr(Dest
, DefValue
);
1197 RTLIB::Libcall RTLibcall
= getStateLibraryFunctionFor(MI
, TLI
);
1198 return createLibcall(MIRBuilder
, RTLibcall
,
1199 CallLowering::ArgInfo({0}, Type::getVoidTy(Ctx
), 0),
1200 CallLowering::ArgInfo({Dest
.getReg(), StatePtrTy
, 0}),
1204 LegalizerHelper::LegalizeResult
1205 LegalizerHelper::libcall(MachineInstr
&MI
, LostDebugLocObserver
&LocObserver
) {
1206 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
1208 switch (MI
.getOpcode()) {
1210 return UnableToLegalize
;
1211 case TargetOpcode::G_MUL
:
1212 case TargetOpcode::G_SDIV
:
1213 case TargetOpcode::G_UDIV
:
1214 case TargetOpcode::G_SREM
:
1215 case TargetOpcode::G_UREM
:
1216 case TargetOpcode::G_CTLZ_ZERO_UNDEF
: {
1217 LLT LLTy
= MRI
.getType(MI
.getOperand(0).getReg());
1218 unsigned Size
= LLTy
.getSizeInBits();
1219 Type
*HLTy
= IntegerType::get(Ctx
, Size
);
1220 auto Status
= simpleLibcall(MI
, MIRBuilder
, Size
, HLTy
, LocObserver
);
1221 if (Status
!= Legalized
)
1225 case TargetOpcode::G_FADD
:
1226 case TargetOpcode::G_FSUB
:
1227 case TargetOpcode::G_FMUL
:
1228 case TargetOpcode::G_FDIV
:
1229 case TargetOpcode::G_FMA
:
1230 case TargetOpcode::G_FPOW
:
1231 case TargetOpcode::G_FREM
:
1232 case TargetOpcode::G_FCOS
:
1233 case TargetOpcode::G_FSIN
:
1234 case TargetOpcode::G_FTAN
:
1235 case TargetOpcode::G_FACOS
:
1236 case TargetOpcode::G_FASIN
:
1237 case TargetOpcode::G_FATAN
:
1238 case TargetOpcode::G_FATAN2
:
1239 case TargetOpcode::G_FCOSH
:
1240 case TargetOpcode::G_FSINH
:
1241 case TargetOpcode::G_FTANH
:
1242 case TargetOpcode::G_FLOG10
:
1243 case TargetOpcode::G_FLOG
:
1244 case TargetOpcode::G_FLOG2
:
1245 case TargetOpcode::G_FEXP
:
1246 case TargetOpcode::G_FEXP2
:
1247 case TargetOpcode::G_FEXP10
:
1248 case TargetOpcode::G_FCEIL
:
1249 case TargetOpcode::G_FFLOOR
:
1250 case TargetOpcode::G_FMINNUM
:
1251 case TargetOpcode::G_FMAXNUM
:
1252 case TargetOpcode::G_FSQRT
:
1253 case TargetOpcode::G_FRINT
:
1254 case TargetOpcode::G_FNEARBYINT
:
1255 case TargetOpcode::G_INTRINSIC_TRUNC
:
1256 case TargetOpcode::G_INTRINSIC_ROUND
:
1257 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
: {
1258 LLT LLTy
= MRI
.getType(MI
.getOperand(0).getReg());
1259 unsigned Size
= LLTy
.getSizeInBits();
1260 Type
*HLTy
= getFloatTypeForLLT(Ctx
, LLTy
);
1261 if (!HLTy
|| (Size
!= 32 && Size
!= 64 && Size
!= 80 && Size
!= 128)) {
1262 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy
<< ".\n");
1263 return UnableToLegalize
;
1265 auto Status
= simpleLibcall(MI
, MIRBuilder
, Size
, HLTy
, LocObserver
);
1266 if (Status
!= Legalized
)
1270 case TargetOpcode::G_INTRINSIC_LRINT
:
1271 case TargetOpcode::G_INTRINSIC_LLRINT
: {
1272 LLT LLTy
= MRI
.getType(MI
.getOperand(1).getReg());
1273 unsigned Size
= LLTy
.getSizeInBits();
1274 Type
*HLTy
= getFloatTypeForLLT(Ctx
, LLTy
);
1275 Type
*ITy
= IntegerType::get(
1276 Ctx
, MRI
.getType(MI
.getOperand(0).getReg()).getSizeInBits());
1277 if (!HLTy
|| (Size
!= 32 && Size
!= 64 && Size
!= 80 && Size
!= 128)) {
1278 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy
<< ".\n");
1279 return UnableToLegalize
;
1281 auto Libcall
= getRTLibDesc(MI
.getOpcode(), Size
);
1282 LegalizeResult Status
=
1283 createLibcall(MIRBuilder
, Libcall
, {MI
.getOperand(0).getReg(), ITy
, 0},
1284 {{MI
.getOperand(1).getReg(), HLTy
, 0}}, LocObserver
, &MI
);
1285 if (Status
!= Legalized
)
1287 MI
.eraseFromParent();
1290 case TargetOpcode::G_FPOWI
:
1291 case TargetOpcode::G_FLDEXP
: {
1292 LLT LLTy
= MRI
.getType(MI
.getOperand(0).getReg());
1293 unsigned Size
= LLTy
.getSizeInBits();
1294 Type
*HLTy
= getFloatTypeForLLT(Ctx
, LLTy
);
1295 Type
*ITy
= IntegerType::get(
1296 Ctx
, MRI
.getType(MI
.getOperand(2).getReg()).getSizeInBits());
1297 if (!HLTy
|| (Size
!= 32 && Size
!= 64 && Size
!= 80 && Size
!= 128)) {
1298 LLVM_DEBUG(dbgs() << "No libcall available for type " << LLTy
<< ".\n");
1299 return UnableToLegalize
;
1301 auto Libcall
= getRTLibDesc(MI
.getOpcode(), Size
);
1302 SmallVector
<CallLowering::ArgInfo
, 2> Args
= {
1303 {MI
.getOperand(1).getReg(), HLTy
, 0},
1304 {MI
.getOperand(2).getReg(), ITy
, 1}};
1305 Args
[1].Flags
[0].setSExt();
1306 LegalizeResult Status
=
1307 createLibcall(MIRBuilder
, Libcall
, {MI
.getOperand(0).getReg(), HLTy
, 0},
1308 Args
, LocObserver
, &MI
);
1309 if (Status
!= Legalized
)
1313 case TargetOpcode::G_FPEXT
:
1314 case TargetOpcode::G_FPTRUNC
: {
1315 Type
*FromTy
= getFloatTypeForLLT(Ctx
, MRI
.getType(MI
.getOperand(1).getReg()));
1316 Type
*ToTy
= getFloatTypeForLLT(Ctx
, MRI
.getType(MI
.getOperand(0).getReg()));
1317 if (!FromTy
|| !ToTy
)
1318 return UnableToLegalize
;
1319 LegalizeResult Status
=
1320 conversionLibcall(MI
, MIRBuilder
, ToTy
, FromTy
, LocObserver
, TLI
);
1321 if (Status
!= Legalized
)
1325 case TargetOpcode::G_FCMP
: {
1326 LegalizeResult Status
= createFCMPLibcall(MIRBuilder
, MI
, LocObserver
);
1327 if (Status
!= Legalized
)
1329 MI
.eraseFromParent();
1332 case TargetOpcode::G_FPTOSI
:
1333 case TargetOpcode::G_FPTOUI
: {
1334 // FIXME: Support other types
1336 getFloatTypeForLLT(Ctx
, MRI
.getType(MI
.getOperand(1).getReg()));
1337 unsigned ToSize
= MRI
.getType(MI
.getOperand(0).getReg()).getSizeInBits();
1338 if ((ToSize
!= 32 && ToSize
!= 64 && ToSize
!= 128) || !FromTy
)
1339 return UnableToLegalize
;
1340 LegalizeResult Status
= conversionLibcall(
1341 MI
, MIRBuilder
, Type::getIntNTy(Ctx
, ToSize
), FromTy
, LocObserver
, TLI
);
1342 if (Status
!= Legalized
)
1346 case TargetOpcode::G_SITOFP
:
1347 case TargetOpcode::G_UITOFP
: {
1348 unsigned FromSize
= MRI
.getType(MI
.getOperand(1).getReg()).getSizeInBits();
1350 getFloatTypeForLLT(Ctx
, MRI
.getType(MI
.getOperand(0).getReg()));
1351 if ((FromSize
!= 32 && FromSize
!= 64 && FromSize
!= 128) || !ToTy
)
1352 return UnableToLegalize
;
1353 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_SITOFP
;
1354 LegalizeResult Status
=
1355 conversionLibcall(MI
, MIRBuilder
, ToTy
, Type::getIntNTy(Ctx
, FromSize
),
1356 LocObserver
, TLI
, IsSigned
);
1357 if (Status
!= Legalized
)
1361 case TargetOpcode::G_ATOMICRMW_XCHG
:
1362 case TargetOpcode::G_ATOMICRMW_ADD
:
1363 case TargetOpcode::G_ATOMICRMW_SUB
:
1364 case TargetOpcode::G_ATOMICRMW_AND
:
1365 case TargetOpcode::G_ATOMICRMW_OR
:
1366 case TargetOpcode::G_ATOMICRMW_XOR
:
1367 case TargetOpcode::G_ATOMIC_CMPXCHG
:
1368 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
: {
1369 auto Status
= createAtomicLibcall(MIRBuilder
, MI
);
1370 if (Status
!= Legalized
)
1374 case TargetOpcode::G_BZERO
:
1375 case TargetOpcode::G_MEMCPY
:
1376 case TargetOpcode::G_MEMMOVE
:
1377 case TargetOpcode::G_MEMSET
: {
1378 LegalizeResult Result
=
1379 createMemLibcall(MIRBuilder
, *MIRBuilder
.getMRI(), MI
, LocObserver
);
1380 if (Result
!= Legalized
)
1382 MI
.eraseFromParent();
1385 case TargetOpcode::G_GET_FPENV
:
1386 case TargetOpcode::G_GET_FPMODE
: {
1387 LegalizeResult Result
= createGetStateLibcall(MIRBuilder
, MI
, LocObserver
);
1388 if (Result
!= Legalized
)
1392 case TargetOpcode::G_SET_FPENV
:
1393 case TargetOpcode::G_SET_FPMODE
: {
1394 LegalizeResult Result
= createSetStateLibcall(MIRBuilder
, MI
, LocObserver
);
1395 if (Result
!= Legalized
)
1399 case TargetOpcode::G_RESET_FPENV
:
1400 case TargetOpcode::G_RESET_FPMODE
: {
1401 LegalizeResult Result
=
1402 createResetStateLibcall(MIRBuilder
, MI
, LocObserver
);
1403 if (Result
!= Legalized
)
1409 MI
.eraseFromParent();
1413 LegalizerHelper::LegalizeResult
LegalizerHelper::narrowScalar(MachineInstr
&MI
,
1416 uint64_t SizeOp0
= MRI
.getType(MI
.getOperand(0).getReg()).getSizeInBits();
1417 uint64_t NarrowSize
= NarrowTy
.getSizeInBits();
1419 switch (MI
.getOpcode()) {
1421 return UnableToLegalize
;
1422 case TargetOpcode::G_IMPLICIT_DEF
: {
1423 Register DstReg
= MI
.getOperand(0).getReg();
1424 LLT DstTy
= MRI
.getType(DstReg
);
1426 // If SizeOp0 is not an exact multiple of NarrowSize, emit
1427 // G_ANYEXT(G_IMPLICIT_DEF). Cast result to vector if needed.
1428 // FIXME: Although this would also be legal for the general case, it causes
1429 // a lot of regressions in the emitted code (superfluous COPYs, artifact
1430 // combines not being hit). This seems to be a problem related to the
1431 // artifact combiner.
1432 if (SizeOp0
% NarrowSize
!= 0) {
1433 LLT ImplicitTy
= NarrowTy
;
1434 if (DstTy
.isVector())
1435 ImplicitTy
= LLT::vector(DstTy
.getElementCount(), ImplicitTy
);
1437 Register ImplicitReg
= MIRBuilder
.buildUndef(ImplicitTy
).getReg(0);
1438 MIRBuilder
.buildAnyExt(DstReg
, ImplicitReg
);
1440 MI
.eraseFromParent();
1444 int NumParts
= SizeOp0
/ NarrowSize
;
1446 SmallVector
<Register
, 2> DstRegs
;
1447 for (int i
= 0; i
< NumParts
; ++i
)
1448 DstRegs
.push_back(MIRBuilder
.buildUndef(NarrowTy
).getReg(0));
1450 if (DstTy
.isVector())
1451 MIRBuilder
.buildBuildVector(DstReg
, DstRegs
);
1453 MIRBuilder
.buildMergeLikeInstr(DstReg
, DstRegs
);
1454 MI
.eraseFromParent();
1457 case TargetOpcode::G_CONSTANT
: {
1458 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
1459 const APInt
&Val
= MI
.getOperand(1).getCImm()->getValue();
1460 unsigned TotalSize
= Ty
.getSizeInBits();
1461 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
1462 int NumParts
= TotalSize
/ NarrowSize
;
1464 SmallVector
<Register
, 4> PartRegs
;
1465 for (int I
= 0; I
!= NumParts
; ++I
) {
1466 unsigned Offset
= I
* NarrowSize
;
1467 auto K
= MIRBuilder
.buildConstant(NarrowTy
,
1468 Val
.lshr(Offset
).trunc(NarrowSize
));
1469 PartRegs
.push_back(K
.getReg(0));
1473 unsigned LeftoverBits
= TotalSize
- NumParts
* NarrowSize
;
1474 SmallVector
<Register
, 1> LeftoverRegs
;
1475 if (LeftoverBits
!= 0) {
1476 LeftoverTy
= LLT::scalar(LeftoverBits
);
1477 auto K
= MIRBuilder
.buildConstant(
1479 Val
.lshr(NumParts
* NarrowSize
).trunc(LeftoverBits
));
1480 LeftoverRegs
.push_back(K
.getReg(0));
1483 insertParts(MI
.getOperand(0).getReg(),
1484 Ty
, NarrowTy
, PartRegs
, LeftoverTy
, LeftoverRegs
);
1486 MI
.eraseFromParent();
1489 case TargetOpcode::G_SEXT
:
1490 case TargetOpcode::G_ZEXT
:
1491 case TargetOpcode::G_ANYEXT
:
1492 return narrowScalarExt(MI
, TypeIdx
, NarrowTy
);
1493 case TargetOpcode::G_TRUNC
: {
1495 return UnableToLegalize
;
1497 uint64_t SizeOp1
= MRI
.getType(MI
.getOperand(1).getReg()).getSizeInBits();
1498 if (NarrowTy
.getSizeInBits() * 2 != SizeOp1
) {
1499 LLVM_DEBUG(dbgs() << "Can't narrow trunc to type " << NarrowTy
<< "\n");
1500 return UnableToLegalize
;
1503 auto Unmerge
= MIRBuilder
.buildUnmerge(NarrowTy
, MI
.getOperand(1));
1504 MIRBuilder
.buildCopy(MI
.getOperand(0), Unmerge
.getReg(0));
1505 MI
.eraseFromParent();
1508 case TargetOpcode::G_CONSTANT_FOLD_BARRIER
:
1509 case TargetOpcode::G_FREEZE
: {
1511 return UnableToLegalize
;
1513 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
1514 // Should widen scalar first
1515 if (Ty
.getSizeInBits() % NarrowTy
.getSizeInBits() != 0)
1516 return UnableToLegalize
;
1518 auto Unmerge
= MIRBuilder
.buildUnmerge(NarrowTy
, MI
.getOperand(1).getReg());
1519 SmallVector
<Register
, 8> Parts
;
1520 for (unsigned i
= 0; i
< Unmerge
->getNumDefs(); ++i
) {
1522 MIRBuilder
.buildInstr(MI
.getOpcode(), {NarrowTy
}, {Unmerge
.getReg(i
)})
1526 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(0).getReg(), Parts
);
1527 MI
.eraseFromParent();
1530 case TargetOpcode::G_ADD
:
1531 case TargetOpcode::G_SUB
:
1532 case TargetOpcode::G_SADDO
:
1533 case TargetOpcode::G_SSUBO
:
1534 case TargetOpcode::G_SADDE
:
1535 case TargetOpcode::G_SSUBE
:
1536 case TargetOpcode::G_UADDO
:
1537 case TargetOpcode::G_USUBO
:
1538 case TargetOpcode::G_UADDE
:
1539 case TargetOpcode::G_USUBE
:
1540 return narrowScalarAddSub(MI
, TypeIdx
, NarrowTy
);
1541 case TargetOpcode::G_MUL
:
1542 case TargetOpcode::G_UMULH
:
1543 return narrowScalarMul(MI
, NarrowTy
);
1544 case TargetOpcode::G_EXTRACT
:
1545 return narrowScalarExtract(MI
, TypeIdx
, NarrowTy
);
1546 case TargetOpcode::G_INSERT
:
1547 return narrowScalarInsert(MI
, TypeIdx
, NarrowTy
);
1548 case TargetOpcode::G_LOAD
: {
1549 auto &LoadMI
= cast
<GLoad
>(MI
);
1550 Register DstReg
= LoadMI
.getDstReg();
1551 LLT DstTy
= MRI
.getType(DstReg
);
1552 if (DstTy
.isVector())
1553 return UnableToLegalize
;
1555 if (8 * LoadMI
.getMemSize().getValue() != DstTy
.getSizeInBits()) {
1556 Register TmpReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
1557 MIRBuilder
.buildLoad(TmpReg
, LoadMI
.getPointerReg(), LoadMI
.getMMO());
1558 MIRBuilder
.buildAnyExt(DstReg
, TmpReg
);
1559 LoadMI
.eraseFromParent();
1563 return reduceLoadStoreWidth(LoadMI
, TypeIdx
, NarrowTy
);
1565 case TargetOpcode::G_ZEXTLOAD
:
1566 case TargetOpcode::G_SEXTLOAD
: {
1567 auto &LoadMI
= cast
<GExtLoad
>(MI
);
1568 Register DstReg
= LoadMI
.getDstReg();
1569 Register PtrReg
= LoadMI
.getPointerReg();
1571 Register TmpReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
1572 auto &MMO
= LoadMI
.getMMO();
1573 unsigned MemSize
= MMO
.getSizeInBits().getValue();
1575 if (MemSize
== NarrowSize
) {
1576 MIRBuilder
.buildLoad(TmpReg
, PtrReg
, MMO
);
1577 } else if (MemSize
< NarrowSize
) {
1578 MIRBuilder
.buildLoadInstr(LoadMI
.getOpcode(), TmpReg
, PtrReg
, MMO
);
1579 } else if (MemSize
> NarrowSize
) {
1580 // FIXME: Need to split the load.
1581 return UnableToLegalize
;
1584 if (isa
<GZExtLoad
>(LoadMI
))
1585 MIRBuilder
.buildZExt(DstReg
, TmpReg
);
1587 MIRBuilder
.buildSExt(DstReg
, TmpReg
);
1589 LoadMI
.eraseFromParent();
1592 case TargetOpcode::G_STORE
: {
1593 auto &StoreMI
= cast
<GStore
>(MI
);
1595 Register SrcReg
= StoreMI
.getValueReg();
1596 LLT SrcTy
= MRI
.getType(SrcReg
);
1597 if (SrcTy
.isVector())
1598 return UnableToLegalize
;
1600 int NumParts
= SizeOp0
/ NarrowSize
;
1601 unsigned HandledSize
= NumParts
* NarrowTy
.getSizeInBits();
1602 unsigned LeftoverBits
= SrcTy
.getSizeInBits() - HandledSize
;
1603 if (SrcTy
.isVector() && LeftoverBits
!= 0)
1604 return UnableToLegalize
;
1606 if (8 * StoreMI
.getMemSize().getValue() != SrcTy
.getSizeInBits()) {
1607 Register TmpReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
1608 MIRBuilder
.buildTrunc(TmpReg
, SrcReg
);
1609 MIRBuilder
.buildStore(TmpReg
, StoreMI
.getPointerReg(), StoreMI
.getMMO());
1610 StoreMI
.eraseFromParent();
1614 return reduceLoadStoreWidth(StoreMI
, 0, NarrowTy
);
1616 case TargetOpcode::G_SELECT
:
1617 return narrowScalarSelect(MI
, TypeIdx
, NarrowTy
);
1618 case TargetOpcode::G_AND
:
1619 case TargetOpcode::G_OR
:
1620 case TargetOpcode::G_XOR
: {
1621 // Legalize bitwise operation:
1622 // A = BinOp<Ty> B, C
1624 // B1, ..., BN = G_UNMERGE_VALUES B
1625 // C1, ..., CN = G_UNMERGE_VALUES C
1626 // A1 = BinOp<Ty/N> B1, C2
1628 // AN = BinOp<Ty/N> BN, CN
1629 // A = G_MERGE_VALUES A1, ..., AN
1630 return narrowScalarBasic(MI
, TypeIdx
, NarrowTy
);
1632 case TargetOpcode::G_SHL
:
1633 case TargetOpcode::G_LSHR
:
1634 case TargetOpcode::G_ASHR
:
1635 return narrowScalarShift(MI
, TypeIdx
, NarrowTy
);
1636 case TargetOpcode::G_CTLZ
:
1637 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
1638 case TargetOpcode::G_CTTZ
:
1639 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
1640 case TargetOpcode::G_CTPOP
:
1642 switch (MI
.getOpcode()) {
1643 case TargetOpcode::G_CTLZ
:
1644 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
1645 return narrowScalarCTLZ(MI
, TypeIdx
, NarrowTy
);
1646 case TargetOpcode::G_CTTZ
:
1647 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
1648 return narrowScalarCTTZ(MI
, TypeIdx
, NarrowTy
);
1649 case TargetOpcode::G_CTPOP
:
1650 return narrowScalarCTPOP(MI
, TypeIdx
, NarrowTy
);
1652 return UnableToLegalize
;
1655 Observer
.changingInstr(MI
);
1656 narrowScalarDst(MI
, NarrowTy
, 0, TargetOpcode::G_ZEXT
);
1657 Observer
.changedInstr(MI
);
1659 case TargetOpcode::G_INTTOPTR
:
1661 return UnableToLegalize
;
1663 Observer
.changingInstr(MI
);
1664 narrowScalarSrc(MI
, NarrowTy
, 1);
1665 Observer
.changedInstr(MI
);
1667 case TargetOpcode::G_PTRTOINT
:
1669 return UnableToLegalize
;
1671 Observer
.changingInstr(MI
);
1672 narrowScalarDst(MI
, NarrowTy
, 0, TargetOpcode::G_ZEXT
);
1673 Observer
.changedInstr(MI
);
1675 case TargetOpcode::G_PHI
: {
1676 // FIXME: add support for when SizeOp0 isn't an exact multiple of
1678 if (SizeOp0
% NarrowSize
!= 0)
1679 return UnableToLegalize
;
1681 unsigned NumParts
= SizeOp0
/ NarrowSize
;
1682 SmallVector
<Register
, 2> DstRegs(NumParts
);
1683 SmallVector
<SmallVector
<Register
, 2>, 2> SrcRegs(MI
.getNumOperands() / 2);
1684 Observer
.changingInstr(MI
);
1685 for (unsigned i
= 1; i
< MI
.getNumOperands(); i
+= 2) {
1686 MachineBasicBlock
&OpMBB
= *MI
.getOperand(i
+ 1).getMBB();
1687 MIRBuilder
.setInsertPt(OpMBB
, OpMBB
.getFirstTerminatorForward());
1688 extractParts(MI
.getOperand(i
).getReg(), NarrowTy
, NumParts
,
1689 SrcRegs
[i
/ 2], MIRBuilder
, MRI
);
1691 MachineBasicBlock
&MBB
= *MI
.getParent();
1692 MIRBuilder
.setInsertPt(MBB
, MI
);
1693 for (unsigned i
= 0; i
< NumParts
; ++i
) {
1694 DstRegs
[i
] = MRI
.createGenericVirtualRegister(NarrowTy
);
1695 MachineInstrBuilder MIB
=
1696 MIRBuilder
.buildInstr(TargetOpcode::G_PHI
).addDef(DstRegs
[i
]);
1697 for (unsigned j
= 1; j
< MI
.getNumOperands(); j
+= 2)
1698 MIB
.addUse(SrcRegs
[j
/ 2][i
]).add(MI
.getOperand(j
+ 1));
1700 MIRBuilder
.setInsertPt(MBB
, MBB
.getFirstNonPHI());
1701 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(0), DstRegs
);
1702 Observer
.changedInstr(MI
);
1703 MI
.eraseFromParent();
1706 case TargetOpcode::G_EXTRACT_VECTOR_ELT
:
1707 case TargetOpcode::G_INSERT_VECTOR_ELT
: {
1709 return UnableToLegalize
;
1711 int OpIdx
= MI
.getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT
? 2 : 3;
1712 Observer
.changingInstr(MI
);
1713 narrowScalarSrc(MI
, NarrowTy
, OpIdx
);
1714 Observer
.changedInstr(MI
);
1717 case TargetOpcode::G_ICMP
: {
1718 Register LHS
= MI
.getOperand(2).getReg();
1719 LLT SrcTy
= MRI
.getType(LHS
);
1720 CmpInst::Predicate Pred
=
1721 static_cast<CmpInst::Predicate
>(MI
.getOperand(1).getPredicate());
1723 LLT LeftoverTy
; // Example: s88 -> s64 (NarrowTy) + s24 (leftover)
1724 SmallVector
<Register
, 4> LHSPartRegs
, LHSLeftoverRegs
;
1725 if (!extractParts(LHS
, SrcTy
, NarrowTy
, LeftoverTy
, LHSPartRegs
,
1726 LHSLeftoverRegs
, MIRBuilder
, MRI
))
1727 return UnableToLegalize
;
1729 LLT Unused
; // Matches LeftoverTy; G_ICMP LHS and RHS are the same type.
1730 SmallVector
<Register
, 4> RHSPartRegs
, RHSLeftoverRegs
;
1731 if (!extractParts(MI
.getOperand(3).getReg(), SrcTy
, NarrowTy
, Unused
,
1732 RHSPartRegs
, RHSLeftoverRegs
, MIRBuilder
, MRI
))
1733 return UnableToLegalize
;
1735 // We now have the LHS and RHS of the compare split into narrow-type
1736 // registers, plus potentially some leftover type.
1737 Register Dst
= MI
.getOperand(0).getReg();
1738 LLT ResTy
= MRI
.getType(Dst
);
1739 if (ICmpInst::isEquality(Pred
)) {
1740 // For each part on the LHS and RHS, keep track of the result of XOR-ing
1741 // them together. For each equal part, the result should be all 0s. For
1742 // each non-equal part, we'll get at least one 1.
1743 auto Zero
= MIRBuilder
.buildConstant(NarrowTy
, 0);
1744 SmallVector
<Register
, 4> Xors
;
1745 for (auto LHSAndRHS
: zip(LHSPartRegs
, RHSPartRegs
)) {
1746 auto LHS
= std::get
<0>(LHSAndRHS
);
1747 auto RHS
= std::get
<1>(LHSAndRHS
);
1748 auto Xor
= MIRBuilder
.buildXor(NarrowTy
, LHS
, RHS
).getReg(0);
1749 Xors
.push_back(Xor
);
1752 // Build a G_XOR for each leftover register. Each G_XOR must be widened
1753 // to the desired narrow type so that we can OR them together later.
1754 SmallVector
<Register
, 4> WidenedXors
;
1755 for (auto LHSAndRHS
: zip(LHSLeftoverRegs
, RHSLeftoverRegs
)) {
1756 auto LHS
= std::get
<0>(LHSAndRHS
);
1757 auto RHS
= std::get
<1>(LHSAndRHS
);
1758 auto Xor
= MIRBuilder
.buildXor(LeftoverTy
, LHS
, RHS
).getReg(0);
1759 LLT GCDTy
= extractGCDType(WidenedXors
, NarrowTy
, LeftoverTy
, Xor
);
1760 buildLCMMergePieces(LeftoverTy
, NarrowTy
, GCDTy
, WidenedXors
,
1761 /* PadStrategy = */ TargetOpcode::G_ZEXT
);
1762 Xors
.insert(Xors
.end(), WidenedXors
.begin(), WidenedXors
.end());
1765 // Now, for each part we broke up, we know if they are equal/not equal
1766 // based off the G_XOR. We can OR these all together and compare against
1767 // 0 to get the result.
1768 assert(Xors
.size() >= 2 && "Should have gotten at least two Xors?");
1769 auto Or
= MIRBuilder
.buildOr(NarrowTy
, Xors
[0], Xors
[1]);
1770 for (unsigned I
= 2, E
= Xors
.size(); I
< E
; ++I
)
1771 Or
= MIRBuilder
.buildOr(NarrowTy
, Or
, Xors
[I
]);
1772 MIRBuilder
.buildICmp(Pred
, Dst
, Or
, Zero
);
1775 for (unsigned I
= 0, E
= LHSPartRegs
.size(); I
!= E
; ++I
) {
1777 CmpInst::Predicate PartPred
;
1779 if (I
== E
- 1 && LHSLeftoverRegs
.empty()) {
1783 PartPred
= ICmpInst::getUnsignedPredicate(Pred
);
1784 CmpOut
= MRI
.createGenericVirtualRegister(ResTy
);
1788 MIRBuilder
.buildICmp(PartPred
, CmpOut
, LHSPartRegs
[I
],
1791 auto Cmp
= MIRBuilder
.buildICmp(PartPred
, ResTy
, LHSPartRegs
[I
],
1793 auto CmpEq
= MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, ResTy
,
1794 LHSPartRegs
[I
], RHSPartRegs
[I
]);
1795 MIRBuilder
.buildSelect(CmpOut
, CmpEq
, CmpIn
, Cmp
);
1801 for (unsigned I
= 0, E
= LHSLeftoverRegs
.size(); I
!= E
; ++I
) {
1803 CmpInst::Predicate PartPred
;
1805 if (I
== E
- 1 && LHSLeftoverRegs
.empty()) {
1809 PartPred
= ICmpInst::getUnsignedPredicate(Pred
);
1810 CmpOut
= MRI
.createGenericVirtualRegister(ResTy
);
1814 MIRBuilder
.buildICmp(PartPred
, CmpOut
, LHSLeftoverRegs
[I
],
1815 RHSLeftoverRegs
[I
]);
1817 auto Cmp
= MIRBuilder
.buildICmp(PartPred
, ResTy
, LHSLeftoverRegs
[I
],
1818 RHSLeftoverRegs
[I
]);
1820 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, ResTy
,
1821 LHSLeftoverRegs
[I
], RHSLeftoverRegs
[I
]);
1822 MIRBuilder
.buildSelect(CmpOut
, CmpEq
, CmpIn
, Cmp
);
1828 MI
.eraseFromParent();
1831 case TargetOpcode::G_FCMP
:
1833 return UnableToLegalize
;
1835 Observer
.changingInstr(MI
);
1836 narrowScalarDst(MI
, NarrowTy
, 0, TargetOpcode::G_ZEXT
);
1837 Observer
.changedInstr(MI
);
1840 case TargetOpcode::G_SEXT_INREG
: {
1842 return UnableToLegalize
;
1844 int64_t SizeInBits
= MI
.getOperand(2).getImm();
1846 // So long as the new type has more bits than the bits we're extending we
1847 // don't need to break it apart.
1848 if (NarrowTy
.getScalarSizeInBits() > SizeInBits
) {
1849 Observer
.changingInstr(MI
);
1850 // We don't lose any non-extension bits by truncating the src and
1851 // sign-extending the dst.
1852 MachineOperand
&MO1
= MI
.getOperand(1);
1853 auto TruncMIB
= MIRBuilder
.buildTrunc(NarrowTy
, MO1
);
1854 MO1
.setReg(TruncMIB
.getReg(0));
1856 MachineOperand
&MO2
= MI
.getOperand(0);
1857 Register DstExt
= MRI
.createGenericVirtualRegister(NarrowTy
);
1858 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
1859 MIRBuilder
.buildSExt(MO2
, DstExt
);
1861 Observer
.changedInstr(MI
);
1865 // Break it apart. Components below the extension point are unmodified. The
1866 // component containing the extension point becomes a narrower SEXT_INREG.
1867 // Components above it are ashr'd from the component containing the
1869 if (SizeOp0
% NarrowSize
!= 0)
1870 return UnableToLegalize
;
1871 int NumParts
= SizeOp0
/ NarrowSize
;
1873 // List the registers where the destination will be scattered.
1874 SmallVector
<Register
, 2> DstRegs
;
1875 // List the registers where the source will be split.
1876 SmallVector
<Register
, 2> SrcRegs
;
1878 // Create all the temporary registers.
1879 for (int i
= 0; i
< NumParts
; ++i
) {
1880 Register SrcReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
1882 SrcRegs
.push_back(SrcReg
);
1885 // Explode the big arguments into smaller chunks.
1886 MIRBuilder
.buildUnmerge(SrcRegs
, MI
.getOperand(1));
1888 Register AshrCstReg
=
1889 MIRBuilder
.buildConstant(NarrowTy
, NarrowTy
.getScalarSizeInBits() - 1)
1891 Register FullExtensionReg
;
1892 Register PartialExtensionReg
;
1894 // Do the operation on each small part.
1895 for (int i
= 0; i
< NumParts
; ++i
) {
1896 if ((i
+ 1) * NarrowTy
.getScalarSizeInBits() <= SizeInBits
) {
1897 DstRegs
.push_back(SrcRegs
[i
]);
1898 PartialExtensionReg
= DstRegs
.back();
1899 } else if (i
* NarrowTy
.getScalarSizeInBits() >= SizeInBits
) {
1900 assert(PartialExtensionReg
&&
1901 "Expected to visit partial extension before full");
1902 if (FullExtensionReg
) {
1903 DstRegs
.push_back(FullExtensionReg
);
1907 MIRBuilder
.buildAShr(NarrowTy
, PartialExtensionReg
, AshrCstReg
)
1909 FullExtensionReg
= DstRegs
.back();
1914 TargetOpcode::G_SEXT_INREG
, {NarrowTy
},
1915 {SrcRegs
[i
], SizeInBits
% NarrowTy
.getScalarSizeInBits()})
1917 PartialExtensionReg
= DstRegs
.back();
1921 // Gather the destination registers into the final destination.
1922 Register DstReg
= MI
.getOperand(0).getReg();
1923 MIRBuilder
.buildMergeLikeInstr(DstReg
, DstRegs
);
1924 MI
.eraseFromParent();
1927 case TargetOpcode::G_BSWAP
:
1928 case TargetOpcode::G_BITREVERSE
: {
1929 if (SizeOp0
% NarrowSize
!= 0)
1930 return UnableToLegalize
;
1932 Observer
.changingInstr(MI
);
1933 SmallVector
<Register
, 2> SrcRegs
, DstRegs
;
1934 unsigned NumParts
= SizeOp0
/ NarrowSize
;
1935 extractParts(MI
.getOperand(1).getReg(), NarrowTy
, NumParts
, SrcRegs
,
1938 for (unsigned i
= 0; i
< NumParts
; ++i
) {
1939 auto DstPart
= MIRBuilder
.buildInstr(MI
.getOpcode(), {NarrowTy
},
1940 {SrcRegs
[NumParts
- 1 - i
]});
1941 DstRegs
.push_back(DstPart
.getReg(0));
1944 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(0), DstRegs
);
1946 Observer
.changedInstr(MI
);
1947 MI
.eraseFromParent();
1950 case TargetOpcode::G_PTR_ADD
:
1951 case TargetOpcode::G_PTRMASK
: {
1953 return UnableToLegalize
;
1954 Observer
.changingInstr(MI
);
1955 narrowScalarSrc(MI
, NarrowTy
, 2);
1956 Observer
.changedInstr(MI
);
1959 case TargetOpcode::G_FPTOUI
:
1960 case TargetOpcode::G_FPTOSI
:
1961 case TargetOpcode::G_FPTOUI_SAT
:
1962 case TargetOpcode::G_FPTOSI_SAT
:
1963 return narrowScalarFPTOI(MI
, TypeIdx
, NarrowTy
);
1964 case TargetOpcode::G_FPEXT
:
1966 return UnableToLegalize
;
1967 Observer
.changingInstr(MI
);
1968 narrowScalarDst(MI
, NarrowTy
, 0, TargetOpcode::G_FPEXT
);
1969 Observer
.changedInstr(MI
);
1971 case TargetOpcode::G_FLDEXP
:
1972 case TargetOpcode::G_STRICT_FLDEXP
:
1973 return narrowScalarFLDEXP(MI
, TypeIdx
, NarrowTy
);
1974 case TargetOpcode::G_VSCALE
: {
1975 Register Dst
= MI
.getOperand(0).getReg();
1976 LLT Ty
= MRI
.getType(Dst
);
1978 // Assume VSCALE(1) fits into a legal integer
1979 const APInt
One(NarrowTy
.getSizeInBits(), 1);
1980 auto VScaleBase
= MIRBuilder
.buildVScale(NarrowTy
, One
);
1981 auto ZExt
= MIRBuilder
.buildZExt(Ty
, VScaleBase
);
1982 auto C
= MIRBuilder
.buildConstant(Ty
, *MI
.getOperand(1).getCImm());
1983 MIRBuilder
.buildMul(Dst
, ZExt
, C
);
1985 MI
.eraseFromParent();
1991 Register
LegalizerHelper::coerceToScalar(Register Val
) {
1992 LLT Ty
= MRI
.getType(Val
);
1996 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
1997 LLT NewTy
= LLT::scalar(Ty
.getSizeInBits());
1998 if (Ty
.isPointer()) {
1999 if (DL
.isNonIntegralAddressSpace(Ty
.getAddressSpace()))
2001 return MIRBuilder
.buildPtrToInt(NewTy
, Val
).getReg(0);
2004 Register NewVal
= Val
;
2006 assert(Ty
.isVector());
2007 if (Ty
.isPointerVector())
2008 NewVal
= MIRBuilder
.buildPtrToInt(NewTy
, NewVal
).getReg(0);
2009 return MIRBuilder
.buildBitcast(NewTy
, NewVal
).getReg(0);
2012 void LegalizerHelper::widenScalarSrc(MachineInstr
&MI
, LLT WideTy
,
2013 unsigned OpIdx
, unsigned ExtOpcode
) {
2014 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2015 auto ExtB
= MIRBuilder
.buildInstr(ExtOpcode
, {WideTy
}, {MO
});
2016 MO
.setReg(ExtB
.getReg(0));
2019 void LegalizerHelper::narrowScalarSrc(MachineInstr
&MI
, LLT NarrowTy
,
2021 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2022 auto ExtB
= MIRBuilder
.buildTrunc(NarrowTy
, MO
);
2023 MO
.setReg(ExtB
.getReg(0));
2026 void LegalizerHelper::widenScalarDst(MachineInstr
&MI
, LLT WideTy
,
2027 unsigned OpIdx
, unsigned TruncOpcode
) {
2028 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2029 Register DstExt
= MRI
.createGenericVirtualRegister(WideTy
);
2030 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2031 MIRBuilder
.buildInstr(TruncOpcode
, {MO
}, {DstExt
});
2035 void LegalizerHelper::narrowScalarDst(MachineInstr
&MI
, LLT NarrowTy
,
2036 unsigned OpIdx
, unsigned ExtOpcode
) {
2037 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2038 Register DstTrunc
= MRI
.createGenericVirtualRegister(NarrowTy
);
2039 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2040 MIRBuilder
.buildInstr(ExtOpcode
, {MO
}, {DstTrunc
});
2041 MO
.setReg(DstTrunc
);
2044 void LegalizerHelper::moreElementsVectorDst(MachineInstr
&MI
, LLT WideTy
,
2046 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2047 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2048 Register Dst
= MO
.getReg();
2049 Register DstExt
= MRI
.createGenericVirtualRegister(WideTy
);
2051 MIRBuilder
.buildDeleteTrailingVectorElements(Dst
, DstExt
);
2054 void LegalizerHelper::moreElementsVectorSrc(MachineInstr
&MI
, LLT MoreTy
,
2056 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2057 SmallVector
<Register
, 8> Regs
;
2058 MO
.setReg(MIRBuilder
.buildPadVectorWithUndefElements(MoreTy
, MO
).getReg(0));
2061 void LegalizerHelper::bitcastSrc(MachineInstr
&MI
, LLT CastTy
, unsigned OpIdx
) {
2062 MachineOperand
&Op
= MI
.getOperand(OpIdx
);
2063 Op
.setReg(MIRBuilder
.buildBitcast(CastTy
, Op
).getReg(0));
2066 void LegalizerHelper::bitcastDst(MachineInstr
&MI
, LLT CastTy
, unsigned OpIdx
) {
2067 MachineOperand
&MO
= MI
.getOperand(OpIdx
);
2068 Register CastDst
= MRI
.createGenericVirtualRegister(CastTy
);
2069 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2070 MIRBuilder
.buildBitcast(MO
, CastDst
);
2074 LegalizerHelper::LegalizeResult
2075 LegalizerHelper::widenScalarMergeValues(MachineInstr
&MI
, unsigned TypeIdx
,
2078 return UnableToLegalize
;
2080 auto [DstReg
, DstTy
, Src1Reg
, Src1Ty
] = MI
.getFirst2RegLLTs();
2081 if (DstTy
.isVector())
2082 return UnableToLegalize
;
2084 LLT SrcTy
= MRI
.getType(Src1Reg
);
2085 const int DstSize
= DstTy
.getSizeInBits();
2086 const int SrcSize
= SrcTy
.getSizeInBits();
2087 const int WideSize
= WideTy
.getSizeInBits();
2088 const int NumMerge
= (DstSize
+ WideSize
- 1) / WideSize
;
2090 unsigned NumOps
= MI
.getNumOperands();
2091 unsigned NumSrc
= MI
.getNumOperands() - 1;
2092 unsigned PartSize
= DstTy
.getSizeInBits() / NumSrc
;
2094 if (WideSize
>= DstSize
) {
2095 // Directly pack the bits in the target type.
2096 Register ResultReg
= MIRBuilder
.buildZExt(WideTy
, Src1Reg
).getReg(0);
2098 for (unsigned I
= 2; I
!= NumOps
; ++I
) {
2099 const unsigned Offset
= (I
- 1) * PartSize
;
2101 Register SrcReg
= MI
.getOperand(I
).getReg();
2102 assert(MRI
.getType(SrcReg
) == LLT::scalar(PartSize
));
2104 auto ZextInput
= MIRBuilder
.buildZExt(WideTy
, SrcReg
);
2106 Register NextResult
= I
+ 1 == NumOps
&& WideTy
== DstTy
? DstReg
:
2107 MRI
.createGenericVirtualRegister(WideTy
);
2109 auto ShiftAmt
= MIRBuilder
.buildConstant(WideTy
, Offset
);
2110 auto Shl
= MIRBuilder
.buildShl(WideTy
, ZextInput
, ShiftAmt
);
2111 MIRBuilder
.buildOr(NextResult
, ResultReg
, Shl
);
2112 ResultReg
= NextResult
;
2115 if (WideSize
> DstSize
)
2116 MIRBuilder
.buildTrunc(DstReg
, ResultReg
);
2117 else if (DstTy
.isPointer())
2118 MIRBuilder
.buildIntToPtr(DstReg
, ResultReg
);
2120 MI
.eraseFromParent();
2124 // Unmerge the original values to the GCD type, and recombine to the next
2125 // multiple greater than the original type.
2127 // %3:_(s12) = G_MERGE_VALUES %0:_(s4), %1:_(s4), %2:_(s4) -> s6
2128 // %4:_(s2), %5:_(s2) = G_UNMERGE_VALUES %0
2129 // %6:_(s2), %7:_(s2) = G_UNMERGE_VALUES %1
2130 // %8:_(s2), %9:_(s2) = G_UNMERGE_VALUES %2
2131 // %10:_(s6) = G_MERGE_VALUES %4, %5, %6
2132 // %11:_(s6) = G_MERGE_VALUES %7, %8, %9
2133 // %12:_(s12) = G_MERGE_VALUES %10, %11
2135 // Padding with undef if necessary:
2137 // %2:_(s8) = G_MERGE_VALUES %0:_(s4), %1:_(s4) -> s6
2138 // %3:_(s2), %4:_(s2) = G_UNMERGE_VALUES %0
2139 // %5:_(s2), %6:_(s2) = G_UNMERGE_VALUES %1
2140 // %7:_(s2) = G_IMPLICIT_DEF
2141 // %8:_(s6) = G_MERGE_VALUES %3, %4, %5
2142 // %9:_(s6) = G_MERGE_VALUES %6, %7, %7
2143 // %10:_(s12) = G_MERGE_VALUES %8, %9
2145 const int GCD
= std::gcd(SrcSize
, WideSize
);
2146 LLT GCDTy
= LLT::scalar(GCD
);
2148 SmallVector
<Register
, 8> Parts
;
2149 SmallVector
<Register
, 8> NewMergeRegs
;
2150 SmallVector
<Register
, 8> Unmerges
;
2151 LLT WideDstTy
= LLT::scalar(NumMerge
* WideSize
);
2153 // Decompose the original operands if they don't evenly divide.
2154 for (const MachineOperand
&MO
: llvm::drop_begin(MI
.operands())) {
2155 Register SrcReg
= MO
.getReg();
2156 if (GCD
== SrcSize
) {
2157 Unmerges
.push_back(SrcReg
);
2159 auto Unmerge
= MIRBuilder
.buildUnmerge(GCDTy
, SrcReg
);
2160 for (int J
= 0, JE
= Unmerge
->getNumOperands() - 1; J
!= JE
; ++J
)
2161 Unmerges
.push_back(Unmerge
.getReg(J
));
2165 // Pad with undef to the next size that is a multiple of the requested size.
2166 if (static_cast<int>(Unmerges
.size()) != NumMerge
* WideSize
) {
2167 Register UndefReg
= MIRBuilder
.buildUndef(GCDTy
).getReg(0);
2168 for (int I
= Unmerges
.size(); I
!= NumMerge
* WideSize
; ++I
)
2169 Unmerges
.push_back(UndefReg
);
2172 const int PartsPerGCD
= WideSize
/ GCD
;
2174 // Build merges of each piece.
2175 ArrayRef
<Register
> Slicer(Unmerges
);
2176 for (int I
= 0; I
!= NumMerge
; ++I
, Slicer
= Slicer
.drop_front(PartsPerGCD
)) {
2178 MIRBuilder
.buildMergeLikeInstr(WideTy
, Slicer
.take_front(PartsPerGCD
));
2179 NewMergeRegs
.push_back(Merge
.getReg(0));
2182 // A truncate may be necessary if the requested type doesn't evenly divide the
2183 // original result type.
2184 if (DstTy
.getSizeInBits() == WideDstTy
.getSizeInBits()) {
2185 MIRBuilder
.buildMergeLikeInstr(DstReg
, NewMergeRegs
);
2187 auto FinalMerge
= MIRBuilder
.buildMergeLikeInstr(WideDstTy
, NewMergeRegs
);
2188 MIRBuilder
.buildTrunc(DstReg
, FinalMerge
.getReg(0));
2191 MI
.eraseFromParent();
2195 LegalizerHelper::LegalizeResult
2196 LegalizerHelper::widenScalarUnmergeValues(MachineInstr
&MI
, unsigned TypeIdx
,
2199 return UnableToLegalize
;
2201 int NumDst
= MI
.getNumOperands() - 1;
2202 Register SrcReg
= MI
.getOperand(NumDst
).getReg();
2203 LLT SrcTy
= MRI
.getType(SrcReg
);
2204 if (SrcTy
.isVector())
2205 return UnableToLegalize
;
2207 Register Dst0Reg
= MI
.getOperand(0).getReg();
2208 LLT DstTy
= MRI
.getType(Dst0Reg
);
2209 if (!DstTy
.isScalar())
2210 return UnableToLegalize
;
2212 if (WideTy
.getSizeInBits() >= SrcTy
.getSizeInBits()) {
2213 if (SrcTy
.isPointer()) {
2214 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
2215 if (DL
.isNonIntegralAddressSpace(SrcTy
.getAddressSpace())) {
2217 dbgs() << "Not casting non-integral address space integer\n");
2218 return UnableToLegalize
;
2221 SrcTy
= LLT::scalar(SrcTy
.getSizeInBits());
2222 SrcReg
= MIRBuilder
.buildPtrToInt(SrcTy
, SrcReg
).getReg(0);
2225 // Widen SrcTy to WideTy. This does not affect the result, but since the
2226 // user requested this size, it is probably better handled than SrcTy and
2227 // should reduce the total number of legalization artifacts.
2228 if (WideTy
.getSizeInBits() > SrcTy
.getSizeInBits()) {
2230 SrcReg
= MIRBuilder
.buildAnyExt(WideTy
, SrcReg
).getReg(0);
2233 // Theres no unmerge type to target. Directly extract the bits from the
2235 unsigned DstSize
= DstTy
.getSizeInBits();
2237 MIRBuilder
.buildTrunc(Dst0Reg
, SrcReg
);
2238 for (int I
= 1; I
!= NumDst
; ++I
) {
2239 auto ShiftAmt
= MIRBuilder
.buildConstant(SrcTy
, DstSize
* I
);
2240 auto Shr
= MIRBuilder
.buildLShr(SrcTy
, SrcReg
, ShiftAmt
);
2241 MIRBuilder
.buildTrunc(MI
.getOperand(I
), Shr
);
2244 MI
.eraseFromParent();
2248 // Extend the source to a wider type.
2249 LLT LCMTy
= getLCMType(SrcTy
, WideTy
);
2251 Register WideSrc
= SrcReg
;
2252 if (LCMTy
.getSizeInBits() != SrcTy
.getSizeInBits()) {
2253 // TODO: If this is an integral address space, cast to integer and anyext.
2254 if (SrcTy
.isPointer()) {
2255 LLVM_DEBUG(dbgs() << "Widening pointer source types not implemented\n");
2256 return UnableToLegalize
;
2259 WideSrc
= MIRBuilder
.buildAnyExt(LCMTy
, WideSrc
).getReg(0);
2262 auto Unmerge
= MIRBuilder
.buildUnmerge(WideTy
, WideSrc
);
2264 // Create a sequence of unmerges and merges to the original results. Since we
2265 // may have widened the source, we will need to pad the results with dead defs
2266 // to cover the source register.
2267 // e.g. widen s48 to s64:
2268 // %1:_(s48), %2:_(s48) = G_UNMERGE_VALUES %0:_(s96)
2271 // %4:_(s192) = G_ANYEXT %0:_(s96)
2272 // %5:_(s64), %6, %7 = G_UNMERGE_VALUES %4 ; Requested unmerge
2273 // ; unpack to GCD type, with extra dead defs
2274 // %8:_(s16), %9, %10, %11 = G_UNMERGE_VALUES %5:_(s64)
2275 // %12:_(s16), %13, dead %14, dead %15 = G_UNMERGE_VALUES %6:_(s64)
2276 // dead %16:_(s16), dead %17, dead %18, dead %18 = G_UNMERGE_VALUES %7:_(s64)
2277 // %1:_(s48) = G_MERGE_VALUES %8:_(s16), %9, %10 ; Remerge to destination
2278 // %2:_(s48) = G_MERGE_VALUES %11:_(s16), %12, %13 ; Remerge to destination
2279 const LLT GCDTy
= getGCDType(WideTy
, DstTy
);
2280 const int NumUnmerge
= Unmerge
->getNumOperands() - 1;
2281 const int PartsPerRemerge
= DstTy
.getSizeInBits() / GCDTy
.getSizeInBits();
2283 // Directly unmerge to the destination without going through a GCD type
2285 if (PartsPerRemerge
== 1) {
2286 const int PartsPerUnmerge
= WideTy
.getSizeInBits() / DstTy
.getSizeInBits();
2288 for (int I
= 0; I
!= NumUnmerge
; ++I
) {
2289 auto MIB
= MIRBuilder
.buildInstr(TargetOpcode::G_UNMERGE_VALUES
);
2291 for (int J
= 0; J
!= PartsPerUnmerge
; ++J
) {
2292 int Idx
= I
* PartsPerUnmerge
+ J
;
2294 MIB
.addDef(MI
.getOperand(Idx
).getReg());
2296 // Create dead def for excess components.
2297 MIB
.addDef(MRI
.createGenericVirtualRegister(DstTy
));
2301 MIB
.addUse(Unmerge
.getReg(I
));
2304 SmallVector
<Register
, 16> Parts
;
2305 for (int J
= 0; J
!= NumUnmerge
; ++J
)
2306 extractGCDType(Parts
, GCDTy
, Unmerge
.getReg(J
));
2308 SmallVector
<Register
, 8> RemergeParts
;
2309 for (int I
= 0; I
!= NumDst
; ++I
) {
2310 for (int J
= 0; J
< PartsPerRemerge
; ++J
) {
2311 const int Idx
= I
* PartsPerRemerge
+ J
;
2312 RemergeParts
.emplace_back(Parts
[Idx
]);
2315 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(I
).getReg(), RemergeParts
);
2316 RemergeParts
.clear();
2320 MI
.eraseFromParent();
2324 LegalizerHelper::LegalizeResult
2325 LegalizerHelper::widenScalarExtract(MachineInstr
&MI
, unsigned TypeIdx
,
2327 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
2328 unsigned Offset
= MI
.getOperand(2).getImm();
2331 if (SrcTy
.isVector() || DstTy
.isVector())
2332 return UnableToLegalize
;
2335 if (SrcTy
.isPointer()) {
2336 // Extracts from pointers can be handled only if they are really just
2338 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
2339 if (DL
.isNonIntegralAddressSpace(SrcTy
.getAddressSpace()))
2340 return UnableToLegalize
;
2342 LLT SrcAsIntTy
= LLT::scalar(SrcTy
.getSizeInBits());
2343 Src
= MIRBuilder
.buildPtrToInt(SrcAsIntTy
, Src
);
2347 if (DstTy
.isPointer())
2348 return UnableToLegalize
;
2351 // Avoid a shift in the degenerate case.
2352 MIRBuilder
.buildTrunc(DstReg
,
2353 MIRBuilder
.buildAnyExtOrTrunc(WideTy
, Src
));
2354 MI
.eraseFromParent();
2358 // Do a shift in the source type.
2359 LLT ShiftTy
= SrcTy
;
2360 if (WideTy
.getSizeInBits() > SrcTy
.getSizeInBits()) {
2361 Src
= MIRBuilder
.buildAnyExt(WideTy
, Src
);
2365 auto LShr
= MIRBuilder
.buildLShr(
2366 ShiftTy
, Src
, MIRBuilder
.buildConstant(ShiftTy
, Offset
));
2367 MIRBuilder
.buildTrunc(DstReg
, LShr
);
2368 MI
.eraseFromParent();
2372 if (SrcTy
.isScalar()) {
2373 Observer
.changingInstr(MI
);
2374 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2375 Observer
.changedInstr(MI
);
2379 if (!SrcTy
.isVector())
2380 return UnableToLegalize
;
2382 if (DstTy
!= SrcTy
.getElementType())
2383 return UnableToLegalize
;
2385 if (Offset
% SrcTy
.getScalarSizeInBits() != 0)
2386 return UnableToLegalize
;
2388 Observer
.changingInstr(MI
);
2389 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2391 MI
.getOperand(2).setImm((WideTy
.getSizeInBits() / SrcTy
.getSizeInBits()) *
2393 widenScalarDst(MI
, WideTy
.getScalarType(), 0);
2394 Observer
.changedInstr(MI
);
2398 LegalizerHelper::LegalizeResult
2399 LegalizerHelper::widenScalarInsert(MachineInstr
&MI
, unsigned TypeIdx
,
2401 if (TypeIdx
!= 0 || WideTy
.isVector())
2402 return UnableToLegalize
;
2403 Observer
.changingInstr(MI
);
2404 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2405 widenScalarDst(MI
, WideTy
);
2406 Observer
.changedInstr(MI
);
2410 LegalizerHelper::LegalizeResult
2411 LegalizerHelper::widenScalarAddSubOverflow(MachineInstr
&MI
, unsigned TypeIdx
,
2415 std::optional
<Register
> CarryIn
;
2416 switch (MI
.getOpcode()) {
2418 llvm_unreachable("Unexpected opcode!");
2419 case TargetOpcode::G_SADDO
:
2420 Opcode
= TargetOpcode::G_ADD
;
2421 ExtOpcode
= TargetOpcode::G_SEXT
;
2423 case TargetOpcode::G_SSUBO
:
2424 Opcode
= TargetOpcode::G_SUB
;
2425 ExtOpcode
= TargetOpcode::G_SEXT
;
2427 case TargetOpcode::G_UADDO
:
2428 Opcode
= TargetOpcode::G_ADD
;
2429 ExtOpcode
= TargetOpcode::G_ZEXT
;
2431 case TargetOpcode::G_USUBO
:
2432 Opcode
= TargetOpcode::G_SUB
;
2433 ExtOpcode
= TargetOpcode::G_ZEXT
;
2435 case TargetOpcode::G_SADDE
:
2436 Opcode
= TargetOpcode::G_UADDE
;
2437 ExtOpcode
= TargetOpcode::G_SEXT
;
2438 CarryIn
= MI
.getOperand(4).getReg();
2440 case TargetOpcode::G_SSUBE
:
2441 Opcode
= TargetOpcode::G_USUBE
;
2442 ExtOpcode
= TargetOpcode::G_SEXT
;
2443 CarryIn
= MI
.getOperand(4).getReg();
2445 case TargetOpcode::G_UADDE
:
2446 Opcode
= TargetOpcode::G_UADDE
;
2447 ExtOpcode
= TargetOpcode::G_ZEXT
;
2448 CarryIn
= MI
.getOperand(4).getReg();
2450 case TargetOpcode::G_USUBE
:
2451 Opcode
= TargetOpcode::G_USUBE
;
2452 ExtOpcode
= TargetOpcode::G_ZEXT
;
2453 CarryIn
= MI
.getOperand(4).getReg();
2458 unsigned BoolExtOp
= MIRBuilder
.getBoolExtOp(WideTy
.isVector(), false);
2460 Observer
.changingInstr(MI
);
2462 widenScalarSrc(MI
, WideTy
, 4, BoolExtOp
);
2463 widenScalarDst(MI
, WideTy
, 1);
2465 Observer
.changedInstr(MI
);
2469 auto LHSExt
= MIRBuilder
.buildInstr(ExtOpcode
, {WideTy
}, {MI
.getOperand(2)});
2470 auto RHSExt
= MIRBuilder
.buildInstr(ExtOpcode
, {WideTy
}, {MI
.getOperand(3)});
2471 // Do the arithmetic in the larger type.
2474 LLT CarryOutTy
= MRI
.getType(MI
.getOperand(1).getReg());
2476 .buildInstr(Opcode
, {WideTy
, CarryOutTy
},
2477 {LHSExt
, RHSExt
, *CarryIn
})
2480 NewOp
= MIRBuilder
.buildInstr(Opcode
, {WideTy
}, {LHSExt
, RHSExt
}).getReg(0);
2482 LLT OrigTy
= MRI
.getType(MI
.getOperand(0).getReg());
2483 auto TruncOp
= MIRBuilder
.buildTrunc(OrigTy
, NewOp
);
2484 auto ExtOp
= MIRBuilder
.buildInstr(ExtOpcode
, {WideTy
}, {TruncOp
});
2485 // There is no overflow if the ExtOp is the same as NewOp.
2486 MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, MI
.getOperand(1), NewOp
, ExtOp
);
2487 // Now trunc the NewOp to the original result.
2488 MIRBuilder
.buildTrunc(MI
.getOperand(0), NewOp
);
2489 MI
.eraseFromParent();
2493 LegalizerHelper::LegalizeResult
2494 LegalizerHelper::widenScalarAddSubShlSat(MachineInstr
&MI
, unsigned TypeIdx
,
2496 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_SADDSAT
||
2497 MI
.getOpcode() == TargetOpcode::G_SSUBSAT
||
2498 MI
.getOpcode() == TargetOpcode::G_SSHLSAT
;
2499 bool IsShift
= MI
.getOpcode() == TargetOpcode::G_SSHLSAT
||
2500 MI
.getOpcode() == TargetOpcode::G_USHLSAT
;
2501 // We can convert this to:
2502 // 1. Any extend iN to iM
2504 // 3. [US][ADD|SUB|SHL]SAT
2507 // It may be more efficient to lower this to a min and a max operation in
2508 // the higher precision arithmetic if the promoted operation isn't legal,
2509 // but this decision is up to the target's lowering request.
2510 Register DstReg
= MI
.getOperand(0).getReg();
2512 unsigned NewBits
= WideTy
.getScalarSizeInBits();
2513 unsigned SHLAmount
= NewBits
- MRI
.getType(DstReg
).getScalarSizeInBits();
2515 // Shifts must zero-extend the RHS to preserve the unsigned quantity, and
2516 // must not left shift the RHS to preserve the shift amount.
2517 auto LHS
= MIRBuilder
.buildAnyExt(WideTy
, MI
.getOperand(1));
2518 auto RHS
= IsShift
? MIRBuilder
.buildZExt(WideTy
, MI
.getOperand(2))
2519 : MIRBuilder
.buildAnyExt(WideTy
, MI
.getOperand(2));
2520 auto ShiftK
= MIRBuilder
.buildConstant(WideTy
, SHLAmount
);
2521 auto ShiftL
= MIRBuilder
.buildShl(WideTy
, LHS
, ShiftK
);
2522 auto ShiftR
= IsShift
? RHS
: MIRBuilder
.buildShl(WideTy
, RHS
, ShiftK
);
2524 auto WideInst
= MIRBuilder
.buildInstr(MI
.getOpcode(), {WideTy
},
2525 {ShiftL
, ShiftR
}, MI
.getFlags());
2527 // Use a shift that will preserve the number of sign bits when the trunc is
2529 auto Result
= IsSigned
? MIRBuilder
.buildAShr(WideTy
, WideInst
, ShiftK
)
2530 : MIRBuilder
.buildLShr(WideTy
, WideInst
, ShiftK
);
2532 MIRBuilder
.buildTrunc(DstReg
, Result
);
2533 MI
.eraseFromParent();
2537 LegalizerHelper::LegalizeResult
2538 LegalizerHelper::widenScalarMulo(MachineInstr
&MI
, unsigned TypeIdx
,
2541 Observer
.changingInstr(MI
);
2542 widenScalarDst(MI
, WideTy
, 1);
2543 Observer
.changedInstr(MI
);
2547 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_SMULO
;
2548 auto [Result
, OriginalOverflow
, LHS
, RHS
] = MI
.getFirst4Regs();
2549 LLT SrcTy
= MRI
.getType(LHS
);
2550 LLT OverflowTy
= MRI
.getType(OriginalOverflow
);
2551 unsigned SrcBitWidth
= SrcTy
.getScalarSizeInBits();
2553 // To determine if the result overflowed in the larger type, we extend the
2554 // input to the larger type, do the multiply (checking if it overflows),
2555 // then also check the high bits of the result to see if overflow happened
2557 unsigned ExtOp
= IsSigned
? TargetOpcode::G_SEXT
: TargetOpcode::G_ZEXT
;
2558 auto LeftOperand
= MIRBuilder
.buildInstr(ExtOp
, {WideTy
}, {LHS
});
2559 auto RightOperand
= MIRBuilder
.buildInstr(ExtOp
, {WideTy
}, {RHS
});
2561 // Multiplication cannot overflow if the WideTy is >= 2 * original width,
2562 // so we don't need to check the overflow result of larger type Mulo.
2563 bool WideMulCanOverflow
= WideTy
.getScalarSizeInBits() < 2 * SrcBitWidth
;
2566 WideMulCanOverflow
? MI
.getOpcode() : (unsigned)TargetOpcode::G_MUL
;
2568 MachineInstrBuilder Mulo
;
2569 if (WideMulCanOverflow
)
2570 Mulo
= MIRBuilder
.buildInstr(MulOpc
, {WideTy
, OverflowTy
},
2571 {LeftOperand
, RightOperand
});
2573 Mulo
= MIRBuilder
.buildInstr(MulOpc
, {WideTy
}, {LeftOperand
, RightOperand
});
2575 auto Mul
= Mulo
->getOperand(0);
2576 MIRBuilder
.buildTrunc(Result
, Mul
);
2578 MachineInstrBuilder ExtResult
;
2579 // Overflow occurred if it occurred in the larger type, or if the high part
2580 // of the result does not zero/sign-extend the low part. Check this second
2581 // possibility first.
2583 // For signed, overflow occurred when the high part does not sign-extend
2585 ExtResult
= MIRBuilder
.buildSExtInReg(WideTy
, Mul
, SrcBitWidth
);
2587 // Unsigned overflow occurred when the high part does not zero-extend the
2589 ExtResult
= MIRBuilder
.buildZExtInReg(WideTy
, Mul
, SrcBitWidth
);
2592 if (WideMulCanOverflow
) {
2594 MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, OverflowTy
, Mul
, ExtResult
);
2595 // Finally check if the multiplication in the larger type itself overflowed.
2596 MIRBuilder
.buildOr(OriginalOverflow
, Mulo
->getOperand(1), Overflow
);
2598 MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, OriginalOverflow
, Mul
, ExtResult
);
2600 MI
.eraseFromParent();
2604 LegalizerHelper::LegalizeResult
2605 LegalizerHelper::widenScalar(MachineInstr
&MI
, unsigned TypeIdx
, LLT WideTy
) {
2606 unsigned Opcode
= MI
.getOpcode();
2609 return UnableToLegalize
;
2610 case TargetOpcode::G_ATOMICRMW_XCHG
:
2611 case TargetOpcode::G_ATOMICRMW_ADD
:
2612 case TargetOpcode::G_ATOMICRMW_SUB
:
2613 case TargetOpcode::G_ATOMICRMW_AND
:
2614 case TargetOpcode::G_ATOMICRMW_OR
:
2615 case TargetOpcode::G_ATOMICRMW_XOR
:
2616 case TargetOpcode::G_ATOMICRMW_MIN
:
2617 case TargetOpcode::G_ATOMICRMW_MAX
:
2618 case TargetOpcode::G_ATOMICRMW_UMIN
:
2619 case TargetOpcode::G_ATOMICRMW_UMAX
:
2620 assert(TypeIdx
== 0 && "atomicrmw with second scalar type");
2621 Observer
.changingInstr(MI
);
2622 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ANYEXT
);
2623 widenScalarDst(MI
, WideTy
, 0);
2624 Observer
.changedInstr(MI
);
2626 case TargetOpcode::G_ATOMIC_CMPXCHG
:
2627 assert(TypeIdx
== 0 && "G_ATOMIC_CMPXCHG with second scalar type");
2628 Observer
.changingInstr(MI
);
2629 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ANYEXT
);
2630 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_ANYEXT
);
2631 widenScalarDst(MI
, WideTy
, 0);
2632 Observer
.changedInstr(MI
);
2634 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
:
2636 Observer
.changingInstr(MI
);
2637 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_ANYEXT
);
2638 widenScalarSrc(MI
, WideTy
, 4, TargetOpcode::G_ANYEXT
);
2639 widenScalarDst(MI
, WideTy
, 0);
2640 Observer
.changedInstr(MI
);
2643 assert(TypeIdx
== 1 &&
2644 "G_ATOMIC_CMPXCHG_WITH_SUCCESS with third scalar type");
2645 Observer
.changingInstr(MI
);
2646 widenScalarDst(MI
, WideTy
, 1);
2647 Observer
.changedInstr(MI
);
2649 case TargetOpcode::G_EXTRACT
:
2650 return widenScalarExtract(MI
, TypeIdx
, WideTy
);
2651 case TargetOpcode::G_INSERT
:
2652 return widenScalarInsert(MI
, TypeIdx
, WideTy
);
2653 case TargetOpcode::G_MERGE_VALUES
:
2654 return widenScalarMergeValues(MI
, TypeIdx
, WideTy
);
2655 case TargetOpcode::G_UNMERGE_VALUES
:
2656 return widenScalarUnmergeValues(MI
, TypeIdx
, WideTy
);
2657 case TargetOpcode::G_SADDO
:
2658 case TargetOpcode::G_SSUBO
:
2659 case TargetOpcode::G_UADDO
:
2660 case TargetOpcode::G_USUBO
:
2661 case TargetOpcode::G_SADDE
:
2662 case TargetOpcode::G_SSUBE
:
2663 case TargetOpcode::G_UADDE
:
2664 case TargetOpcode::G_USUBE
:
2665 return widenScalarAddSubOverflow(MI
, TypeIdx
, WideTy
);
2666 case TargetOpcode::G_UMULO
:
2667 case TargetOpcode::G_SMULO
:
2668 return widenScalarMulo(MI
, TypeIdx
, WideTy
);
2669 case TargetOpcode::G_SADDSAT
:
2670 case TargetOpcode::G_SSUBSAT
:
2671 case TargetOpcode::G_SSHLSAT
:
2672 case TargetOpcode::G_UADDSAT
:
2673 case TargetOpcode::G_USUBSAT
:
2674 case TargetOpcode::G_USHLSAT
:
2675 return widenScalarAddSubShlSat(MI
, TypeIdx
, WideTy
);
2676 case TargetOpcode::G_CTTZ
:
2677 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
2678 case TargetOpcode::G_CTLZ
:
2679 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
2680 case TargetOpcode::G_CTPOP
: {
2682 Observer
.changingInstr(MI
);
2683 widenScalarDst(MI
, WideTy
, 0);
2684 Observer
.changedInstr(MI
);
2688 Register SrcReg
= MI
.getOperand(1).getReg();
2690 // First extend the input.
2691 unsigned ExtOpc
= Opcode
== TargetOpcode::G_CTTZ
||
2692 Opcode
== TargetOpcode::G_CTTZ_ZERO_UNDEF
2693 ? TargetOpcode::G_ANYEXT
2694 : TargetOpcode::G_ZEXT
;
2695 auto MIBSrc
= MIRBuilder
.buildInstr(ExtOpc
, {WideTy
}, {SrcReg
});
2696 LLT CurTy
= MRI
.getType(SrcReg
);
2697 unsigned NewOpc
= Opcode
;
2698 if (NewOpc
== TargetOpcode::G_CTTZ
) {
2699 // The count is the same in the larger type except if the original
2700 // value was zero. This can be handled by setting the bit just off
2701 // the top of the original type.
2703 APInt::getOneBitSet(WideTy
.getSizeInBits(), CurTy
.getSizeInBits());
2704 MIBSrc
= MIRBuilder
.buildOr(
2705 WideTy
, MIBSrc
, MIRBuilder
.buildConstant(WideTy
, TopBit
));
2706 // Now we know the operand is non-zero, use the more relaxed opcode.
2707 NewOpc
= TargetOpcode::G_CTTZ_ZERO_UNDEF
;
2710 unsigned SizeDiff
= WideTy
.getSizeInBits() - CurTy
.getSizeInBits();
2712 if (Opcode
== TargetOpcode::G_CTLZ_ZERO_UNDEF
) {
2713 // An optimization where the result is the CTLZ after the left shift by
2714 // (Difference in widety and current ty), that is,
2715 // MIBSrc = MIBSrc << (sizeinbits(WideTy) - sizeinbits(CurTy))
2716 // Result = ctlz MIBSrc
2717 MIBSrc
= MIRBuilder
.buildShl(WideTy
, MIBSrc
,
2718 MIRBuilder
.buildConstant(WideTy
, SizeDiff
));
2721 // Perform the operation at the larger size.
2722 auto MIBNewOp
= MIRBuilder
.buildInstr(NewOpc
, {WideTy
}, {MIBSrc
});
2723 // This is already the correct result for CTPOP and CTTZs
2724 if (Opcode
== TargetOpcode::G_CTLZ
) {
2725 // The correct result is NewOp - (Difference in widety and current ty).
2726 MIBNewOp
= MIRBuilder
.buildSub(
2727 WideTy
, MIBNewOp
, MIRBuilder
.buildConstant(WideTy
, SizeDiff
));
2730 MIRBuilder
.buildZExtOrTrunc(MI
.getOperand(0), MIBNewOp
);
2731 MI
.eraseFromParent();
2734 case TargetOpcode::G_BSWAP
: {
2735 Observer
.changingInstr(MI
);
2736 Register DstReg
= MI
.getOperand(0).getReg();
2738 Register ShrReg
= MRI
.createGenericVirtualRegister(WideTy
);
2739 Register DstExt
= MRI
.createGenericVirtualRegister(WideTy
);
2740 Register ShiftAmtReg
= MRI
.createGenericVirtualRegister(WideTy
);
2741 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2743 MI
.getOperand(0).setReg(DstExt
);
2745 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2747 LLT Ty
= MRI
.getType(DstReg
);
2748 unsigned DiffBits
= WideTy
.getScalarSizeInBits() - Ty
.getScalarSizeInBits();
2749 MIRBuilder
.buildConstant(ShiftAmtReg
, DiffBits
);
2750 MIRBuilder
.buildLShr(ShrReg
, DstExt
, ShiftAmtReg
);
2752 MIRBuilder
.buildTrunc(DstReg
, ShrReg
);
2753 Observer
.changedInstr(MI
);
2756 case TargetOpcode::G_BITREVERSE
: {
2757 Observer
.changingInstr(MI
);
2759 Register DstReg
= MI
.getOperand(0).getReg();
2760 LLT Ty
= MRI
.getType(DstReg
);
2761 unsigned DiffBits
= WideTy
.getScalarSizeInBits() - Ty
.getScalarSizeInBits();
2763 Register DstExt
= MRI
.createGenericVirtualRegister(WideTy
);
2764 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2765 MI
.getOperand(0).setReg(DstExt
);
2766 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2768 auto ShiftAmt
= MIRBuilder
.buildConstant(WideTy
, DiffBits
);
2769 auto Shift
= MIRBuilder
.buildLShr(WideTy
, DstExt
, ShiftAmt
);
2770 MIRBuilder
.buildTrunc(DstReg
, Shift
);
2771 Observer
.changedInstr(MI
);
2774 case TargetOpcode::G_FREEZE
:
2775 case TargetOpcode::G_CONSTANT_FOLD_BARRIER
:
2776 Observer
.changingInstr(MI
);
2777 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2778 widenScalarDst(MI
, WideTy
);
2779 Observer
.changedInstr(MI
);
2782 case TargetOpcode::G_ABS
:
2783 Observer
.changingInstr(MI
);
2784 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_SEXT
);
2785 widenScalarDst(MI
, WideTy
);
2786 Observer
.changedInstr(MI
);
2789 case TargetOpcode::G_ADD
:
2790 case TargetOpcode::G_AND
:
2791 case TargetOpcode::G_MUL
:
2792 case TargetOpcode::G_OR
:
2793 case TargetOpcode::G_XOR
:
2794 case TargetOpcode::G_SUB
:
2795 case TargetOpcode::G_SHUFFLE_VECTOR
:
2796 // Perform operation at larger width (any extension is fines here, high bits
2797 // don't affect the result) and then truncate the result back to the
2799 Observer
.changingInstr(MI
);
2800 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2801 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ANYEXT
);
2802 widenScalarDst(MI
, WideTy
);
2803 Observer
.changedInstr(MI
);
2806 case TargetOpcode::G_SBFX
:
2807 case TargetOpcode::G_UBFX
:
2808 Observer
.changingInstr(MI
);
2811 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2812 widenScalarDst(MI
, WideTy
);
2814 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2815 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_ZEXT
);
2818 Observer
.changedInstr(MI
);
2821 case TargetOpcode::G_SHL
:
2822 Observer
.changingInstr(MI
);
2825 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
2826 widenScalarDst(MI
, WideTy
);
2828 assert(TypeIdx
== 1);
2829 // The "number of bits to shift" operand must preserve its value as an
2830 // unsigned integer:
2831 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2834 Observer
.changedInstr(MI
);
2837 case TargetOpcode::G_ROTR
:
2838 case TargetOpcode::G_ROTL
:
2840 return UnableToLegalize
;
2842 Observer
.changingInstr(MI
);
2843 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2844 Observer
.changedInstr(MI
);
2847 case TargetOpcode::G_SDIV
:
2848 case TargetOpcode::G_SREM
:
2849 case TargetOpcode::G_SMIN
:
2850 case TargetOpcode::G_SMAX
:
2851 Observer
.changingInstr(MI
);
2852 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_SEXT
);
2853 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_SEXT
);
2854 widenScalarDst(MI
, WideTy
);
2855 Observer
.changedInstr(MI
);
2858 case TargetOpcode::G_SDIVREM
:
2859 Observer
.changingInstr(MI
);
2860 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_SEXT
);
2861 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_SEXT
);
2862 widenScalarDst(MI
, WideTy
);
2863 widenScalarDst(MI
, WideTy
, 1);
2864 Observer
.changedInstr(MI
);
2867 case TargetOpcode::G_ASHR
:
2868 case TargetOpcode::G_LSHR
:
2869 Observer
.changingInstr(MI
);
2872 unsigned CvtOp
= Opcode
== TargetOpcode::G_ASHR
? TargetOpcode::G_SEXT
2873 : TargetOpcode::G_ZEXT
;
2875 widenScalarSrc(MI
, WideTy
, 1, CvtOp
);
2876 widenScalarDst(MI
, WideTy
);
2878 assert(TypeIdx
== 1);
2879 // The "number of bits to shift" operand must preserve its value as an
2880 // unsigned integer:
2881 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2884 Observer
.changedInstr(MI
);
2886 case TargetOpcode::G_UDIV
:
2887 case TargetOpcode::G_UREM
:
2888 Observer
.changingInstr(MI
);
2889 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ZEXT
);
2890 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2891 widenScalarDst(MI
, WideTy
);
2892 Observer
.changedInstr(MI
);
2894 case TargetOpcode::G_UDIVREM
:
2895 Observer
.changingInstr(MI
);
2896 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
2897 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_ZEXT
);
2898 widenScalarDst(MI
, WideTy
);
2899 widenScalarDst(MI
, WideTy
, 1);
2900 Observer
.changedInstr(MI
);
2902 case TargetOpcode::G_UMIN
:
2903 case TargetOpcode::G_UMAX
: {
2904 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
2906 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
2908 TLI
.isSExtCheaperThanZExt(getApproximateEVTForLLT(Ty
, Ctx
),
2909 getApproximateEVTForLLT(WideTy
, Ctx
))
2910 ? TargetOpcode::G_SEXT
2911 : TargetOpcode::G_ZEXT
;
2913 Observer
.changingInstr(MI
);
2914 widenScalarSrc(MI
, WideTy
, 1, ExtOpc
);
2915 widenScalarSrc(MI
, WideTy
, 2, ExtOpc
);
2916 widenScalarDst(MI
, WideTy
);
2917 Observer
.changedInstr(MI
);
2921 case TargetOpcode::G_SELECT
:
2922 Observer
.changingInstr(MI
);
2924 // Perform operation at larger width (any extension is fine here, high
2925 // bits don't affect the result) and then truncate the result back to the
2927 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ANYEXT
);
2928 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_ANYEXT
);
2929 widenScalarDst(MI
, WideTy
);
2931 bool IsVec
= MRI
.getType(MI
.getOperand(1).getReg()).isVector();
2932 // Explicit extension is required here since high bits affect the result.
2933 widenScalarSrc(MI
, WideTy
, 1, MIRBuilder
.getBoolExtOp(IsVec
, false));
2935 Observer
.changedInstr(MI
);
2938 case TargetOpcode::G_FPTOSI
:
2939 case TargetOpcode::G_FPTOUI
:
2940 case TargetOpcode::G_INTRINSIC_LRINT
:
2941 case TargetOpcode::G_INTRINSIC_LLRINT
:
2942 case TargetOpcode::G_IS_FPCLASS
:
2943 Observer
.changingInstr(MI
);
2946 widenScalarDst(MI
, WideTy
);
2948 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_FPEXT
);
2950 Observer
.changedInstr(MI
);
2952 case TargetOpcode::G_SITOFP
:
2953 Observer
.changingInstr(MI
);
2956 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
2958 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_SEXT
);
2960 Observer
.changedInstr(MI
);
2962 case TargetOpcode::G_UITOFP
:
2963 Observer
.changingInstr(MI
);
2966 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
2968 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ZEXT
);
2970 Observer
.changedInstr(MI
);
2972 case TargetOpcode::G_FPTOSI_SAT
:
2973 case TargetOpcode::G_FPTOUI_SAT
:
2974 Observer
.changingInstr(MI
);
2977 Register OldDst
= MI
.getOperand(0).getReg();
2978 LLT Ty
= MRI
.getType(OldDst
);
2979 Register ExtReg
= MRI
.createGenericVirtualRegister(WideTy
);
2981 MI
.getOperand(0).setReg(ExtReg
);
2982 uint64_t ShortBits
= Ty
.getScalarSizeInBits();
2983 uint64_t WideBits
= WideTy
.getScalarSizeInBits();
2984 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
2985 if (Opcode
== TargetOpcode::G_FPTOSI_SAT
) {
2986 // z = i16 fptosi_sat(a)
2988 // x = i32 fptosi_sat(a)
2989 // y = smin(x, 32767)
2990 // z = smax(y, -32768)
2991 auto MaxVal
= MIRBuilder
.buildConstant(
2992 WideTy
, APInt::getSignedMaxValue(ShortBits
).sext(WideBits
));
2993 auto MinVal
= MIRBuilder
.buildConstant(
2994 WideTy
, APInt::getSignedMinValue(ShortBits
).sext(WideBits
));
2996 MIRBuilder
.buildSMin(WideTy
, ExtReg
, MaxVal
).getReg(0);
2997 NewDst
= MIRBuilder
.buildSMax(WideTy
, MidReg
, MinVal
).getReg(0);
2999 // z = i16 fptoui_sat(a)
3001 // x = i32 fptoui_sat(a)
3002 // y = smin(x, 65535)
3003 auto MaxVal
= MIRBuilder
.buildConstant(
3004 WideTy
, APInt::getAllOnes(ShortBits
).zext(WideBits
));
3005 NewDst
= MIRBuilder
.buildUMin(WideTy
, ExtReg
, MaxVal
).getReg(0);
3007 MIRBuilder
.buildTrunc(OldDst
, NewDst
);
3009 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_FPEXT
);
3011 Observer
.changedInstr(MI
);
3013 case TargetOpcode::G_LOAD
:
3014 case TargetOpcode::G_SEXTLOAD
:
3015 case TargetOpcode::G_ZEXTLOAD
:
3016 Observer
.changingInstr(MI
);
3017 widenScalarDst(MI
, WideTy
);
3018 Observer
.changedInstr(MI
);
3021 case TargetOpcode::G_STORE
: {
3023 return UnableToLegalize
;
3025 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
3026 assert(!Ty
.isPointerOrPointerVector() && "Can't widen type");
3027 if (!Ty
.isScalar()) {
3028 // We need to widen the vector element type.
3029 Observer
.changingInstr(MI
);
3030 widenScalarSrc(MI
, WideTy
, 0, TargetOpcode::G_ANYEXT
);
3031 // We also need to adjust the MMO to turn this into a truncating store.
3032 MachineMemOperand
&MMO
= **MI
.memoperands_begin();
3033 MachineFunction
&MF
= MIRBuilder
.getMF();
3034 auto *NewMMO
= MF
.getMachineMemOperand(&MMO
, MMO
.getPointerInfo(), Ty
);
3035 MI
.setMemRefs(MF
, {NewMMO
});
3036 Observer
.changedInstr(MI
);
3040 Observer
.changingInstr(MI
);
3042 unsigned ExtType
= Ty
.getScalarSizeInBits() == 1 ?
3043 TargetOpcode::G_ZEXT
: TargetOpcode::G_ANYEXT
;
3044 widenScalarSrc(MI
, WideTy
, 0, ExtType
);
3046 Observer
.changedInstr(MI
);
3049 case TargetOpcode::G_CONSTANT
: {
3050 MachineOperand
&SrcMO
= MI
.getOperand(1);
3051 LLVMContext
&Ctx
= MIRBuilder
.getMF().getFunction().getContext();
3052 unsigned ExtOpc
= LI
.getExtOpcodeForWideningConstant(
3053 MRI
.getType(MI
.getOperand(0).getReg()));
3054 assert((ExtOpc
== TargetOpcode::G_ZEXT
|| ExtOpc
== TargetOpcode::G_SEXT
||
3055 ExtOpc
== TargetOpcode::G_ANYEXT
) &&
3057 const APInt
&SrcVal
= SrcMO
.getCImm()->getValue();
3058 const APInt
&Val
= (ExtOpc
== TargetOpcode::G_SEXT
)
3059 ? SrcVal
.sext(WideTy
.getSizeInBits())
3060 : SrcVal
.zext(WideTy
.getSizeInBits());
3061 Observer
.changingInstr(MI
);
3062 SrcMO
.setCImm(ConstantInt::get(Ctx
, Val
));
3064 widenScalarDst(MI
, WideTy
);
3065 Observer
.changedInstr(MI
);
3068 case TargetOpcode::G_FCONSTANT
: {
3069 // To avoid changing the bits of the constant due to extension to a larger
3070 // type and then using G_FPTRUNC, we simply convert to a G_CONSTANT.
3071 MachineOperand
&SrcMO
= MI
.getOperand(1);
3072 APInt Val
= SrcMO
.getFPImm()->getValueAPF().bitcastToAPInt();
3073 MIRBuilder
.setInstrAndDebugLoc(MI
);
3074 auto IntCst
= MIRBuilder
.buildConstant(MI
.getOperand(0).getReg(), Val
);
3075 widenScalarDst(*IntCst
, WideTy
, 0, TargetOpcode::G_TRUNC
);
3076 MI
.eraseFromParent();
3079 case TargetOpcode::G_IMPLICIT_DEF
: {
3080 Observer
.changingInstr(MI
);
3081 widenScalarDst(MI
, WideTy
);
3082 Observer
.changedInstr(MI
);
3085 case TargetOpcode::G_BRCOND
:
3086 Observer
.changingInstr(MI
);
3087 widenScalarSrc(MI
, WideTy
, 0, MIRBuilder
.getBoolExtOp(false, false));
3088 Observer
.changedInstr(MI
);
3091 case TargetOpcode::G_FCMP
:
3092 Observer
.changingInstr(MI
);
3094 widenScalarDst(MI
, WideTy
);
3096 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_FPEXT
);
3097 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_FPEXT
);
3099 Observer
.changedInstr(MI
);
3102 case TargetOpcode::G_ICMP
:
3103 Observer
.changingInstr(MI
);
3105 widenScalarDst(MI
, WideTy
);
3107 LLT SrcTy
= MRI
.getType(MI
.getOperand(2).getReg());
3108 CmpInst::Predicate Pred
=
3109 static_cast<CmpInst::Predicate
>(MI
.getOperand(1).getPredicate());
3111 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
3112 unsigned ExtOpcode
=
3113 (CmpInst::isSigned(Pred
) ||
3114 TLI
.isSExtCheaperThanZExt(getApproximateEVTForLLT(SrcTy
, Ctx
),
3115 getApproximateEVTForLLT(WideTy
, Ctx
)))
3116 ? TargetOpcode::G_SEXT
3117 : TargetOpcode::G_ZEXT
;
3118 widenScalarSrc(MI
, WideTy
, 2, ExtOpcode
);
3119 widenScalarSrc(MI
, WideTy
, 3, ExtOpcode
);
3121 Observer
.changedInstr(MI
);
3124 case TargetOpcode::G_PTR_ADD
:
3125 assert(TypeIdx
== 1 && "unable to legalize pointer of G_PTR_ADD");
3126 Observer
.changingInstr(MI
);
3127 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_SEXT
);
3128 Observer
.changedInstr(MI
);
3131 case TargetOpcode::G_PHI
: {
3132 assert(TypeIdx
== 0 && "Expecting only Idx 0");
3134 Observer
.changingInstr(MI
);
3135 for (unsigned I
= 1; I
< MI
.getNumOperands(); I
+= 2) {
3136 MachineBasicBlock
&OpMBB
= *MI
.getOperand(I
+ 1).getMBB();
3137 MIRBuilder
.setInsertPt(OpMBB
, OpMBB
.getFirstTerminatorForward());
3138 widenScalarSrc(MI
, WideTy
, I
, TargetOpcode::G_ANYEXT
);
3141 MachineBasicBlock
&MBB
= *MI
.getParent();
3142 MIRBuilder
.setInsertPt(MBB
, --MBB
.getFirstNonPHI());
3143 widenScalarDst(MI
, WideTy
);
3144 Observer
.changedInstr(MI
);
3147 case TargetOpcode::G_EXTRACT_VECTOR_ELT
: {
3149 Register VecReg
= MI
.getOperand(1).getReg();
3150 LLT VecTy
= MRI
.getType(VecReg
);
3151 Observer
.changingInstr(MI
);
3154 MI
, LLT::vector(VecTy
.getElementCount(), WideTy
.getSizeInBits()), 1,
3155 TargetOpcode::G_ANYEXT
);
3157 widenScalarDst(MI
, WideTy
, 0);
3158 Observer
.changedInstr(MI
);
3163 return UnableToLegalize
;
3164 Observer
.changingInstr(MI
);
3165 // TODO: Probably should be zext
3166 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_SEXT
);
3167 Observer
.changedInstr(MI
);
3170 case TargetOpcode::G_INSERT_VECTOR_ELT
: {
3172 Observer
.changingInstr(MI
);
3173 const LLT WideEltTy
= WideTy
.getElementType();
3175 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
3176 widenScalarSrc(MI
, WideEltTy
, 2, TargetOpcode::G_ANYEXT
);
3177 widenScalarDst(MI
, WideTy
, 0);
3178 Observer
.changedInstr(MI
);
3183 Observer
.changingInstr(MI
);
3185 Register VecReg
= MI
.getOperand(1).getReg();
3186 LLT VecTy
= MRI
.getType(VecReg
);
3187 LLT WideVecTy
= LLT::vector(VecTy
.getElementCount(), WideTy
);
3189 widenScalarSrc(MI
, WideVecTy
, 1, TargetOpcode::G_ANYEXT
);
3190 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ANYEXT
);
3191 widenScalarDst(MI
, WideVecTy
, 0);
3192 Observer
.changedInstr(MI
);
3197 Observer
.changingInstr(MI
);
3198 // TODO: Probably should be zext
3199 widenScalarSrc(MI
, WideTy
, 3, TargetOpcode::G_SEXT
);
3200 Observer
.changedInstr(MI
);
3204 return UnableToLegalize
;
3206 case TargetOpcode::G_FADD
:
3207 case TargetOpcode::G_FMUL
:
3208 case TargetOpcode::G_FSUB
:
3209 case TargetOpcode::G_FMA
:
3210 case TargetOpcode::G_FMAD
:
3211 case TargetOpcode::G_FNEG
:
3212 case TargetOpcode::G_FABS
:
3213 case TargetOpcode::G_FCANONICALIZE
:
3214 case TargetOpcode::G_FMINNUM
:
3215 case TargetOpcode::G_FMAXNUM
:
3216 case TargetOpcode::G_FMINNUM_IEEE
:
3217 case TargetOpcode::G_FMAXNUM_IEEE
:
3218 case TargetOpcode::G_FMINIMUM
:
3219 case TargetOpcode::G_FMAXIMUM
:
3220 case TargetOpcode::G_FDIV
:
3221 case TargetOpcode::G_FREM
:
3222 case TargetOpcode::G_FCEIL
:
3223 case TargetOpcode::G_FFLOOR
:
3224 case TargetOpcode::G_FCOS
:
3225 case TargetOpcode::G_FSIN
:
3226 case TargetOpcode::G_FTAN
:
3227 case TargetOpcode::G_FACOS
:
3228 case TargetOpcode::G_FASIN
:
3229 case TargetOpcode::G_FATAN
:
3230 case TargetOpcode::G_FATAN2
:
3231 case TargetOpcode::G_FCOSH
:
3232 case TargetOpcode::G_FSINH
:
3233 case TargetOpcode::G_FTANH
:
3234 case TargetOpcode::G_FLOG10
:
3235 case TargetOpcode::G_FLOG
:
3236 case TargetOpcode::G_FLOG2
:
3237 case TargetOpcode::G_FRINT
:
3238 case TargetOpcode::G_FNEARBYINT
:
3239 case TargetOpcode::G_FSQRT
:
3240 case TargetOpcode::G_FEXP
:
3241 case TargetOpcode::G_FEXP2
:
3242 case TargetOpcode::G_FEXP10
:
3243 case TargetOpcode::G_FPOW
:
3244 case TargetOpcode::G_INTRINSIC_TRUNC
:
3245 case TargetOpcode::G_INTRINSIC_ROUND
:
3246 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
:
3247 assert(TypeIdx
== 0);
3248 Observer
.changingInstr(MI
);
3250 for (unsigned I
= 1, E
= MI
.getNumOperands(); I
!= E
; ++I
)
3251 widenScalarSrc(MI
, WideTy
, I
, TargetOpcode::G_FPEXT
);
3253 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
3254 Observer
.changedInstr(MI
);
3256 case TargetOpcode::G_FPOWI
:
3257 case TargetOpcode::G_FLDEXP
:
3258 case TargetOpcode::G_STRICT_FLDEXP
: {
3260 if (Opcode
== TargetOpcode::G_STRICT_FLDEXP
)
3261 return UnableToLegalize
;
3263 Observer
.changingInstr(MI
);
3264 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_FPEXT
);
3265 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
3266 Observer
.changedInstr(MI
);
3271 // For some reason SelectionDAG tries to promote to a libcall without
3272 // actually changing the integer type for promotion.
3273 Observer
.changingInstr(MI
);
3274 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_SEXT
);
3275 Observer
.changedInstr(MI
);
3279 return UnableToLegalize
;
3281 case TargetOpcode::G_FFREXP
: {
3282 Observer
.changingInstr(MI
);
3285 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_FPEXT
);
3286 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
3288 widenScalarDst(MI
, WideTy
, 1);
3291 Observer
.changedInstr(MI
);
3294 case TargetOpcode::G_INTTOPTR
:
3296 return UnableToLegalize
;
3298 Observer
.changingInstr(MI
);
3299 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ZEXT
);
3300 Observer
.changedInstr(MI
);
3302 case TargetOpcode::G_PTRTOINT
:
3304 return UnableToLegalize
;
3306 Observer
.changingInstr(MI
);
3307 widenScalarDst(MI
, WideTy
, 0);
3308 Observer
.changedInstr(MI
);
3310 case TargetOpcode::G_BUILD_VECTOR
: {
3311 Observer
.changingInstr(MI
);
3313 const LLT WideEltTy
= TypeIdx
== 1 ? WideTy
: WideTy
.getElementType();
3314 for (int I
= 1, E
= MI
.getNumOperands(); I
!= E
; ++I
)
3315 widenScalarSrc(MI
, WideEltTy
, I
, TargetOpcode::G_ANYEXT
);
3317 // Avoid changing the result vector type if the source element type was
3320 MI
.setDesc(MIRBuilder
.getTII().get(TargetOpcode::G_BUILD_VECTOR_TRUNC
));
3322 widenScalarDst(MI
, WideTy
, 0);
3325 Observer
.changedInstr(MI
);
3328 case TargetOpcode::G_SEXT_INREG
:
3330 return UnableToLegalize
;
3332 Observer
.changingInstr(MI
);
3333 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
3334 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_TRUNC
);
3335 Observer
.changedInstr(MI
);
3337 case TargetOpcode::G_PTRMASK
: {
3339 return UnableToLegalize
;
3340 Observer
.changingInstr(MI
);
3341 widenScalarSrc(MI
, WideTy
, 2, TargetOpcode::G_ZEXT
);
3342 Observer
.changedInstr(MI
);
3345 case TargetOpcode::G_VECREDUCE_FADD
:
3346 case TargetOpcode::G_VECREDUCE_FMUL
:
3347 case TargetOpcode::G_VECREDUCE_FMIN
:
3348 case TargetOpcode::G_VECREDUCE_FMAX
:
3349 case TargetOpcode::G_VECREDUCE_FMINIMUM
:
3350 case TargetOpcode::G_VECREDUCE_FMAXIMUM
: {
3352 return UnableToLegalize
;
3353 Observer
.changingInstr(MI
);
3354 Register VecReg
= MI
.getOperand(1).getReg();
3355 LLT VecTy
= MRI
.getType(VecReg
);
3356 LLT WideVecTy
= VecTy
.isVector()
3357 ? LLT::vector(VecTy
.getElementCount(), WideTy
)
3359 widenScalarSrc(MI
, WideVecTy
, 1, TargetOpcode::G_FPEXT
);
3360 widenScalarDst(MI
, WideTy
, 0, TargetOpcode::G_FPTRUNC
);
3361 Observer
.changedInstr(MI
);
3364 case TargetOpcode::G_VSCALE
: {
3365 MachineOperand
&SrcMO
= MI
.getOperand(1);
3366 LLVMContext
&Ctx
= MIRBuilder
.getMF().getFunction().getContext();
3367 const APInt
&SrcVal
= SrcMO
.getCImm()->getValue();
3368 // The CImm is always a signed value
3369 const APInt Val
= SrcVal
.sext(WideTy
.getSizeInBits());
3370 Observer
.changingInstr(MI
);
3371 SrcMO
.setCImm(ConstantInt::get(Ctx
, Val
));
3372 widenScalarDst(MI
, WideTy
);
3373 Observer
.changedInstr(MI
);
3376 case TargetOpcode::G_SPLAT_VECTOR
: {
3378 return UnableToLegalize
;
3380 Observer
.changingInstr(MI
);
3381 widenScalarSrc(MI
, WideTy
, 1, TargetOpcode::G_ANYEXT
);
3382 Observer
.changedInstr(MI
);
3385 case TargetOpcode::G_INSERT_SUBVECTOR
: {
3387 return UnableToLegalize
;
3389 GInsertSubvector
&IS
= cast
<GInsertSubvector
>(MI
);
3390 Register BigVec
= IS
.getBigVec();
3391 Register SubVec
= IS
.getSubVec();
3393 LLT SubVecTy
= MRI
.getType(SubVec
);
3394 LLT SubVecWideTy
= SubVecTy
.changeElementType(WideTy
.getElementType());
3396 // Widen the G_INSERT_SUBVECTOR
3397 auto BigZExt
= MIRBuilder
.buildZExt(WideTy
, BigVec
);
3398 auto SubZExt
= MIRBuilder
.buildZExt(SubVecWideTy
, SubVec
);
3399 auto WideInsert
= MIRBuilder
.buildInsertSubvector(WideTy
, BigZExt
, SubZExt
,
3402 // Truncate back down
3403 auto SplatZero
= MIRBuilder
.buildSplatVector(
3404 WideTy
, MIRBuilder
.buildConstant(WideTy
.getElementType(), 0));
3405 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_NE
, IS
.getReg(0), WideInsert
,
3408 MI
.eraseFromParent();
3415 static void getUnmergePieces(SmallVectorImpl
<Register
> &Pieces
,
3416 MachineIRBuilder
&B
, Register Src
, LLT Ty
) {
3417 auto Unmerge
= B
.buildUnmerge(Ty
, Src
);
3418 for (int I
= 0, E
= Unmerge
->getNumOperands() - 1; I
!= E
; ++I
)
3419 Pieces
.push_back(Unmerge
.getReg(I
));
3422 static void emitLoadFromConstantPool(Register DstReg
, const Constant
*ConstVal
,
3423 MachineIRBuilder
&MIRBuilder
) {
3424 MachineRegisterInfo
&MRI
= *MIRBuilder
.getMRI();
3425 MachineFunction
&MF
= MIRBuilder
.getMF();
3426 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
3427 unsigned AddrSpace
= DL
.getDefaultGlobalsAddressSpace();
3428 LLT AddrPtrTy
= LLT::pointer(AddrSpace
, DL
.getPointerSizeInBits(AddrSpace
));
3429 LLT DstLLT
= MRI
.getType(DstReg
);
3431 Align
Alignment(DL
.getABITypeAlign(ConstVal
->getType()));
3433 auto Addr
= MIRBuilder
.buildConstantPool(
3435 MF
.getConstantPool()->getConstantPoolIndex(ConstVal
, Alignment
));
3437 MachineMemOperand
*MMO
=
3438 MF
.getMachineMemOperand(MachinePointerInfo::getConstantPool(MF
),
3439 MachineMemOperand::MOLoad
, DstLLT
, Alignment
);
3441 MIRBuilder
.buildLoadInstr(TargetOpcode::G_LOAD
, DstReg
, Addr
, *MMO
);
3444 LegalizerHelper::LegalizeResult
3445 LegalizerHelper::lowerConstant(MachineInstr
&MI
) {
3446 const MachineOperand
&ConstOperand
= MI
.getOperand(1);
3447 const Constant
*ConstantVal
= ConstOperand
.getCImm();
3449 emitLoadFromConstantPool(MI
.getOperand(0).getReg(), ConstantVal
, MIRBuilder
);
3450 MI
.eraseFromParent();
3455 LegalizerHelper::LegalizeResult
3456 LegalizerHelper::lowerFConstant(MachineInstr
&MI
) {
3457 const MachineOperand
&ConstOperand
= MI
.getOperand(1);
3458 const Constant
*ConstantVal
= ConstOperand
.getFPImm();
3460 emitLoadFromConstantPool(MI
.getOperand(0).getReg(), ConstantVal
, MIRBuilder
);
3461 MI
.eraseFromParent();
3466 LegalizerHelper::LegalizeResult
3467 LegalizerHelper::lowerBitcast(MachineInstr
&MI
) {
3468 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
3469 if (SrcTy
.isVector()) {
3470 LLT SrcEltTy
= SrcTy
.getElementType();
3471 SmallVector
<Register
, 8> SrcRegs
;
3473 if (DstTy
.isVector()) {
3474 int NumDstElt
= DstTy
.getNumElements();
3475 int NumSrcElt
= SrcTy
.getNumElements();
3477 LLT DstEltTy
= DstTy
.getElementType();
3478 LLT DstCastTy
= DstEltTy
; // Intermediate bitcast result type
3479 LLT SrcPartTy
= SrcEltTy
; // Original unmerge result type.
3481 // If there's an element size mismatch, insert intermediate casts to match
3482 // the result element type.
3483 if (NumSrcElt
< NumDstElt
) { // Source element type is larger.
3484 // %1:_(<4 x s8>) = G_BITCAST %0:_(<2 x s16>)
3488 // %2:_(s16), %3:_(s16) = G_UNMERGE_VALUES %0
3489 // %3:_(<2 x s8>) = G_BITCAST %2
3490 // %4:_(<2 x s8>) = G_BITCAST %3
3491 // %1:_(<4 x s16>) = G_CONCAT_VECTORS %3, %4
3492 DstCastTy
= LLT::fixed_vector(NumDstElt
/ NumSrcElt
, DstEltTy
);
3493 SrcPartTy
= SrcEltTy
;
3494 } else if (NumSrcElt
> NumDstElt
) { // Source element type is smaller.
3496 // %1:_(<2 x s16>) = G_BITCAST %0:_(<4 x s8>)
3500 // %2:_(<2 x s8>), %3:_(<2 x s8>) = G_UNMERGE_VALUES %0
3501 // %3:_(s16) = G_BITCAST %2
3502 // %4:_(s16) = G_BITCAST %3
3503 // %1:_(<2 x s16>) = G_BUILD_VECTOR %3, %4
3504 SrcPartTy
= LLT::fixed_vector(NumSrcElt
/ NumDstElt
, SrcEltTy
);
3505 DstCastTy
= DstEltTy
;
3508 getUnmergePieces(SrcRegs
, MIRBuilder
, Src
, SrcPartTy
);
3509 for (Register
&SrcReg
: SrcRegs
)
3510 SrcReg
= MIRBuilder
.buildBitcast(DstCastTy
, SrcReg
).getReg(0);
3512 getUnmergePieces(SrcRegs
, MIRBuilder
, Src
, SrcEltTy
);
3514 MIRBuilder
.buildMergeLikeInstr(Dst
, SrcRegs
);
3515 MI
.eraseFromParent();
3519 if (DstTy
.isVector()) {
3520 SmallVector
<Register
, 8> SrcRegs
;
3521 getUnmergePieces(SrcRegs
, MIRBuilder
, Src
, DstTy
.getElementType());
3522 MIRBuilder
.buildMergeLikeInstr(Dst
, SrcRegs
);
3523 MI
.eraseFromParent();
3527 return UnableToLegalize
;
3530 /// Figure out the bit offset into a register when coercing a vector index for
3531 /// the wide element type. This is only for the case when promoting vector to
3532 /// one with larger elements.
3535 /// %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3536 /// %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3537 static Register
getBitcastWiderVectorElementOffset(MachineIRBuilder
&B
,
3539 unsigned NewEltSize
,
3540 unsigned OldEltSize
) {
3541 const unsigned Log2EltRatio
= Log2_32(NewEltSize
/ OldEltSize
);
3542 LLT IdxTy
= B
.getMRI()->getType(Idx
);
3544 // Now figure out the amount we need to shift to get the target bits.
3545 auto OffsetMask
= B
.buildConstant(
3546 IdxTy
, ~(APInt::getAllOnes(IdxTy
.getSizeInBits()) << Log2EltRatio
));
3547 auto OffsetIdx
= B
.buildAnd(IdxTy
, Idx
, OffsetMask
);
3548 return B
.buildShl(IdxTy
, OffsetIdx
,
3549 B
.buildConstant(IdxTy
, Log2_32(OldEltSize
))).getReg(0);
3552 /// Perform a G_EXTRACT_VECTOR_ELT in a different sized vector element. If this
3553 /// is casting to a vector with a smaller element size, perform multiple element
3554 /// extracts and merge the results. If this is coercing to a vector with larger
3555 /// elements, index the bitcasted vector and extract the target element with bit
3556 /// operations. This is intended to force the indexing in the native register
3557 /// size for architectures that can dynamically index the register file.
3558 LegalizerHelper::LegalizeResult
3559 LegalizerHelper::bitcastExtractVectorElt(MachineInstr
&MI
, unsigned TypeIdx
,
3562 return UnableToLegalize
;
3564 auto [Dst
, DstTy
, SrcVec
, SrcVecTy
, Idx
, IdxTy
] = MI
.getFirst3RegLLTs();
3566 LLT SrcEltTy
= SrcVecTy
.getElementType();
3567 unsigned NewNumElts
= CastTy
.isVector() ? CastTy
.getNumElements() : 1;
3568 unsigned OldNumElts
= SrcVecTy
.getNumElements();
3570 LLT NewEltTy
= CastTy
.isVector() ? CastTy
.getElementType() : CastTy
;
3571 Register CastVec
= MIRBuilder
.buildBitcast(CastTy
, SrcVec
).getReg(0);
3573 const unsigned NewEltSize
= NewEltTy
.getSizeInBits();
3574 const unsigned OldEltSize
= SrcEltTy
.getSizeInBits();
3575 if (NewNumElts
> OldNumElts
) {
3576 // Decreasing the vector element size
3578 // e.g. i64 = extract_vector_elt x:v2i64, y:i32
3580 // v4i32:castx = bitcast x:v2i64
3583 // (v2i32 build_vector (i32 (extract_vector_elt castx, (2 * y))),
3584 // (i32 (extract_vector_elt castx, (2 * y + 1)))
3586 if (NewNumElts
% OldNumElts
!= 0)
3587 return UnableToLegalize
;
3589 // Type of the intermediate result vector.
3590 const unsigned NewEltsPerOldElt
= NewNumElts
/ OldNumElts
;
3592 LLT::scalarOrVector(ElementCount::getFixed(NewEltsPerOldElt
), NewEltTy
);
3594 auto NewEltsPerOldEltK
= MIRBuilder
.buildConstant(IdxTy
, NewEltsPerOldElt
);
3596 SmallVector
<Register
, 8> NewOps(NewEltsPerOldElt
);
3597 auto NewBaseIdx
= MIRBuilder
.buildMul(IdxTy
, Idx
, NewEltsPerOldEltK
);
3599 for (unsigned I
= 0; I
< NewEltsPerOldElt
; ++I
) {
3600 auto IdxOffset
= MIRBuilder
.buildConstant(IdxTy
, I
);
3601 auto TmpIdx
= MIRBuilder
.buildAdd(IdxTy
, NewBaseIdx
, IdxOffset
);
3602 auto Elt
= MIRBuilder
.buildExtractVectorElement(NewEltTy
, CastVec
, TmpIdx
);
3603 NewOps
[I
] = Elt
.getReg(0);
3606 auto NewVec
= MIRBuilder
.buildBuildVector(MidTy
, NewOps
);
3607 MIRBuilder
.buildBitcast(Dst
, NewVec
);
3608 MI
.eraseFromParent();
3612 if (NewNumElts
< OldNumElts
) {
3613 if (NewEltSize
% OldEltSize
!= 0)
3614 return UnableToLegalize
;
3616 // This only depends on powers of 2 because we use bit tricks to figure out
3617 // the bit offset we need to shift to get the target element. A general
3618 // expansion could emit division/multiply.
3619 if (!isPowerOf2_32(NewEltSize
/ OldEltSize
))
3620 return UnableToLegalize
;
3622 // Increasing the vector element size.
3623 // %elt:_(small_elt) = G_EXTRACT_VECTOR_ELT %vec:_(<N x small_elt>), %idx
3627 // %cast = G_BITCAST %vec
3628 // %scaled_idx = G_LSHR %idx, Log2(DstEltSize / SrcEltSize)
3629 // %wide_elt = G_EXTRACT_VECTOR_ELT %cast, %scaled_idx
3630 // %offset_idx = G_AND %idx, ~(-1 << Log2(DstEltSize / SrcEltSize))
3631 // %offset_bits = G_SHL %offset_idx, Log2(SrcEltSize)
3632 // %elt_bits = G_LSHR %wide_elt, %offset_bits
3633 // %elt = G_TRUNC %elt_bits
3635 const unsigned Log2EltRatio
= Log2_32(NewEltSize
/ OldEltSize
);
3636 auto Log2Ratio
= MIRBuilder
.buildConstant(IdxTy
, Log2EltRatio
);
3638 // Divide to get the index in the wider element type.
3639 auto ScaledIdx
= MIRBuilder
.buildLShr(IdxTy
, Idx
, Log2Ratio
);
3641 Register WideElt
= CastVec
;
3642 if (CastTy
.isVector()) {
3643 WideElt
= MIRBuilder
.buildExtractVectorElement(NewEltTy
, CastVec
,
3644 ScaledIdx
).getReg(0);
3647 // Compute the bit offset into the register of the target element.
3648 Register OffsetBits
= getBitcastWiderVectorElementOffset(
3649 MIRBuilder
, Idx
, NewEltSize
, OldEltSize
);
3651 // Shift the wide element to get the target element.
3652 auto ExtractedBits
= MIRBuilder
.buildLShr(NewEltTy
, WideElt
, OffsetBits
);
3653 MIRBuilder
.buildTrunc(Dst
, ExtractedBits
);
3654 MI
.eraseFromParent();
3658 return UnableToLegalize
;
3661 /// Emit code to insert \p InsertReg into \p TargetRet at \p OffsetBits in \p
3662 /// TargetReg, while preserving other bits in \p TargetReg.
3664 /// (InsertReg << Offset) | (TargetReg & ~(-1 >> InsertReg.size()) << Offset)
3665 static Register
buildBitFieldInsert(MachineIRBuilder
&B
,
3666 Register TargetReg
, Register InsertReg
,
3667 Register OffsetBits
) {
3668 LLT TargetTy
= B
.getMRI()->getType(TargetReg
);
3669 LLT InsertTy
= B
.getMRI()->getType(InsertReg
);
3670 auto ZextVal
= B
.buildZExt(TargetTy
, InsertReg
);
3671 auto ShiftedInsertVal
= B
.buildShl(TargetTy
, ZextVal
, OffsetBits
);
3673 // Produce a bitmask of the value to insert
3674 auto EltMask
= B
.buildConstant(
3675 TargetTy
, APInt::getLowBitsSet(TargetTy
.getSizeInBits(),
3676 InsertTy
.getSizeInBits()));
3677 // Shift it into position
3678 auto ShiftedMask
= B
.buildShl(TargetTy
, EltMask
, OffsetBits
);
3679 auto InvShiftedMask
= B
.buildNot(TargetTy
, ShiftedMask
);
3681 // Clear out the bits in the wide element
3682 auto MaskedOldElt
= B
.buildAnd(TargetTy
, TargetReg
, InvShiftedMask
);
3684 // The value to insert has all zeros already, so stick it into the masked
3686 return B
.buildOr(TargetTy
, MaskedOldElt
, ShiftedInsertVal
).getReg(0);
3689 /// Perform a G_INSERT_VECTOR_ELT in a different sized vector element. If this
3690 /// is increasing the element size, perform the indexing in the target element
3691 /// type, and use bit operations to insert at the element position. This is
3692 /// intended for architectures that can dynamically index the register file and
3693 /// want to force indexing in the native register size.
3694 LegalizerHelper::LegalizeResult
3695 LegalizerHelper::bitcastInsertVectorElt(MachineInstr
&MI
, unsigned TypeIdx
,
3698 return UnableToLegalize
;
3700 auto [Dst
, DstTy
, SrcVec
, SrcVecTy
, Val
, ValTy
, Idx
, IdxTy
] =
3701 MI
.getFirst4RegLLTs();
3704 LLT VecEltTy
= VecTy
.getElementType();
3705 LLT NewEltTy
= CastTy
.isVector() ? CastTy
.getElementType() : CastTy
;
3706 const unsigned NewEltSize
= NewEltTy
.getSizeInBits();
3707 const unsigned OldEltSize
= VecEltTy
.getSizeInBits();
3709 unsigned NewNumElts
= CastTy
.isVector() ? CastTy
.getNumElements() : 1;
3710 unsigned OldNumElts
= VecTy
.getNumElements();
3712 Register CastVec
= MIRBuilder
.buildBitcast(CastTy
, SrcVec
).getReg(0);
3713 if (NewNumElts
< OldNumElts
) {
3714 if (NewEltSize
% OldEltSize
!= 0)
3715 return UnableToLegalize
;
3717 // This only depends on powers of 2 because we use bit tricks to figure out
3718 // the bit offset we need to shift to get the target element. A general
3719 // expansion could emit division/multiply.
3720 if (!isPowerOf2_32(NewEltSize
/ OldEltSize
))
3721 return UnableToLegalize
;
3723 const unsigned Log2EltRatio
= Log2_32(NewEltSize
/ OldEltSize
);
3724 auto Log2Ratio
= MIRBuilder
.buildConstant(IdxTy
, Log2EltRatio
);
3726 // Divide to get the index in the wider element type.
3727 auto ScaledIdx
= MIRBuilder
.buildLShr(IdxTy
, Idx
, Log2Ratio
);
3729 Register ExtractedElt
= CastVec
;
3730 if (CastTy
.isVector()) {
3731 ExtractedElt
= MIRBuilder
.buildExtractVectorElement(NewEltTy
, CastVec
,
3732 ScaledIdx
).getReg(0);
3735 // Compute the bit offset into the register of the target element.
3736 Register OffsetBits
= getBitcastWiderVectorElementOffset(
3737 MIRBuilder
, Idx
, NewEltSize
, OldEltSize
);
3739 Register InsertedElt
= buildBitFieldInsert(MIRBuilder
, ExtractedElt
,
3741 if (CastTy
.isVector()) {
3742 InsertedElt
= MIRBuilder
.buildInsertVectorElement(
3743 CastTy
, CastVec
, InsertedElt
, ScaledIdx
).getReg(0);
3746 MIRBuilder
.buildBitcast(Dst
, InsertedElt
);
3747 MI
.eraseFromParent();
3751 return UnableToLegalize
;
3754 // This attempts to handle G_CONCAT_VECTORS with illegal operands, particularly
3755 // those that have smaller than legal operands.
3757 // <16 x s8> = G_CONCAT_VECTORS <4 x s8>, <4 x s8>, <4 x s8>, <4 x s8>
3761 // s32 = G_BITCAST <4 x s8>
3762 // s32 = G_BITCAST <4 x s8>
3763 // s32 = G_BITCAST <4 x s8>
3764 // s32 = G_BITCAST <4 x s8>
3765 // <4 x s32> = G_BUILD_VECTOR s32, s32, s32, s32
3766 // <16 x s8> = G_BITCAST <4 x s32>
3767 LegalizerHelper::LegalizeResult
3768 LegalizerHelper::bitcastConcatVector(MachineInstr
&MI
, unsigned TypeIdx
,
3770 // Convert it to CONCAT instruction
3771 auto ConcatMI
= dyn_cast
<GConcatVectors
>(&MI
);
3773 return UnableToLegalize
;
3776 // Check if bitcast is Legal
3777 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
3778 LLT SrcScalTy
= LLT::scalar(SrcTy
.getSizeInBits());
3780 // Check if the build vector is Legal
3781 if (!LI
.isLegal({TargetOpcode::G_BUILD_VECTOR
, {CastTy
, SrcScalTy
}})) {
3782 return UnableToLegalize
;
3785 // Bitcast the sources
3786 SmallVector
<Register
> BitcastRegs
;
3787 for (unsigned i
= 0; i
< ConcatMI
->getNumSources(); i
++) {
3788 BitcastRegs
.push_back(
3789 MIRBuilder
.buildBitcast(SrcScalTy
, ConcatMI
->getSourceReg(i
))
3793 // Build the scalar values into a vector
3795 MIRBuilder
.buildBuildVector(CastTy
, BitcastRegs
).getReg(0);
3796 MIRBuilder
.buildBitcast(DstReg
, BuildReg
);
3798 MI
.eraseFromParent();
3802 // This bitcasts a shuffle vector to a different type currently of the same
3803 // element size. Mostly used to legalize ptr vectors, where ptrtoint/inttoptr
3804 // will be used instead.
3806 // <16 x p0> = G_CONCAT_VECTORS <4 x p0>, <4 x p0>, mask
3808 // <4 x s64> = G_PTRTOINT <4 x p0>
3809 // <4 x s64> = G_PTRTOINT <4 x p0>
3810 // <16 x s64> = G_CONCAT_VECTORS <4 x s64>, <4 x s64>, mask
3811 // <16 x p0> = G_INTTOPTR <16 x s64>
3812 LegalizerHelper::LegalizeResult
3813 LegalizerHelper::bitcastShuffleVector(MachineInstr
&MI
, unsigned TypeIdx
,
3815 auto ShuffleMI
= cast
<GShuffleVector
>(&MI
);
3816 LLT DstTy
= MRI
.getType(ShuffleMI
->getReg(0));
3817 LLT SrcTy
= MRI
.getType(ShuffleMI
->getReg(1));
3819 // We currently only handle vectors of the same size.
3821 CastTy
.getScalarSizeInBits() != DstTy
.getScalarSizeInBits() ||
3822 CastTy
.getElementCount() != DstTy
.getElementCount())
3823 return UnableToLegalize
;
3825 LLT NewSrcTy
= SrcTy
.changeElementType(CastTy
.getScalarType());
3827 auto Inp1
= MIRBuilder
.buildCast(NewSrcTy
, ShuffleMI
->getReg(1));
3828 auto Inp2
= MIRBuilder
.buildCast(NewSrcTy
, ShuffleMI
->getReg(2));
3830 MIRBuilder
.buildShuffleVector(CastTy
, Inp1
, Inp2
, ShuffleMI
->getMask());
3831 MIRBuilder
.buildCast(ShuffleMI
->getReg(0), Shuf
);
3833 MI
.eraseFromParent();
3837 /// This attempts to bitcast G_EXTRACT_SUBVECTOR to CastTy.
3839 /// <vscale x 8 x i1> = G_EXTRACT_SUBVECTOR <vscale x 16 x i1>, N
3843 /// <vscale x 2 x i1> = G_BITCAST <vscale x 16 x i1>
3844 /// <vscale x 1 x i8> = G_EXTRACT_SUBVECTOR <vscale x 2 x i1>, N / 8
3845 /// <vscale x 8 x i1> = G_BITCAST <vscale x 1 x i8>
3846 LegalizerHelper::LegalizeResult
3847 LegalizerHelper::bitcastExtractSubvector(MachineInstr
&MI
, unsigned TypeIdx
,
3849 auto ES
= cast
<GExtractSubvector
>(&MI
);
3851 if (!CastTy
.isVector())
3852 return UnableToLegalize
;
3855 return UnableToLegalize
;
3857 Register Dst
= ES
->getReg(0);
3858 Register Src
= ES
->getSrcVec();
3859 uint64_t Idx
= ES
->getIndexImm();
3861 MachineRegisterInfo
&MRI
= *MIRBuilder
.getMRI();
3863 LLT DstTy
= MRI
.getType(Dst
);
3864 LLT SrcTy
= MRI
.getType(Src
);
3865 ElementCount DstTyEC
= DstTy
.getElementCount();
3866 ElementCount SrcTyEC
= SrcTy
.getElementCount();
3867 auto DstTyMinElts
= DstTyEC
.getKnownMinValue();
3868 auto SrcTyMinElts
= SrcTyEC
.getKnownMinValue();
3870 if (DstTy
== CastTy
)
3873 if (DstTy
.getSizeInBits() != CastTy
.getSizeInBits())
3874 return UnableToLegalize
;
3876 unsigned CastEltSize
= CastTy
.getElementType().getSizeInBits();
3877 unsigned DstEltSize
= DstTy
.getElementType().getSizeInBits();
3878 if (CastEltSize
< DstEltSize
)
3879 return UnableToLegalize
;
3881 auto AdjustAmt
= CastEltSize
/ DstEltSize
;
3882 if (Idx
% AdjustAmt
!= 0 || DstTyMinElts
% AdjustAmt
!= 0 ||
3883 SrcTyMinElts
% AdjustAmt
!= 0)
3884 return UnableToLegalize
;
3887 SrcTy
= LLT::vector(SrcTyEC
.divideCoefficientBy(AdjustAmt
), AdjustAmt
);
3888 auto CastVec
= MIRBuilder
.buildBitcast(SrcTy
, Src
);
3889 auto PromotedES
= MIRBuilder
.buildExtractSubvector(CastTy
, CastVec
, Idx
);
3890 MIRBuilder
.buildBitcast(Dst
, PromotedES
);
3892 ES
->eraseFromParent();
3896 /// This attempts to bitcast G_INSERT_SUBVECTOR to CastTy.
3898 /// <vscale x 16 x i1> = G_INSERT_SUBVECTOR <vscale x 16 x i1>,
3899 /// <vscale x 8 x i1>,
3904 /// <vscale x 2 x i8> = G_BITCAST <vscale x 16 x i1>
3905 /// <vscale x 1 x i8> = G_BITCAST <vscale x 8 x i1>
3906 /// <vscale x 2 x i8> = G_INSERT_SUBVECTOR <vscale x 2 x i8>,
3907 /// <vscale x 1 x i8>, N / 8
3908 /// <vscale x 16 x i1> = G_BITCAST <vscale x 2 x i8>
3909 LegalizerHelper::LegalizeResult
3910 LegalizerHelper::bitcastInsertSubvector(MachineInstr
&MI
, unsigned TypeIdx
,
3912 auto ES
= cast
<GInsertSubvector
>(&MI
);
3914 if (!CastTy
.isVector())
3915 return UnableToLegalize
;
3918 return UnableToLegalize
;
3920 Register Dst
= ES
->getReg(0);
3921 Register BigVec
= ES
->getBigVec();
3922 Register SubVec
= ES
->getSubVec();
3923 uint64_t Idx
= ES
->getIndexImm();
3925 MachineRegisterInfo
&MRI
= *MIRBuilder
.getMRI();
3927 LLT DstTy
= MRI
.getType(Dst
);
3928 LLT BigVecTy
= MRI
.getType(BigVec
);
3929 LLT SubVecTy
= MRI
.getType(SubVec
);
3931 if (DstTy
== CastTy
)
3934 if (DstTy
.getSizeInBits() != CastTy
.getSizeInBits())
3935 return UnableToLegalize
;
3937 ElementCount DstTyEC
= DstTy
.getElementCount();
3938 ElementCount BigVecTyEC
= BigVecTy
.getElementCount();
3939 ElementCount SubVecTyEC
= SubVecTy
.getElementCount();
3940 auto DstTyMinElts
= DstTyEC
.getKnownMinValue();
3941 auto BigVecTyMinElts
= BigVecTyEC
.getKnownMinValue();
3942 auto SubVecTyMinElts
= SubVecTyEC
.getKnownMinValue();
3944 unsigned CastEltSize
= CastTy
.getElementType().getSizeInBits();
3945 unsigned DstEltSize
= DstTy
.getElementType().getSizeInBits();
3946 if (CastEltSize
< DstEltSize
)
3947 return UnableToLegalize
;
3949 auto AdjustAmt
= CastEltSize
/ DstEltSize
;
3950 if (Idx
% AdjustAmt
!= 0 || DstTyMinElts
% AdjustAmt
!= 0 ||
3951 BigVecTyMinElts
% AdjustAmt
!= 0 || SubVecTyMinElts
% AdjustAmt
!= 0)
3952 return UnableToLegalize
;
3955 BigVecTy
= LLT::vector(BigVecTyEC
.divideCoefficientBy(AdjustAmt
), AdjustAmt
);
3956 SubVecTy
= LLT::vector(SubVecTyEC
.divideCoefficientBy(AdjustAmt
), AdjustAmt
);
3957 auto CastBigVec
= MIRBuilder
.buildBitcast(BigVecTy
, BigVec
);
3958 auto CastSubVec
= MIRBuilder
.buildBitcast(SubVecTy
, SubVec
);
3960 MIRBuilder
.buildInsertSubvector(CastTy
, CastBigVec
, CastSubVec
, Idx
);
3961 MIRBuilder
.buildBitcast(Dst
, PromotedIS
);
3963 ES
->eraseFromParent();
3967 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerLoad(GAnyLoad
&LoadMI
) {
3968 // Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
3969 Register DstReg
= LoadMI
.getDstReg();
3970 Register PtrReg
= LoadMI
.getPointerReg();
3971 LLT DstTy
= MRI
.getType(DstReg
);
3972 MachineMemOperand
&MMO
= LoadMI
.getMMO();
3973 LLT MemTy
= MMO
.getMemoryType();
3974 MachineFunction
&MF
= MIRBuilder
.getMF();
3976 unsigned MemSizeInBits
= MemTy
.getSizeInBits();
3977 unsigned MemStoreSizeInBits
= 8 * MemTy
.getSizeInBytes();
3979 if (MemSizeInBits
!= MemStoreSizeInBits
) {
3980 if (MemTy
.isVector())
3981 return UnableToLegalize
;
3983 // Promote to a byte-sized load if not loading an integral number of
3984 // bytes. For example, promote EXTLOAD:i20 -> EXTLOAD:i24.
3985 LLT WideMemTy
= LLT::scalar(MemStoreSizeInBits
);
3986 MachineMemOperand
*NewMMO
=
3987 MF
.getMachineMemOperand(&MMO
, MMO
.getPointerInfo(), WideMemTy
);
3989 Register LoadReg
= DstReg
;
3992 // If this wasn't already an extending load, we need to widen the result
3993 // register to avoid creating a load with a narrower result than the source.
3994 if (MemStoreSizeInBits
> DstTy
.getSizeInBits()) {
3996 LoadReg
= MRI
.createGenericVirtualRegister(WideMemTy
);
3999 if (isa
<GSExtLoad
>(LoadMI
)) {
4000 auto NewLoad
= MIRBuilder
.buildLoad(LoadTy
, PtrReg
, *NewMMO
);
4001 MIRBuilder
.buildSExtInReg(LoadReg
, NewLoad
, MemSizeInBits
);
4002 } else if (isa
<GZExtLoad
>(LoadMI
) || WideMemTy
== LoadTy
) {
4003 auto NewLoad
= MIRBuilder
.buildLoad(LoadTy
, PtrReg
, *NewMMO
);
4004 // The extra bits are guaranteed to be zero, since we stored them that
4005 // way. A zext load from Wide thus automatically gives zext from MemVT.
4006 MIRBuilder
.buildAssertZExt(LoadReg
, NewLoad
, MemSizeInBits
);
4008 MIRBuilder
.buildLoad(LoadReg
, PtrReg
, *NewMMO
);
4011 if (DstTy
!= LoadTy
)
4012 MIRBuilder
.buildTrunc(DstReg
, LoadReg
);
4014 LoadMI
.eraseFromParent();
4018 // Big endian lowering not implemented.
4019 if (MIRBuilder
.getDataLayout().isBigEndian())
4020 return UnableToLegalize
;
4022 // This load needs splitting into power of 2 sized loads.
4024 // Our strategy here is to generate anyextending loads for the smaller
4025 // types up to next power-2 result type, and then combine the two larger
4026 // result values together, before truncating back down to the non-pow-2
4028 // E.g. v1 = i24 load =>
4029 // v2 = i32 zextload (2 byte)
4030 // v3 = i32 load (1 byte)
4031 // v4 = i32 shl v3, 16
4032 // v5 = i32 or v4, v2
4033 // v1 = i24 trunc v5
4034 // By doing this we generate the correct truncate which should get
4035 // combined away as an artifact with a matching extend.
4037 uint64_t LargeSplitSize
, SmallSplitSize
;
4039 if (!isPowerOf2_32(MemSizeInBits
)) {
4040 // This load needs splitting into power of 2 sized loads.
4041 LargeSplitSize
= llvm::bit_floor(MemSizeInBits
);
4042 SmallSplitSize
= MemSizeInBits
- LargeSplitSize
;
4044 // This is already a power of 2, but we still need to split this in half.
4046 // Assume we're being asked to decompose an unaligned load.
4047 // TODO: If this requires multiple splits, handle them all at once.
4048 auto &Ctx
= MF
.getFunction().getContext();
4049 if (TLI
.allowsMemoryAccess(Ctx
, MIRBuilder
.getDataLayout(), MemTy
, MMO
))
4050 return UnableToLegalize
;
4052 SmallSplitSize
= LargeSplitSize
= MemSizeInBits
/ 2;
4055 if (MemTy
.isVector()) {
4056 // TODO: Handle vector extloads
4058 return UnableToLegalize
;
4060 // TODO: We can do better than scalarizing the vector and at least split it
4062 return reduceLoadStoreWidth(LoadMI
, 0, DstTy
.getElementType());
4065 MachineMemOperand
*LargeMMO
=
4066 MF
.getMachineMemOperand(&MMO
, 0, LargeSplitSize
/ 8);
4067 MachineMemOperand
*SmallMMO
=
4068 MF
.getMachineMemOperand(&MMO
, LargeSplitSize
/ 8, SmallSplitSize
/ 8);
4070 LLT PtrTy
= MRI
.getType(PtrReg
);
4071 unsigned AnyExtSize
= PowerOf2Ceil(DstTy
.getSizeInBits());
4072 LLT AnyExtTy
= LLT::scalar(AnyExtSize
);
4073 auto LargeLoad
= MIRBuilder
.buildLoadInstr(TargetOpcode::G_ZEXTLOAD
, AnyExtTy
,
4076 auto OffsetCst
= MIRBuilder
.buildConstant(LLT::scalar(PtrTy
.getSizeInBits()),
4077 LargeSplitSize
/ 8);
4078 Register PtrAddReg
= MRI
.createGenericVirtualRegister(PtrTy
);
4079 auto SmallPtr
= MIRBuilder
.buildPtrAdd(PtrAddReg
, PtrReg
, OffsetCst
);
4080 auto SmallLoad
= MIRBuilder
.buildLoadInstr(LoadMI
.getOpcode(), AnyExtTy
,
4081 SmallPtr
, *SmallMMO
);
4083 auto ShiftAmt
= MIRBuilder
.buildConstant(AnyExtTy
, LargeSplitSize
);
4084 auto Shift
= MIRBuilder
.buildShl(AnyExtTy
, SmallLoad
, ShiftAmt
);
4086 if (AnyExtTy
== DstTy
)
4087 MIRBuilder
.buildOr(DstReg
, Shift
, LargeLoad
);
4088 else if (AnyExtTy
.getSizeInBits() != DstTy
.getSizeInBits()) {
4089 auto Or
= MIRBuilder
.buildOr(AnyExtTy
, Shift
, LargeLoad
);
4090 MIRBuilder
.buildTrunc(DstReg
, {Or
});
4092 assert(DstTy
.isPointer() && "expected pointer");
4093 auto Or
= MIRBuilder
.buildOr(AnyExtTy
, Shift
, LargeLoad
);
4095 // FIXME: We currently consider this to be illegal for non-integral address
4096 // spaces, but we need still need a way to reinterpret the bits.
4097 MIRBuilder
.buildIntToPtr(DstReg
, Or
);
4100 LoadMI
.eraseFromParent();
4104 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerStore(GStore
&StoreMI
) {
4105 // Lower a non-power of 2 store into multiple pow-2 stores.
4106 // E.g. split an i24 store into an i16 store + i8 store.
4107 // We do this by first extending the stored value to the next largest power
4108 // of 2 type, and then using truncating stores to store the components.
4109 // By doing this, likewise with G_LOAD, generate an extend that can be
4110 // artifact-combined away instead of leaving behind extracts.
4111 Register SrcReg
= StoreMI
.getValueReg();
4112 Register PtrReg
= StoreMI
.getPointerReg();
4113 LLT SrcTy
= MRI
.getType(SrcReg
);
4114 MachineFunction
&MF
= MIRBuilder
.getMF();
4115 MachineMemOperand
&MMO
= **StoreMI
.memoperands_begin();
4116 LLT MemTy
= MMO
.getMemoryType();
4118 unsigned StoreWidth
= MemTy
.getSizeInBits();
4119 unsigned StoreSizeInBits
= 8 * MemTy
.getSizeInBytes();
4121 if (StoreWidth
!= StoreSizeInBits
&& !SrcTy
.isVector()) {
4122 // Promote to a byte-sized store with upper bits zero if not
4123 // storing an integral number of bytes. For example, promote
4124 // TRUNCSTORE:i1 X -> TRUNCSTORE:i8 (and X, 1)
4125 LLT WideTy
= LLT::scalar(StoreSizeInBits
);
4127 if (StoreSizeInBits
> SrcTy
.getSizeInBits()) {
4128 // Avoid creating a store with a narrower source than result.
4129 SrcReg
= MIRBuilder
.buildAnyExt(WideTy
, SrcReg
).getReg(0);
4133 auto ZextInReg
= MIRBuilder
.buildZExtInReg(SrcTy
, SrcReg
, StoreWidth
);
4135 MachineMemOperand
*NewMMO
=
4136 MF
.getMachineMemOperand(&MMO
, MMO
.getPointerInfo(), WideTy
);
4137 MIRBuilder
.buildStore(ZextInReg
, PtrReg
, *NewMMO
);
4138 StoreMI
.eraseFromParent();
4142 if (MemTy
.isVector()) {
4144 return scalarizeVectorBooleanStore(StoreMI
);
4146 // TODO: We can do better than scalarizing the vector and at least split it
4148 return reduceLoadStoreWidth(StoreMI
, 0, SrcTy
.getElementType());
4151 unsigned MemSizeInBits
= MemTy
.getSizeInBits();
4152 uint64_t LargeSplitSize
, SmallSplitSize
;
4154 if (!isPowerOf2_32(MemSizeInBits
)) {
4155 LargeSplitSize
= llvm::bit_floor
<uint64_t>(MemTy
.getSizeInBits());
4156 SmallSplitSize
= MemTy
.getSizeInBits() - LargeSplitSize
;
4158 auto &Ctx
= MF
.getFunction().getContext();
4159 if (TLI
.allowsMemoryAccess(Ctx
, MIRBuilder
.getDataLayout(), MemTy
, MMO
))
4160 return UnableToLegalize
; // Don't know what we're being asked to do.
4162 SmallSplitSize
= LargeSplitSize
= MemSizeInBits
/ 2;
4165 // Extend to the next pow-2. If this store was itself the result of lowering,
4166 // e.g. an s56 store being broken into s32 + s24, we might have a stored type
4167 // that's wider than the stored size.
4168 unsigned AnyExtSize
= PowerOf2Ceil(MemTy
.getSizeInBits());
4169 const LLT NewSrcTy
= LLT::scalar(AnyExtSize
);
4171 if (SrcTy
.isPointer()) {
4172 const LLT IntPtrTy
= LLT::scalar(SrcTy
.getSizeInBits());
4173 SrcReg
= MIRBuilder
.buildPtrToInt(IntPtrTy
, SrcReg
).getReg(0);
4176 auto ExtVal
= MIRBuilder
.buildAnyExtOrTrunc(NewSrcTy
, SrcReg
);
4178 // Obtain the smaller value by shifting away the larger value.
4179 auto ShiftAmt
= MIRBuilder
.buildConstant(NewSrcTy
, LargeSplitSize
);
4180 auto SmallVal
= MIRBuilder
.buildLShr(NewSrcTy
, ExtVal
, ShiftAmt
);
4182 // Generate the PtrAdd and truncating stores.
4183 LLT PtrTy
= MRI
.getType(PtrReg
);
4184 auto OffsetCst
= MIRBuilder
.buildConstant(
4185 LLT::scalar(PtrTy
.getSizeInBits()), LargeSplitSize
/ 8);
4187 MIRBuilder
.buildPtrAdd(PtrTy
, PtrReg
, OffsetCst
);
4189 MachineMemOperand
*LargeMMO
=
4190 MF
.getMachineMemOperand(&MMO
, 0, LargeSplitSize
/ 8);
4191 MachineMemOperand
*SmallMMO
=
4192 MF
.getMachineMemOperand(&MMO
, LargeSplitSize
/ 8, SmallSplitSize
/ 8);
4193 MIRBuilder
.buildStore(ExtVal
, PtrReg
, *LargeMMO
);
4194 MIRBuilder
.buildStore(SmallVal
, SmallPtr
, *SmallMMO
);
4195 StoreMI
.eraseFromParent();
4199 LegalizerHelper::LegalizeResult
4200 LegalizerHelper::scalarizeVectorBooleanStore(GStore
&StoreMI
) {
4201 Register SrcReg
= StoreMI
.getValueReg();
4202 Register PtrReg
= StoreMI
.getPointerReg();
4203 LLT SrcTy
= MRI
.getType(SrcReg
);
4204 MachineMemOperand
&MMO
= **StoreMI
.memoperands_begin();
4205 LLT MemTy
= MMO
.getMemoryType();
4206 LLT MemScalarTy
= MemTy
.getElementType();
4207 MachineFunction
&MF
= MIRBuilder
.getMF();
4209 assert(SrcTy
.isVector() && "Expect a vector store type");
4211 if (!MemScalarTy
.isByteSized()) {
4212 // We need to build an integer scalar of the vector bit pattern.
4213 // It's not legal for us to add padding when storing a vector.
4214 unsigned NumBits
= MemTy
.getSizeInBits();
4215 LLT IntTy
= LLT::scalar(NumBits
);
4216 auto CurrVal
= MIRBuilder
.buildConstant(IntTy
, 0);
4217 LLT IdxTy
= getLLTForMVT(TLI
.getVectorIdxTy(MF
.getDataLayout()));
4219 for (unsigned I
= 0, E
= MemTy
.getNumElements(); I
< E
; ++I
) {
4220 auto Elt
= MIRBuilder
.buildExtractVectorElement(
4221 SrcTy
.getElementType(), SrcReg
, MIRBuilder
.buildConstant(IdxTy
, I
));
4222 auto Trunc
= MIRBuilder
.buildTrunc(MemScalarTy
, Elt
);
4223 auto ZExt
= MIRBuilder
.buildZExt(IntTy
, Trunc
);
4224 unsigned ShiftIntoIdx
= MF
.getDataLayout().isBigEndian()
4225 ? (MemTy
.getNumElements() - 1) - I
4227 auto ShiftAmt
= MIRBuilder
.buildConstant(
4228 IntTy
, ShiftIntoIdx
* MemScalarTy
.getSizeInBits());
4229 auto Shifted
= MIRBuilder
.buildShl(IntTy
, ZExt
, ShiftAmt
);
4230 CurrVal
= MIRBuilder
.buildOr(IntTy
, CurrVal
, Shifted
);
4232 auto PtrInfo
= MMO
.getPointerInfo();
4233 auto *NewMMO
= MF
.getMachineMemOperand(&MMO
, PtrInfo
, IntTy
);
4234 MIRBuilder
.buildStore(CurrVal
, PtrReg
, *NewMMO
);
4235 StoreMI
.eraseFromParent();
4239 // TODO: implement simple scalarization.
4240 return UnableToLegalize
;
4243 LegalizerHelper::LegalizeResult
4244 LegalizerHelper::bitcast(MachineInstr
&MI
, unsigned TypeIdx
, LLT CastTy
) {
4245 switch (MI
.getOpcode()) {
4246 case TargetOpcode::G_LOAD
: {
4248 return UnableToLegalize
;
4249 MachineMemOperand
&MMO
= **MI
.memoperands_begin();
4251 // Not sure how to interpret a bitcast of an extending load.
4252 if (MMO
.getMemoryType().getSizeInBits() != CastTy
.getSizeInBits())
4253 return UnableToLegalize
;
4255 Observer
.changingInstr(MI
);
4256 bitcastDst(MI
, CastTy
, 0);
4257 MMO
.setType(CastTy
);
4258 // The range metadata is no longer valid when reinterpreted as a different
4261 Observer
.changedInstr(MI
);
4264 case TargetOpcode::G_STORE
: {
4266 return UnableToLegalize
;
4268 MachineMemOperand
&MMO
= **MI
.memoperands_begin();
4270 // Not sure how to interpret a bitcast of a truncating store.
4271 if (MMO
.getMemoryType().getSizeInBits() != CastTy
.getSizeInBits())
4272 return UnableToLegalize
;
4274 Observer
.changingInstr(MI
);
4275 bitcastSrc(MI
, CastTy
, 0);
4276 MMO
.setType(CastTy
);
4277 Observer
.changedInstr(MI
);
4280 case TargetOpcode::G_SELECT
: {
4282 return UnableToLegalize
;
4284 if (MRI
.getType(MI
.getOperand(1).getReg()).isVector()) {
4286 dbgs() << "bitcast action not implemented for vector select\n");
4287 return UnableToLegalize
;
4290 Observer
.changingInstr(MI
);
4291 bitcastSrc(MI
, CastTy
, 2);
4292 bitcastSrc(MI
, CastTy
, 3);
4293 bitcastDst(MI
, CastTy
, 0);
4294 Observer
.changedInstr(MI
);
4297 case TargetOpcode::G_AND
:
4298 case TargetOpcode::G_OR
:
4299 case TargetOpcode::G_XOR
: {
4300 Observer
.changingInstr(MI
);
4301 bitcastSrc(MI
, CastTy
, 1);
4302 bitcastSrc(MI
, CastTy
, 2);
4303 bitcastDst(MI
, CastTy
, 0);
4304 Observer
.changedInstr(MI
);
4307 case TargetOpcode::G_EXTRACT_VECTOR_ELT
:
4308 return bitcastExtractVectorElt(MI
, TypeIdx
, CastTy
);
4309 case TargetOpcode::G_INSERT_VECTOR_ELT
:
4310 return bitcastInsertVectorElt(MI
, TypeIdx
, CastTy
);
4311 case TargetOpcode::G_CONCAT_VECTORS
:
4312 return bitcastConcatVector(MI
, TypeIdx
, CastTy
);
4313 case TargetOpcode::G_SHUFFLE_VECTOR
:
4314 return bitcastShuffleVector(MI
, TypeIdx
, CastTy
);
4315 case TargetOpcode::G_EXTRACT_SUBVECTOR
:
4316 return bitcastExtractSubvector(MI
, TypeIdx
, CastTy
);
4317 case TargetOpcode::G_INSERT_SUBVECTOR
:
4318 return bitcastInsertSubvector(MI
, TypeIdx
, CastTy
);
4320 return UnableToLegalize
;
4324 // Legalize an instruction by changing the opcode in place.
4325 void LegalizerHelper::changeOpcode(MachineInstr
&MI
, unsigned NewOpcode
) {
4326 Observer
.changingInstr(MI
);
4327 MI
.setDesc(MIRBuilder
.getTII().get(NewOpcode
));
4328 Observer
.changedInstr(MI
);
4331 LegalizerHelper::LegalizeResult
4332 LegalizerHelper::lower(MachineInstr
&MI
, unsigned TypeIdx
, LLT LowerHintTy
) {
4333 using namespace TargetOpcode
;
4335 switch(MI
.getOpcode()) {
4337 return UnableToLegalize
;
4338 case TargetOpcode::G_FCONSTANT
:
4339 return lowerFConstant(MI
);
4340 case TargetOpcode::G_BITCAST
:
4341 return lowerBitcast(MI
);
4342 case TargetOpcode::G_SREM
:
4343 case TargetOpcode::G_UREM
: {
4344 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
4346 MIRBuilder
.buildInstr(MI
.getOpcode() == G_SREM
? G_SDIV
: G_UDIV
, {Ty
},
4347 {MI
.getOperand(1), MI
.getOperand(2)});
4349 auto Prod
= MIRBuilder
.buildMul(Ty
, Quot
, MI
.getOperand(2));
4350 MIRBuilder
.buildSub(MI
.getOperand(0), MI
.getOperand(1), Prod
);
4351 MI
.eraseFromParent();
4354 case TargetOpcode::G_SADDO
:
4355 case TargetOpcode::G_SSUBO
:
4356 return lowerSADDO_SSUBO(MI
);
4357 case TargetOpcode::G_UMULH
:
4358 case TargetOpcode::G_SMULH
:
4359 return lowerSMULH_UMULH(MI
);
4360 case TargetOpcode::G_SMULO
:
4361 case TargetOpcode::G_UMULO
: {
4362 // Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
4364 auto [Res
, Overflow
, LHS
, RHS
] = MI
.getFirst4Regs();
4365 LLT Ty
= MRI
.getType(Res
);
4367 unsigned Opcode
= MI
.getOpcode() == TargetOpcode::G_SMULO
4368 ? TargetOpcode::G_SMULH
4369 : TargetOpcode::G_UMULH
;
4371 Observer
.changingInstr(MI
);
4372 const auto &TII
= MIRBuilder
.getTII();
4373 MI
.setDesc(TII
.get(TargetOpcode::G_MUL
));
4374 MI
.removeOperand(1);
4375 Observer
.changedInstr(MI
);
4377 auto HiPart
= MIRBuilder
.buildInstr(Opcode
, {Ty
}, {LHS
, RHS
});
4378 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
4380 // Move insert point forward so we can use the Res register if needed.
4381 MIRBuilder
.setInsertPt(MIRBuilder
.getMBB(), ++MIRBuilder
.getInsertPt());
4383 // For *signed* multiply, overflow is detected by checking:
4384 // (hi != (lo >> bitwidth-1))
4385 if (Opcode
== TargetOpcode::G_SMULH
) {
4386 auto ShiftAmt
= MIRBuilder
.buildConstant(Ty
, Ty
.getSizeInBits() - 1);
4387 auto Shifted
= MIRBuilder
.buildAShr(Ty
, Res
, ShiftAmt
);
4388 MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, Overflow
, HiPart
, Shifted
);
4390 MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, Overflow
, HiPart
, Zero
);
4394 case TargetOpcode::G_FNEG
: {
4395 auto [Res
, SubByReg
] = MI
.getFirst2Regs();
4396 LLT Ty
= MRI
.getType(Res
);
4398 auto SignMask
= MIRBuilder
.buildConstant(
4399 Ty
, APInt::getSignMask(Ty
.getScalarSizeInBits()));
4400 MIRBuilder
.buildXor(Res
, SubByReg
, SignMask
);
4401 MI
.eraseFromParent();
4404 case TargetOpcode::G_FSUB
:
4405 case TargetOpcode::G_STRICT_FSUB
: {
4406 auto [Res
, LHS
, RHS
] = MI
.getFirst3Regs();
4407 LLT Ty
= MRI
.getType(Res
);
4409 // Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
4410 auto Neg
= MIRBuilder
.buildFNeg(Ty
, RHS
);
4412 if (MI
.getOpcode() == TargetOpcode::G_STRICT_FSUB
)
4413 MIRBuilder
.buildStrictFAdd(Res
, LHS
, Neg
, MI
.getFlags());
4415 MIRBuilder
.buildFAdd(Res
, LHS
, Neg
, MI
.getFlags());
4417 MI
.eraseFromParent();
4420 case TargetOpcode::G_FMAD
:
4421 return lowerFMad(MI
);
4422 case TargetOpcode::G_FFLOOR
:
4423 return lowerFFloor(MI
);
4424 case TargetOpcode::G_LROUND
:
4425 case TargetOpcode::G_LLROUND
: {
4426 Register DstReg
= MI
.getOperand(0).getReg();
4427 Register SrcReg
= MI
.getOperand(1).getReg();
4428 LLT SrcTy
= MRI
.getType(SrcReg
);
4429 auto Round
= MIRBuilder
.buildInstr(TargetOpcode::G_INTRINSIC_ROUND
, {SrcTy
},
4431 MIRBuilder
.buildFPTOSI(DstReg
, Round
);
4432 MI
.eraseFromParent();
4435 case TargetOpcode::G_INTRINSIC_ROUND
:
4436 return lowerIntrinsicRound(MI
);
4437 case TargetOpcode::G_FRINT
: {
4438 // Since round even is the assumed rounding mode for unconstrained FP
4439 // operations, rint and roundeven are the same operation.
4440 changeOpcode(MI
, TargetOpcode::G_INTRINSIC_ROUNDEVEN
);
4443 case TargetOpcode::G_INTRINSIC_LRINT
:
4444 case TargetOpcode::G_INTRINSIC_LLRINT
: {
4445 Register DstReg
= MI
.getOperand(0).getReg();
4446 Register SrcReg
= MI
.getOperand(1).getReg();
4447 LLT SrcTy
= MRI
.getType(SrcReg
);
4449 MIRBuilder
.buildInstr(TargetOpcode::G_FRINT
, {SrcTy
}, {SrcReg
});
4450 MIRBuilder
.buildFPTOSI(DstReg
, Round
);
4451 MI
.eraseFromParent();
4454 case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS
: {
4455 auto [OldValRes
, SuccessRes
, Addr
, CmpVal
, NewVal
] = MI
.getFirst5Regs();
4456 Register NewOldValRes
= MRI
.cloneVirtualRegister(OldValRes
);
4457 MIRBuilder
.buildAtomicCmpXchg(NewOldValRes
, Addr
, CmpVal
, NewVal
,
4458 **MI
.memoperands_begin());
4459 MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, SuccessRes
, NewOldValRes
, CmpVal
);
4460 MIRBuilder
.buildCopy(OldValRes
, NewOldValRes
);
4461 MI
.eraseFromParent();
4464 case TargetOpcode::G_LOAD
:
4465 case TargetOpcode::G_SEXTLOAD
:
4466 case TargetOpcode::G_ZEXTLOAD
:
4467 return lowerLoad(cast
<GAnyLoad
>(MI
));
4468 case TargetOpcode::G_STORE
:
4469 return lowerStore(cast
<GStore
>(MI
));
4470 case TargetOpcode::G_CTLZ_ZERO_UNDEF
:
4471 case TargetOpcode::G_CTTZ_ZERO_UNDEF
:
4472 case TargetOpcode::G_CTLZ
:
4473 case TargetOpcode::G_CTTZ
:
4474 case TargetOpcode::G_CTPOP
:
4475 return lowerBitCount(MI
);
4477 auto [Res
, CarryOut
, LHS
, RHS
] = MI
.getFirst4Regs();
4479 Register NewRes
= MRI
.cloneVirtualRegister(Res
);
4481 MIRBuilder
.buildAdd(NewRes
, LHS
, RHS
);
4482 MIRBuilder
.buildICmp(CmpInst::ICMP_ULT
, CarryOut
, NewRes
, RHS
);
4484 MIRBuilder
.buildCopy(Res
, NewRes
);
4486 MI
.eraseFromParent();
4490 auto [Res
, CarryOut
, LHS
, RHS
, CarryIn
] = MI
.getFirst5Regs();
4491 const LLT CondTy
= MRI
.getType(CarryOut
);
4492 const LLT Ty
= MRI
.getType(Res
);
4494 Register NewRes
= MRI
.cloneVirtualRegister(Res
);
4496 // Initial add of the two operands.
4497 auto TmpRes
= MIRBuilder
.buildAdd(Ty
, LHS
, RHS
);
4499 // Initial check for carry.
4500 auto Carry
= MIRBuilder
.buildICmp(CmpInst::ICMP_ULT
, CondTy
, TmpRes
, LHS
);
4502 // Add the sum and the carry.
4503 auto ZExtCarryIn
= MIRBuilder
.buildZExt(Ty
, CarryIn
);
4504 MIRBuilder
.buildAdd(NewRes
, TmpRes
, ZExtCarryIn
);
4506 // Second check for carry. We can only carry if the initial sum is all 1s
4507 // and the carry is set, resulting in a new sum of 0.
4508 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
4510 MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, CondTy
, NewRes
, Zero
);
4511 auto Carry2
= MIRBuilder
.buildAnd(CondTy
, ResEqZero
, CarryIn
);
4512 MIRBuilder
.buildOr(CarryOut
, Carry
, Carry2
);
4514 MIRBuilder
.buildCopy(Res
, NewRes
);
4516 MI
.eraseFromParent();
4520 auto [Res
, BorrowOut
, LHS
, RHS
] = MI
.getFirst4Regs();
4522 MIRBuilder
.buildSub(Res
, LHS
, RHS
);
4523 MIRBuilder
.buildICmp(CmpInst::ICMP_ULT
, BorrowOut
, LHS
, RHS
);
4525 MI
.eraseFromParent();
4529 auto [Res
, BorrowOut
, LHS
, RHS
, BorrowIn
] = MI
.getFirst5Regs();
4530 const LLT CondTy
= MRI
.getType(BorrowOut
);
4531 const LLT Ty
= MRI
.getType(Res
);
4533 // Initial subtract of the two operands.
4534 auto TmpRes
= MIRBuilder
.buildSub(Ty
, LHS
, RHS
);
4536 // Initial check for borrow.
4537 auto Borrow
= MIRBuilder
.buildICmp(CmpInst::ICMP_UGT
, CondTy
, TmpRes
, LHS
);
4539 // Subtract the borrow from the first subtract.
4540 auto ZExtBorrowIn
= MIRBuilder
.buildZExt(Ty
, BorrowIn
);
4541 MIRBuilder
.buildSub(Res
, TmpRes
, ZExtBorrowIn
);
4543 // Second check for borrow. We can only borrow if the initial difference is
4544 // 0 and the borrow is set, resulting in a new difference of all 1s.
4545 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
4547 MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, CondTy
, TmpRes
, Zero
);
4548 auto Borrow2
= MIRBuilder
.buildAnd(CondTy
, TmpResEqZero
, BorrowIn
);
4549 MIRBuilder
.buildOr(BorrowOut
, Borrow
, Borrow2
);
4551 MI
.eraseFromParent();
4555 return lowerUITOFP(MI
);
4557 return lowerSITOFP(MI
);
4559 return lowerFPTOUI(MI
);
4561 return lowerFPTOSI(MI
);
4564 return lowerFPTOINT_SAT(MI
);
4566 return lowerFPTRUNC(MI
);
4568 return lowerFPOWI(MI
);
4573 return lowerMinMax(MI
);
4576 return lowerThreewayCompare(MI
);
4578 return lowerFCopySign(MI
);
4581 return lowerFMinNumMaxNum(MI
);
4582 case G_MERGE_VALUES
:
4583 return lowerMergeValues(MI
);
4584 case G_UNMERGE_VALUES
:
4585 return lowerUnmergeValues(MI
);
4586 case TargetOpcode::G_SEXT_INREG
: {
4587 assert(MI
.getOperand(2).isImm() && "Expected immediate");
4588 int64_t SizeInBits
= MI
.getOperand(2).getImm();
4590 auto [DstReg
, SrcReg
] = MI
.getFirst2Regs();
4591 LLT DstTy
= MRI
.getType(DstReg
);
4592 Register TmpRes
= MRI
.createGenericVirtualRegister(DstTy
);
4594 auto MIBSz
= MIRBuilder
.buildConstant(DstTy
, DstTy
.getScalarSizeInBits() - SizeInBits
);
4595 MIRBuilder
.buildShl(TmpRes
, SrcReg
, MIBSz
->getOperand(0));
4596 MIRBuilder
.buildAShr(DstReg
, TmpRes
, MIBSz
->getOperand(0));
4597 MI
.eraseFromParent();
4600 case G_EXTRACT_VECTOR_ELT
:
4601 case G_INSERT_VECTOR_ELT
:
4602 return lowerExtractInsertVectorElt(MI
);
4603 case G_SHUFFLE_VECTOR
:
4604 return lowerShuffleVector(MI
);
4605 case G_VECTOR_COMPRESS
:
4606 return lowerVECTOR_COMPRESS(MI
);
4607 case G_DYN_STACKALLOC
:
4608 return lowerDynStackAlloc(MI
);
4610 return lowerStackSave(MI
);
4611 case G_STACKRESTORE
:
4612 return lowerStackRestore(MI
);
4614 return lowerExtract(MI
);
4616 return lowerInsert(MI
);
4618 return lowerBswap(MI
);
4620 return lowerBitreverse(MI
);
4621 case G_READ_REGISTER
:
4622 case G_WRITE_REGISTER
:
4623 return lowerReadWriteRegister(MI
);
4626 // Try to make a reasonable guess about which lowering strategy to use. The
4627 // target can override this with custom lowering and calling the
4628 // implementation functions.
4629 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
4630 if (LI
.isLegalOrCustom({G_UMIN
, Ty
}))
4631 return lowerAddSubSatToMinMax(MI
);
4632 return lowerAddSubSatToAddoSubo(MI
);
4636 LLT Ty
= MRI
.getType(MI
.getOperand(0).getReg());
4638 // FIXME: It would probably make more sense to see if G_SADDO is preferred,
4639 // since it's a shorter expansion. However, we would need to figure out the
4640 // preferred boolean type for the carry out for the query.
4641 if (LI
.isLegalOrCustom({G_SMIN
, Ty
}) && LI
.isLegalOrCustom({G_SMAX
, Ty
}))
4642 return lowerAddSubSatToMinMax(MI
);
4643 return lowerAddSubSatToAddoSubo(MI
);
4647 return lowerShlSat(MI
);
4649 return lowerAbsToAddXor(MI
);
4651 return lowerFAbs(MI
);
4653 return lowerSelect(MI
);
4655 return lowerISFPCLASS(MI
);
4658 return lowerDIVREM(MI
);
4661 return lowerFunnelShift(MI
);
4664 return lowerRotate(MI
);
4668 return lowerMemCpyFamily(MI
);
4669 case G_MEMCPY_INLINE
:
4670 return lowerMemcpyInline(MI
);
4674 return lowerEXT(MI
);
4676 return lowerTRUNC(MI
);
4677 GISEL_VECREDUCE_CASES_NONSEQ
4678 return lowerVectorReduction(MI
);
4680 return lowerVAArg(MI
);
4684 Align
LegalizerHelper::getStackTemporaryAlignment(LLT Ty
,
4685 Align MinAlign
) const {
4686 // FIXME: We're missing a way to go back from LLT to llvm::Type to query the
4687 // datalayout for the preferred alignment. Also there should be a target hook
4688 // for this to allow targets to reduce the alignment and ignore the
4689 // datalayout. e.g. AMDGPU should always use a 4-byte alignment, regardless of
4691 return std::max(Align(PowerOf2Ceil(Ty
.getSizeInBytes())), MinAlign
);
4695 LegalizerHelper::createStackTemporary(TypeSize Bytes
, Align Alignment
,
4696 MachinePointerInfo
&PtrInfo
) {
4697 MachineFunction
&MF
= MIRBuilder
.getMF();
4698 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
4699 int FrameIdx
= MF
.getFrameInfo().CreateStackObject(Bytes
, Alignment
, false);
4701 unsigned AddrSpace
= DL
.getAllocaAddrSpace();
4702 LLT FramePtrTy
= LLT::pointer(AddrSpace
, DL
.getPointerSizeInBits(AddrSpace
));
4704 PtrInfo
= MachinePointerInfo::getFixedStack(MF
, FrameIdx
);
4705 return MIRBuilder
.buildFrameIndex(FramePtrTy
, FrameIdx
);
4708 MachineInstrBuilder
LegalizerHelper::createStackStoreLoad(const DstOp
&Res
,
4710 LLT SrcTy
= Val
.getLLTTy(MRI
);
4711 Align StackTypeAlign
=
4712 std::max(getStackTemporaryAlignment(SrcTy
),
4713 getStackTemporaryAlignment(Res
.getLLTTy(MRI
)));
4714 MachinePointerInfo PtrInfo
;
4716 createStackTemporary(SrcTy
.getSizeInBytes(), StackTypeAlign
, PtrInfo
);
4718 MIRBuilder
.buildStore(Val
, StackTemp
, PtrInfo
, StackTypeAlign
);
4719 return MIRBuilder
.buildLoad(Res
, StackTemp
, PtrInfo
, StackTypeAlign
);
4722 static Register
clampVectorIndex(MachineIRBuilder
&B
, Register IdxReg
,
4724 LLT IdxTy
= B
.getMRI()->getType(IdxReg
);
4725 unsigned NElts
= VecTy
.getNumElements();
4728 if (mi_match(IdxReg
, *B
.getMRI(), m_ICst(IdxVal
))) {
4729 if (IdxVal
< VecTy
.getNumElements())
4731 // If a constant index would be out of bounds, clamp it as well.
4734 if (isPowerOf2_32(NElts
)) {
4735 APInt Imm
= APInt::getLowBitsSet(IdxTy
.getSizeInBits(), Log2_32(NElts
));
4736 return B
.buildAnd(IdxTy
, IdxReg
, B
.buildConstant(IdxTy
, Imm
)).getReg(0);
4739 return B
.buildUMin(IdxTy
, IdxReg
, B
.buildConstant(IdxTy
, NElts
- 1))
4743 Register
LegalizerHelper::getVectorElementPointer(Register VecPtr
, LLT VecTy
,
4745 LLT EltTy
= VecTy
.getElementType();
4747 // Calculate the element offset and add it to the pointer.
4748 unsigned EltSize
= EltTy
.getSizeInBits() / 8; // FIXME: should be ABI size.
4749 assert(EltSize
* 8 == EltTy
.getSizeInBits() &&
4750 "Converting bits to bytes lost precision");
4752 Index
= clampVectorIndex(MIRBuilder
, Index
, VecTy
);
4754 // Convert index to the correct size for the address space.
4755 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
4756 unsigned AS
= MRI
.getType(VecPtr
).getAddressSpace();
4757 unsigned IndexSizeInBits
= DL
.getIndexSize(AS
) * 8;
4758 LLT IdxTy
= MRI
.getType(Index
).changeElementSize(IndexSizeInBits
);
4759 if (IdxTy
!= MRI
.getType(Index
))
4760 Index
= MIRBuilder
.buildSExtOrTrunc(IdxTy
, Index
).getReg(0);
4762 auto Mul
= MIRBuilder
.buildMul(IdxTy
, Index
,
4763 MIRBuilder
.buildConstant(IdxTy
, EltSize
));
4765 LLT PtrTy
= MRI
.getType(VecPtr
);
4766 return MIRBuilder
.buildPtrAdd(PtrTy
, VecPtr
, Mul
).getReg(0);
4770 /// Check that all vector operands have same number of elements. Other operands
4771 /// should be listed in NonVecOp.
4772 static bool hasSameNumEltsOnAllVectorOperands(
4773 GenericMachineInstr
&MI
, MachineRegisterInfo
&MRI
,
4774 std::initializer_list
<unsigned> NonVecOpIndices
) {
4775 if (MI
.getNumMemOperands() != 0)
4778 LLT VecTy
= MRI
.getType(MI
.getReg(0));
4779 if (!VecTy
.isVector())
4781 unsigned NumElts
= VecTy
.getNumElements();
4783 for (unsigned OpIdx
= 1; OpIdx
< MI
.getNumOperands(); ++OpIdx
) {
4784 MachineOperand
&Op
= MI
.getOperand(OpIdx
);
4786 if (!is_contained(NonVecOpIndices
, OpIdx
))
4791 LLT Ty
= MRI
.getType(Op
.getReg());
4792 if (!Ty
.isVector()) {
4793 if (!is_contained(NonVecOpIndices
, OpIdx
))
4798 if (Ty
.getNumElements() != NumElts
)
4806 /// Fill \p DstOps with DstOps that have same number of elements combined as
4807 /// the Ty. These DstOps have either scalar type when \p NumElts = 1 or are
4808 /// vectors with \p NumElts elements. When Ty.getNumElements() is not multiple
4809 /// of \p NumElts last DstOp (leftover) has fewer then \p NumElts elements.
4810 static void makeDstOps(SmallVectorImpl
<DstOp
> &DstOps
, LLT Ty
,
4813 assert(Ty
.isVector() && "Expected vector type");
4814 LLT EltTy
= Ty
.getElementType();
4815 LLT NarrowTy
= (NumElts
== 1) ? EltTy
: LLT::fixed_vector(NumElts
, EltTy
);
4816 int NumParts
, NumLeftover
;
4817 std::tie(NumParts
, NumLeftover
) =
4818 getNarrowTypeBreakDown(Ty
, NarrowTy
, LeftoverTy
);
4820 assert(NumParts
> 0 && "Error in getNarrowTypeBreakDown");
4821 for (int i
= 0; i
< NumParts
; ++i
) {
4822 DstOps
.push_back(NarrowTy
);
4825 if (LeftoverTy
.isValid()) {
4826 assert(NumLeftover
== 1 && "expected exactly one leftover");
4827 DstOps
.push_back(LeftoverTy
);
4831 /// Operand \p Op is used on \p N sub-instructions. Fill \p Ops with \p N SrcOps
4832 /// made from \p Op depending on operand type.
4833 static void broadcastSrcOp(SmallVectorImpl
<SrcOp
> &Ops
, unsigned N
,
4834 MachineOperand
&Op
) {
4835 for (unsigned i
= 0; i
< N
; ++i
) {
4837 Ops
.push_back(Op
.getReg());
4838 else if (Op
.isImm())
4839 Ops
.push_back(Op
.getImm());
4840 else if (Op
.isPredicate())
4841 Ops
.push_back(static_cast<CmpInst::Predicate
>(Op
.getPredicate()));
4843 llvm_unreachable("Unsupported type");
4847 // Handle splitting vector operations which need to have the same number of
4848 // elements in each type index, but each type index may have a different element
4851 // e.g. <4 x s64> = G_SHL <4 x s64>, <4 x s32> ->
4852 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4853 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4855 // Also handles some irregular breakdown cases, e.g.
4856 // e.g. <3 x s64> = G_SHL <3 x s64>, <3 x s32> ->
4857 // <2 x s64> = G_SHL <2 x s64>, <2 x s32>
4858 // s64 = G_SHL s64, s32
4859 LegalizerHelper::LegalizeResult
4860 LegalizerHelper::fewerElementsVectorMultiEltType(
4861 GenericMachineInstr
&MI
, unsigned NumElts
,
4862 std::initializer_list
<unsigned> NonVecOpIndices
) {
4863 assert(hasSameNumEltsOnAllVectorOperands(MI
, MRI
, NonVecOpIndices
) &&
4864 "Non-compatible opcode or not specified non-vector operands");
4865 unsigned OrigNumElts
= MRI
.getType(MI
.getReg(0)).getNumElements();
4867 unsigned NumInputs
= MI
.getNumOperands() - MI
.getNumDefs();
4868 unsigned NumDefs
= MI
.getNumDefs();
4870 // Create DstOps (sub-vectors with NumElts elts + Leftover) for each output.
4871 // Build instructions with DstOps to use instruction found by CSE directly.
4872 // CSE copies found instruction into given vreg when building with vreg dest.
4873 SmallVector
<SmallVector
<DstOp
, 8>, 2> OutputOpsPieces(NumDefs
);
4874 // Output registers will be taken from created instructions.
4875 SmallVector
<SmallVector
<Register
, 8>, 2> OutputRegs(NumDefs
);
4876 for (unsigned i
= 0; i
< NumDefs
; ++i
) {
4877 makeDstOps(OutputOpsPieces
[i
], MRI
.getType(MI
.getReg(i
)), NumElts
);
4880 // Split vector input operands into sub-vectors with NumElts elts + Leftover.
4881 // Operands listed in NonVecOpIndices will be used as is without splitting;
4882 // examples: compare predicate in icmp and fcmp (op 1), vector select with i1
4883 // scalar condition (op 1), immediate in sext_inreg (op 2).
4884 SmallVector
<SmallVector
<SrcOp
, 8>, 3> InputOpsPieces(NumInputs
);
4885 for (unsigned UseIdx
= NumDefs
, UseNo
= 0; UseIdx
< MI
.getNumOperands();
4886 ++UseIdx
, ++UseNo
) {
4887 if (is_contained(NonVecOpIndices
, UseIdx
)) {
4888 broadcastSrcOp(InputOpsPieces
[UseNo
], OutputOpsPieces
[0].size(),
4889 MI
.getOperand(UseIdx
));
4891 SmallVector
<Register
, 8> SplitPieces
;
4892 extractVectorParts(MI
.getReg(UseIdx
), NumElts
, SplitPieces
, MIRBuilder
,
4894 for (auto Reg
: SplitPieces
)
4895 InputOpsPieces
[UseNo
].push_back(Reg
);
4899 unsigned NumLeftovers
= OrigNumElts
% NumElts
? 1 : 0;
4901 // Take i-th piece of each input operand split and build sub-vector/scalar
4902 // instruction. Set i-th DstOp(s) from OutputOpsPieces as destination(s).
4903 for (unsigned i
= 0; i
< OrigNumElts
/ NumElts
+ NumLeftovers
; ++i
) {
4904 SmallVector
<DstOp
, 2> Defs
;
4905 for (unsigned DstNo
= 0; DstNo
< NumDefs
; ++DstNo
)
4906 Defs
.push_back(OutputOpsPieces
[DstNo
][i
]);
4908 SmallVector
<SrcOp
, 3> Uses
;
4909 for (unsigned InputNo
= 0; InputNo
< NumInputs
; ++InputNo
)
4910 Uses
.push_back(InputOpsPieces
[InputNo
][i
]);
4912 auto I
= MIRBuilder
.buildInstr(MI
.getOpcode(), Defs
, Uses
, MI
.getFlags());
4913 for (unsigned DstNo
= 0; DstNo
< NumDefs
; ++DstNo
)
4914 OutputRegs
[DstNo
].push_back(I
.getReg(DstNo
));
4917 // Merge small outputs into MI's output for each def operand.
4919 for (unsigned i
= 0; i
< NumDefs
; ++i
)
4920 mergeMixedSubvectors(MI
.getReg(i
), OutputRegs
[i
]);
4922 for (unsigned i
= 0; i
< NumDefs
; ++i
)
4923 MIRBuilder
.buildMergeLikeInstr(MI
.getReg(i
), OutputRegs
[i
]);
4926 MI
.eraseFromParent();
4930 LegalizerHelper::LegalizeResult
4931 LegalizerHelper::fewerElementsVectorPhi(GenericMachineInstr
&MI
,
4933 unsigned OrigNumElts
= MRI
.getType(MI
.getReg(0)).getNumElements();
4935 unsigned NumInputs
= MI
.getNumOperands() - MI
.getNumDefs();
4936 unsigned NumDefs
= MI
.getNumDefs();
4938 SmallVector
<DstOp
, 8> OutputOpsPieces
;
4939 SmallVector
<Register
, 8> OutputRegs
;
4940 makeDstOps(OutputOpsPieces
, MRI
.getType(MI
.getReg(0)), NumElts
);
4942 // Instructions that perform register split will be inserted in basic block
4943 // where register is defined (basic block is in the next operand).
4944 SmallVector
<SmallVector
<Register
, 8>, 3> InputOpsPieces(NumInputs
/ 2);
4945 for (unsigned UseIdx
= NumDefs
, UseNo
= 0; UseIdx
< MI
.getNumOperands();
4946 UseIdx
+= 2, ++UseNo
) {
4947 MachineBasicBlock
&OpMBB
= *MI
.getOperand(UseIdx
+ 1).getMBB();
4948 MIRBuilder
.setInsertPt(OpMBB
, OpMBB
.getFirstTerminatorForward());
4949 extractVectorParts(MI
.getReg(UseIdx
), NumElts
, InputOpsPieces
[UseNo
],
4953 // Build PHIs with fewer elements.
4954 unsigned NumLeftovers
= OrigNumElts
% NumElts
? 1 : 0;
4955 MIRBuilder
.setInsertPt(*MI
.getParent(), MI
);
4956 for (unsigned i
= 0; i
< OrigNumElts
/ NumElts
+ NumLeftovers
; ++i
) {
4957 auto Phi
= MIRBuilder
.buildInstr(TargetOpcode::G_PHI
);
4959 MRI
.createGenericVirtualRegister(OutputOpsPieces
[i
].getLLTTy(MRI
)));
4960 OutputRegs
.push_back(Phi
.getReg(0));
4962 for (unsigned j
= 0; j
< NumInputs
/ 2; ++j
) {
4963 Phi
.addUse(InputOpsPieces
[j
][i
]);
4964 Phi
.add(MI
.getOperand(1 + j
* 2 + 1));
4968 // Set the insert point after the existing PHIs
4969 MachineBasicBlock
&MBB
= *MI
.getParent();
4970 MIRBuilder
.setInsertPt(MBB
, MBB
.getFirstNonPHI());
4972 // Merge small outputs into MI's def.
4974 mergeMixedSubvectors(MI
.getReg(0), OutputRegs
);
4976 MIRBuilder
.buildMergeLikeInstr(MI
.getReg(0), OutputRegs
);
4979 MI
.eraseFromParent();
4983 LegalizerHelper::LegalizeResult
4984 LegalizerHelper::fewerElementsVectorUnmergeValues(MachineInstr
&MI
,
4987 const int NumDst
= MI
.getNumOperands() - 1;
4988 const Register SrcReg
= MI
.getOperand(NumDst
).getReg();
4989 LLT DstTy
= MRI
.getType(MI
.getOperand(0).getReg());
4990 LLT SrcTy
= MRI
.getType(SrcReg
);
4992 if (TypeIdx
!= 1 || NarrowTy
== DstTy
)
4993 return UnableToLegalize
;
4995 // Requires compatible types. Otherwise SrcReg should have been defined by
4996 // merge-like instruction that would get artifact combined. Most likely
4997 // instruction that defines SrcReg has to perform more/fewer elements
4998 // legalization compatible with NarrowTy.
4999 assert(SrcTy
.isVector() && NarrowTy
.isVector() && "Expected vector types");
5000 assert((SrcTy
.getScalarType() == NarrowTy
.getScalarType()) && "bad type");
5002 if ((SrcTy
.getSizeInBits() % NarrowTy
.getSizeInBits() != 0) ||
5003 (NarrowTy
.getSizeInBits() % DstTy
.getSizeInBits() != 0))
5004 return UnableToLegalize
;
5006 // This is most likely DstTy (smaller then register size) packed in SrcTy
5007 // (larger then register size) and since unmerge was not combined it will be
5008 // lowered to bit sequence extracts from register. Unpack SrcTy to NarrowTy
5009 // (register size) pieces first. Then unpack each of NarrowTy pieces to DstTy.
5011 // %1:_(DstTy), %2, %3, %4 = G_UNMERGE_VALUES %0:_(SrcTy)
5013 // %5:_(NarrowTy), %6 = G_UNMERGE_VALUES %0:_(SrcTy) - reg sequence
5014 // %1:_(DstTy), %2 = G_UNMERGE_VALUES %5:_(NarrowTy) - sequence of bits in reg
5015 // %3:_(DstTy), %4 = G_UNMERGE_VALUES %6:_(NarrowTy)
5016 auto Unmerge
= MIRBuilder
.buildUnmerge(NarrowTy
, SrcReg
);
5017 const int NumUnmerge
= Unmerge
->getNumOperands() - 1;
5018 const int PartsPerUnmerge
= NumDst
/ NumUnmerge
;
5020 for (int I
= 0; I
!= NumUnmerge
; ++I
) {
5021 auto MIB
= MIRBuilder
.buildInstr(TargetOpcode::G_UNMERGE_VALUES
);
5023 for (int J
= 0; J
!= PartsPerUnmerge
; ++J
)
5024 MIB
.addDef(MI
.getOperand(I
* PartsPerUnmerge
+ J
).getReg());
5025 MIB
.addUse(Unmerge
.getReg(I
));
5028 MI
.eraseFromParent();
5032 LegalizerHelper::LegalizeResult
5033 LegalizerHelper::fewerElementsVectorMerge(MachineInstr
&MI
, unsigned TypeIdx
,
5035 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
5036 // Requires compatible types. Otherwise user of DstReg did not perform unmerge
5037 // that should have been artifact combined. Most likely instruction that uses
5038 // DstReg has to do more/fewer elements legalization compatible with NarrowTy.
5039 assert(DstTy
.isVector() && NarrowTy
.isVector() && "Expected vector types");
5040 assert((DstTy
.getScalarType() == NarrowTy
.getScalarType()) && "bad type");
5041 if (NarrowTy
== SrcTy
)
5042 return UnableToLegalize
;
5044 // This attempts to lower part of LCMTy merge/unmerge sequence. Intended use
5045 // is for old mir tests. Since the changes to more/fewer elements it should no
5046 // longer be possible to generate MIR like this when starting from llvm-ir
5047 // because LCMTy approach was replaced with merge/unmerge to vector elements.
5049 assert(SrcTy
.isVector() && "Expected vector types");
5050 assert((SrcTy
.getScalarType() == NarrowTy
.getScalarType()) && "bad type");
5051 if ((DstTy
.getSizeInBits() % NarrowTy
.getSizeInBits() != 0) ||
5052 (NarrowTy
.getNumElements() >= SrcTy
.getNumElements()))
5053 return UnableToLegalize
;
5054 // %2:_(DstTy) = G_CONCAT_VECTORS %0:_(SrcTy), %1:_(SrcTy)
5056 // %3:_(EltTy), %4, %5 = G_UNMERGE_VALUES %0:_(SrcTy)
5057 // %6:_(EltTy), %7, %8 = G_UNMERGE_VALUES %1:_(SrcTy)
5058 // %9:_(NarrowTy) = G_BUILD_VECTOR %3:_(EltTy), %4
5059 // %10:_(NarrowTy) = G_BUILD_VECTOR %5:_(EltTy), %6
5060 // %11:_(NarrowTy) = G_BUILD_VECTOR %7:_(EltTy), %8
5061 // %2:_(DstTy) = G_CONCAT_VECTORS %9:_(NarrowTy), %10, %11
5063 SmallVector
<Register
, 8> Elts
;
5064 LLT EltTy
= MRI
.getType(MI
.getOperand(1).getReg()).getScalarType();
5065 for (unsigned i
= 1; i
< MI
.getNumOperands(); ++i
) {
5066 auto Unmerge
= MIRBuilder
.buildUnmerge(EltTy
, MI
.getOperand(i
).getReg());
5067 for (unsigned j
= 0; j
< Unmerge
->getNumDefs(); ++j
)
5068 Elts
.push_back(Unmerge
.getReg(j
));
5071 SmallVector
<Register
, 8> NarrowTyElts
;
5072 unsigned NumNarrowTyElts
= NarrowTy
.getNumElements();
5073 unsigned NumNarrowTyPieces
= DstTy
.getNumElements() / NumNarrowTyElts
;
5074 for (unsigned i
= 0, Offset
= 0; i
< NumNarrowTyPieces
;
5075 ++i
, Offset
+= NumNarrowTyElts
) {
5076 ArrayRef
<Register
> Pieces(&Elts
[Offset
], NumNarrowTyElts
);
5077 NarrowTyElts
.push_back(
5078 MIRBuilder
.buildMergeLikeInstr(NarrowTy
, Pieces
).getReg(0));
5081 MIRBuilder
.buildMergeLikeInstr(DstReg
, NarrowTyElts
);
5082 MI
.eraseFromParent();
5086 assert(TypeIdx
== 0 && "Bad type index");
5087 if ((NarrowTy
.getSizeInBits() % SrcTy
.getSizeInBits() != 0) ||
5088 (DstTy
.getSizeInBits() % NarrowTy
.getSizeInBits() != 0))
5089 return UnableToLegalize
;
5091 // This is most likely SrcTy (smaller then register size) packed in DstTy
5092 // (larger then register size) and since merge was not combined it will be
5093 // lowered to bit sequence packing into register. Merge SrcTy to NarrowTy
5094 // (register size) pieces first. Then merge each of NarrowTy pieces to DstTy.
5096 // %0:_(DstTy) = G_MERGE_VALUES %1:_(SrcTy), %2, %3, %4
5098 // %5:_(NarrowTy) = G_MERGE_VALUES %1:_(SrcTy), %2 - sequence of bits in reg
5099 // %6:_(NarrowTy) = G_MERGE_VALUES %3:_(SrcTy), %4
5100 // %0:_(DstTy) = G_MERGE_VALUES %5:_(NarrowTy), %6 - reg sequence
5101 SmallVector
<Register
, 8> NarrowTyElts
;
5102 unsigned NumParts
= DstTy
.getNumElements() / NarrowTy
.getNumElements();
5103 unsigned NumSrcElts
= SrcTy
.isVector() ? SrcTy
.getNumElements() : 1;
5104 unsigned NumElts
= NarrowTy
.getNumElements() / NumSrcElts
;
5105 for (unsigned i
= 0; i
< NumParts
; ++i
) {
5106 SmallVector
<Register
, 8> Sources
;
5107 for (unsigned j
= 0; j
< NumElts
; ++j
)
5108 Sources
.push_back(MI
.getOperand(1 + i
* NumElts
+ j
).getReg());
5109 NarrowTyElts
.push_back(
5110 MIRBuilder
.buildMergeLikeInstr(NarrowTy
, Sources
).getReg(0));
5113 MIRBuilder
.buildMergeLikeInstr(DstReg
, NarrowTyElts
);
5114 MI
.eraseFromParent();
5118 LegalizerHelper::LegalizeResult
5119 LegalizerHelper::fewerElementsVectorExtractInsertVectorElt(MachineInstr
&MI
,
5122 auto [DstReg
, SrcVec
] = MI
.getFirst2Regs();
5124 bool IsInsert
= MI
.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT
;
5126 assert((IsInsert
? TypeIdx
== 0 : TypeIdx
== 1) && "not a vector type index");
5128 InsertVal
= MI
.getOperand(2).getReg();
5130 Register Idx
= MI
.getOperand(MI
.getNumOperands() - 1).getReg();
5132 // TODO: Handle total scalarization case.
5133 if (!NarrowVecTy
.isVector())
5134 return UnableToLegalize
;
5136 LLT VecTy
= MRI
.getType(SrcVec
);
5138 // If the index is a constant, we can really break this down as you would
5139 // expect, and index into the target size pieces.
5141 auto MaybeCst
= getIConstantVRegValWithLookThrough(Idx
, MRI
);
5143 IdxVal
= MaybeCst
->Value
.getSExtValue();
5144 // Avoid out of bounds indexing the pieces.
5145 if (IdxVal
>= VecTy
.getNumElements()) {
5146 MIRBuilder
.buildUndef(DstReg
);
5147 MI
.eraseFromParent();
5151 SmallVector
<Register
, 8> VecParts
;
5152 LLT GCDTy
= extractGCDType(VecParts
, VecTy
, NarrowVecTy
, SrcVec
);
5154 // Build a sequence of NarrowTy pieces in VecParts for this operand.
5155 LLT LCMTy
= buildLCMMergePieces(VecTy
, NarrowVecTy
, GCDTy
, VecParts
,
5156 TargetOpcode::G_ANYEXT
);
5158 unsigned NewNumElts
= NarrowVecTy
.getNumElements();
5160 LLT IdxTy
= MRI
.getType(Idx
);
5161 int64_t PartIdx
= IdxVal
/ NewNumElts
;
5163 MIRBuilder
.buildConstant(IdxTy
, IdxVal
- NewNumElts
* PartIdx
);
5166 LLT PartTy
= MRI
.getType(VecParts
[PartIdx
]);
5168 // Use the adjusted index to insert into one of the subvectors.
5169 auto InsertPart
= MIRBuilder
.buildInsertVectorElement(
5170 PartTy
, VecParts
[PartIdx
], InsertVal
, NewIdx
);
5171 VecParts
[PartIdx
] = InsertPart
.getReg(0);
5173 // Recombine the inserted subvector with the others to reform the result
5175 buildWidenedRemergeToDst(DstReg
, LCMTy
, VecParts
);
5177 MIRBuilder
.buildExtractVectorElement(DstReg
, VecParts
[PartIdx
], NewIdx
);
5180 MI
.eraseFromParent();
5184 // With a variable index, we can't perform the operation in a smaller type, so
5185 // we're forced to expand this.
5187 // TODO: We could emit a chain of compare/select to figure out which piece to
5189 return lowerExtractInsertVectorElt(MI
);
5192 LegalizerHelper::LegalizeResult
5193 LegalizerHelper::reduceLoadStoreWidth(GLoadStore
&LdStMI
, unsigned TypeIdx
,
5195 // FIXME: Don't know how to handle secondary types yet.
5197 return UnableToLegalize
;
5199 // This implementation doesn't work for atomics. Give up instead of doing
5200 // something invalid.
5201 if (LdStMI
.isAtomic())
5202 return UnableToLegalize
;
5204 bool IsLoad
= isa
<GLoad
>(LdStMI
);
5205 Register ValReg
= LdStMI
.getReg(0);
5206 Register AddrReg
= LdStMI
.getPointerReg();
5207 LLT ValTy
= MRI
.getType(ValReg
);
5209 // FIXME: Do we need a distinct NarrowMemory legalize action?
5210 if (ValTy
.getSizeInBits() != 8 * LdStMI
.getMemSize().getValue()) {
5211 LLVM_DEBUG(dbgs() << "Can't narrow extload/truncstore\n");
5212 return UnableToLegalize
;
5216 int NumLeftover
= -1;
5218 SmallVector
<Register
, 8> NarrowRegs
, NarrowLeftoverRegs
;
5220 std::tie(NumParts
, NumLeftover
) = getNarrowTypeBreakDown(ValTy
, NarrowTy
, LeftoverTy
);
5222 if (extractParts(ValReg
, ValTy
, NarrowTy
, LeftoverTy
, NarrowRegs
,
5223 NarrowLeftoverRegs
, MIRBuilder
, MRI
)) {
5224 NumParts
= NarrowRegs
.size();
5225 NumLeftover
= NarrowLeftoverRegs
.size();
5230 return UnableToLegalize
;
5232 LLT PtrTy
= MRI
.getType(AddrReg
);
5233 const LLT OffsetTy
= LLT::scalar(PtrTy
.getSizeInBits());
5235 unsigned TotalSize
= ValTy
.getSizeInBits();
5237 // Split the load/store into PartTy sized pieces starting at Offset. If this
5238 // is a load, return the new registers in ValRegs. For a store, each elements
5239 // of ValRegs should be PartTy. Returns the next offset that needs to be
5241 bool isBigEndian
= MIRBuilder
.getDataLayout().isBigEndian();
5242 auto MMO
= LdStMI
.getMMO();
5243 auto splitTypePieces
= [=](LLT PartTy
, SmallVectorImpl
<Register
> &ValRegs
,
5244 unsigned NumParts
, unsigned Offset
) -> unsigned {
5245 MachineFunction
&MF
= MIRBuilder
.getMF();
5246 unsigned PartSize
= PartTy
.getSizeInBits();
5247 for (unsigned Idx
= 0, E
= NumParts
; Idx
!= E
&& Offset
< TotalSize
;
5249 unsigned ByteOffset
= Offset
/ 8;
5250 Register NewAddrReg
;
5252 MIRBuilder
.materializePtrAdd(NewAddrReg
, AddrReg
, OffsetTy
, ByteOffset
);
5254 MachineMemOperand
*NewMMO
=
5255 MF
.getMachineMemOperand(&MMO
, ByteOffset
, PartTy
);
5258 Register Dst
= MRI
.createGenericVirtualRegister(PartTy
);
5259 ValRegs
.push_back(Dst
);
5260 MIRBuilder
.buildLoad(Dst
, NewAddrReg
, *NewMMO
);
5262 MIRBuilder
.buildStore(ValRegs
[Idx
], NewAddrReg
, *NewMMO
);
5264 Offset
= isBigEndian
? Offset
- PartSize
: Offset
+ PartSize
;
5270 unsigned Offset
= isBigEndian
? TotalSize
- NarrowTy
.getSizeInBits() : 0;
5271 unsigned HandledOffset
=
5272 splitTypePieces(NarrowTy
, NarrowRegs
, NumParts
, Offset
);
5274 // Handle the rest of the register if this isn't an even type breakdown.
5275 if (LeftoverTy
.isValid())
5276 splitTypePieces(LeftoverTy
, NarrowLeftoverRegs
, NumLeftover
, HandledOffset
);
5279 insertParts(ValReg
, ValTy
, NarrowTy
, NarrowRegs
,
5280 LeftoverTy
, NarrowLeftoverRegs
);
5283 LdStMI
.eraseFromParent();
5287 LegalizerHelper::LegalizeResult
5288 LegalizerHelper::fewerElementsVector(MachineInstr
&MI
, unsigned TypeIdx
,
5290 using namespace TargetOpcode
;
5291 GenericMachineInstr
&GMI
= cast
<GenericMachineInstr
>(MI
);
5292 unsigned NumElts
= NarrowTy
.isVector() ? NarrowTy
.getNumElements() : 1;
5294 switch (MI
.getOpcode()) {
5295 case G_IMPLICIT_DEF
:
5311 case G_FCANONICALIZE
:
5328 case G_INTRINSIC_LRINT
:
5329 case G_INTRINSIC_LLRINT
:
5330 case G_INTRINSIC_ROUND
:
5331 case G_INTRINSIC_ROUNDEVEN
:
5334 case G_INTRINSIC_TRUNC
:
5361 case G_FMINNUM_IEEE
:
5362 case G_FMAXNUM_IEEE
:
5382 case G_CTLZ_ZERO_UNDEF
:
5384 case G_CTTZ_ZERO_UNDEF
:
5400 case G_ADDRSPACE_CAST
:
5413 case G_STRICT_FLDEXP
:
5415 return fewerElementsVectorMultiEltType(GMI
, NumElts
);
5418 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {1 /*cpm predicate*/});
5420 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {2, 3 /*mask,fpsem*/});
5422 if (MRI
.getType(MI
.getOperand(1).getReg()).isVector())
5423 return fewerElementsVectorMultiEltType(GMI
, NumElts
);
5424 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {1 /*scalar cond*/});
5426 return fewerElementsVectorPhi(GMI
, NumElts
);
5427 case G_UNMERGE_VALUES
:
5428 return fewerElementsVectorUnmergeValues(MI
, TypeIdx
, NarrowTy
);
5429 case G_BUILD_VECTOR
:
5430 assert(TypeIdx
== 0 && "not a vector type index");
5431 return fewerElementsVectorMerge(MI
, TypeIdx
, NarrowTy
);
5432 case G_CONCAT_VECTORS
:
5433 if (TypeIdx
!= 1) // TODO: This probably does work as expected already.
5434 return UnableToLegalize
;
5435 return fewerElementsVectorMerge(MI
, TypeIdx
, NarrowTy
);
5436 case G_EXTRACT_VECTOR_ELT
:
5437 case G_INSERT_VECTOR_ELT
:
5438 return fewerElementsVectorExtractInsertVectorElt(MI
, TypeIdx
, NarrowTy
);
5441 return reduceLoadStoreWidth(cast
<GLoadStore
>(MI
), TypeIdx
, NarrowTy
);
5443 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {2 /*imm*/});
5444 GISEL_VECREDUCE_CASES_NONSEQ
5445 return fewerElementsVectorReductions(MI
, TypeIdx
, NarrowTy
);
5446 case TargetOpcode::G_VECREDUCE_SEQ_FADD
:
5447 case TargetOpcode::G_VECREDUCE_SEQ_FMUL
:
5448 return fewerElementsVectorSeqReductions(MI
, TypeIdx
, NarrowTy
);
5449 case G_SHUFFLE_VECTOR
:
5450 return fewerElementsVectorShuffle(MI
, TypeIdx
, NarrowTy
);
5452 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {2 /*pow*/});
5454 return fewerElementsBitcast(MI
, TypeIdx
, NarrowTy
);
5455 case G_INTRINSIC_FPTRUNC_ROUND
:
5456 return fewerElementsVectorMultiEltType(GMI
, NumElts
, {2});
5458 return UnableToLegalize
;
5462 LegalizerHelper::LegalizeResult
5463 LegalizerHelper::fewerElementsBitcast(MachineInstr
&MI
, unsigned int TypeIdx
,
5465 assert(MI
.getOpcode() == TargetOpcode::G_BITCAST
&&
5466 "Not a bitcast operation");
5469 return UnableToLegalize
;
5471 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
5473 unsigned NewElemCount
=
5474 NarrowTy
.getSizeInBits() / SrcTy
.getScalarSizeInBits();
5475 LLT SrcNarrowTy
= LLT::fixed_vector(NewElemCount
, SrcTy
.getElementType());
5477 // Split the Src and Dst Reg into smaller registers
5478 SmallVector
<Register
> SrcVRegs
, BitcastVRegs
;
5479 if (extractGCDType(SrcVRegs
, DstTy
, SrcNarrowTy
, SrcReg
) != SrcNarrowTy
)
5480 return UnableToLegalize
;
5482 // Build new smaller bitcast instructions
5483 // Not supporting Leftover types for now but will have to
5484 for (unsigned i
= 0; i
< SrcVRegs
.size(); i
++)
5485 BitcastVRegs
.push_back(
5486 MIRBuilder
.buildBitcast(NarrowTy
, SrcVRegs
[i
]).getReg(0));
5488 MIRBuilder
.buildMergeLikeInstr(DstReg
, BitcastVRegs
);
5489 MI
.eraseFromParent();
5493 LegalizerHelper::LegalizeResult
LegalizerHelper::fewerElementsVectorShuffle(
5494 MachineInstr
&MI
, unsigned int TypeIdx
, LLT NarrowTy
) {
5495 assert(MI
.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR
);
5497 return UnableToLegalize
;
5499 auto [DstReg
, DstTy
, Src1Reg
, Src1Ty
, Src2Reg
, Src2Ty
] =
5500 MI
.getFirst3RegLLTs();
5501 ArrayRef
<int> Mask
= MI
.getOperand(3).getShuffleMask();
5502 // The shuffle should be canonicalized by now.
5503 if (DstTy
!= Src1Ty
)
5504 return UnableToLegalize
;
5505 if (DstTy
!= Src2Ty
)
5506 return UnableToLegalize
;
5508 if (!isPowerOf2_32(DstTy
.getNumElements()))
5509 return UnableToLegalize
;
5511 // We only support splitting a shuffle into 2, so adjust NarrowTy accordingly.
5512 // Further legalization attempts will be needed to do split further.
5514 DstTy
.changeElementCount(DstTy
.getElementCount().divideCoefficientBy(2));
5515 unsigned NewElts
= NarrowTy
.isVector() ? NarrowTy
.getNumElements() : 1;
5517 SmallVector
<Register
> SplitSrc1Regs
, SplitSrc2Regs
;
5518 extractParts(Src1Reg
, NarrowTy
, 2, SplitSrc1Regs
, MIRBuilder
, MRI
);
5519 extractParts(Src2Reg
, NarrowTy
, 2, SplitSrc2Regs
, MIRBuilder
, MRI
);
5520 Register Inputs
[4] = {SplitSrc1Regs
[0], SplitSrc1Regs
[1], SplitSrc2Regs
[0],
5525 // If Lo or Hi uses elements from at most two of the four input vectors, then
5526 // express it as a vector shuffle of those two inputs. Otherwise extract the
5527 // input elements by hand and construct the Lo/Hi output using a BUILD_VECTOR.
5528 SmallVector
<int, 16> Ops
;
5529 for (unsigned High
= 0; High
< 2; ++High
) {
5530 Register
&Output
= High
? Hi
: Lo
;
5532 // Build a shuffle mask for the output, discovering on the fly which
5533 // input vectors to use as shuffle operands (recorded in InputUsed).
5534 // If building a suitable shuffle vector proves too hard, then bail
5535 // out with useBuildVector set.
5536 unsigned InputUsed
[2] = {-1U, -1U}; // Not yet discovered.
5537 unsigned FirstMaskIdx
= High
* NewElts
;
5538 bool UseBuildVector
= false;
5539 for (unsigned MaskOffset
= 0; MaskOffset
< NewElts
; ++MaskOffset
) {
5540 // The mask element. This indexes into the input.
5541 int Idx
= Mask
[FirstMaskIdx
+ MaskOffset
];
5543 // The input vector this mask element indexes into.
5544 unsigned Input
= (unsigned)Idx
/ NewElts
;
5546 if (Input
>= std::size(Inputs
)) {
5547 // The mask element does not index into any input vector.
5552 // Turn the index into an offset from the start of the input vector.
5553 Idx
-= Input
* NewElts
;
5555 // Find or create a shuffle vector operand to hold this input.
5557 for (OpNo
= 0; OpNo
< std::size(InputUsed
); ++OpNo
) {
5558 if (InputUsed
[OpNo
] == Input
) {
5559 // This input vector is already an operand.
5561 } else if (InputUsed
[OpNo
] == -1U) {
5562 // Create a new operand for this input vector.
5563 InputUsed
[OpNo
] = Input
;
5568 if (OpNo
>= std::size(InputUsed
)) {
5569 // More than two input vectors used! Give up on trying to create a
5570 // shuffle vector. Insert all elements into a BUILD_VECTOR instead.
5571 UseBuildVector
= true;
5575 // Add the mask index for the new shuffle vector.
5576 Ops
.push_back(Idx
+ OpNo
* NewElts
);
5579 if (UseBuildVector
) {
5580 LLT EltTy
= NarrowTy
.getElementType();
5581 SmallVector
<Register
, 16> SVOps
;
5583 // Extract the input elements by hand.
5584 for (unsigned MaskOffset
= 0; MaskOffset
< NewElts
; ++MaskOffset
) {
5585 // The mask element. This indexes into the input.
5586 int Idx
= Mask
[FirstMaskIdx
+ MaskOffset
];
5588 // The input vector this mask element indexes into.
5589 unsigned Input
= (unsigned)Idx
/ NewElts
;
5591 if (Input
>= std::size(Inputs
)) {
5592 // The mask element is "undef" or indexes off the end of the input.
5593 SVOps
.push_back(MIRBuilder
.buildUndef(EltTy
).getReg(0));
5597 // Turn the index into an offset from the start of the input vector.
5598 Idx
-= Input
* NewElts
;
5600 // Extract the vector element by hand.
5601 SVOps
.push_back(MIRBuilder
5602 .buildExtractVectorElement(
5603 EltTy
, Inputs
[Input
],
5604 MIRBuilder
.buildConstant(LLT::scalar(32), Idx
))
5608 // Construct the Lo/Hi output using a G_BUILD_VECTOR.
5609 Output
= MIRBuilder
.buildBuildVector(NarrowTy
, SVOps
).getReg(0);
5610 } else if (InputUsed
[0] == -1U) {
5611 // No input vectors were used! The result is undefined.
5612 Output
= MIRBuilder
.buildUndef(NarrowTy
).getReg(0);
5614 Register Op0
= Inputs
[InputUsed
[0]];
5615 // If only one input was used, use an undefined vector for the other.
5616 Register Op1
= InputUsed
[1] == -1U
5617 ? MIRBuilder
.buildUndef(NarrowTy
).getReg(0)
5618 : Inputs
[InputUsed
[1]];
5619 // At least one input vector was used. Create a new shuffle vector.
5620 Output
= MIRBuilder
.buildShuffleVector(NarrowTy
, Op0
, Op1
, Ops
).getReg(0);
5626 MIRBuilder
.buildMergeLikeInstr(DstReg
, {Lo
, Hi
});
5627 MI
.eraseFromParent();
5631 LegalizerHelper::LegalizeResult
LegalizerHelper::fewerElementsVectorReductions(
5632 MachineInstr
&MI
, unsigned int TypeIdx
, LLT NarrowTy
) {
5633 auto &RdxMI
= cast
<GVecReduce
>(MI
);
5636 return UnableToLegalize
;
5638 // The semantics of the normal non-sequential reductions allow us to freely
5639 // re-associate the operation.
5640 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = RdxMI
.getFirst2RegLLTs();
5642 if (NarrowTy
.isVector() &&
5643 (SrcTy
.getNumElements() % NarrowTy
.getNumElements() != 0))
5644 return UnableToLegalize
;
5646 unsigned ScalarOpc
= RdxMI
.getScalarOpcForReduction();
5647 SmallVector
<Register
> SplitSrcs
;
5648 // If NarrowTy is a scalar then we're being asked to scalarize.
5649 const unsigned NumParts
=
5650 NarrowTy
.isVector() ? SrcTy
.getNumElements() / NarrowTy
.getNumElements()
5651 : SrcTy
.getNumElements();
5653 extractParts(SrcReg
, NarrowTy
, NumParts
, SplitSrcs
, MIRBuilder
, MRI
);
5654 if (NarrowTy
.isScalar()) {
5655 if (DstTy
!= NarrowTy
)
5656 return UnableToLegalize
; // FIXME: handle implicit extensions.
5658 if (isPowerOf2_32(NumParts
)) {
5659 // Generate a tree of scalar operations to reduce the critical path.
5660 SmallVector
<Register
> PartialResults
;
5661 unsigned NumPartsLeft
= NumParts
;
5662 while (NumPartsLeft
> 1) {
5663 for (unsigned Idx
= 0; Idx
< NumPartsLeft
- 1; Idx
+= 2) {
5664 PartialResults
.emplace_back(
5666 .buildInstr(ScalarOpc
, {NarrowTy
},
5667 {SplitSrcs
[Idx
], SplitSrcs
[Idx
+ 1]})
5670 SplitSrcs
= PartialResults
;
5671 PartialResults
.clear();
5672 NumPartsLeft
= SplitSrcs
.size();
5674 assert(SplitSrcs
.size() == 1);
5675 MIRBuilder
.buildCopy(DstReg
, SplitSrcs
[0]);
5676 MI
.eraseFromParent();
5679 // If we can't generate a tree, then just do sequential operations.
5680 Register Acc
= SplitSrcs
[0];
5681 for (unsigned Idx
= 1; Idx
< NumParts
; ++Idx
)
5682 Acc
= MIRBuilder
.buildInstr(ScalarOpc
, {NarrowTy
}, {Acc
, SplitSrcs
[Idx
]})
5684 MIRBuilder
.buildCopy(DstReg
, Acc
);
5685 MI
.eraseFromParent();
5688 SmallVector
<Register
> PartialReductions
;
5689 for (unsigned Part
= 0; Part
< NumParts
; ++Part
) {
5690 PartialReductions
.push_back(
5691 MIRBuilder
.buildInstr(RdxMI
.getOpcode(), {DstTy
}, {SplitSrcs
[Part
]})
5695 // If the types involved are powers of 2, we can generate intermediate vector
5696 // ops, before generating a final reduction operation.
5697 if (isPowerOf2_32(SrcTy
.getNumElements()) &&
5698 isPowerOf2_32(NarrowTy
.getNumElements())) {
5699 return tryNarrowPow2Reduction(MI
, SrcReg
, SrcTy
, NarrowTy
, ScalarOpc
);
5702 Register Acc
= PartialReductions
[0];
5703 for (unsigned Part
= 1; Part
< NumParts
; ++Part
) {
5704 if (Part
== NumParts
- 1) {
5705 MIRBuilder
.buildInstr(ScalarOpc
, {DstReg
},
5706 {Acc
, PartialReductions
[Part
]});
5709 .buildInstr(ScalarOpc
, {DstTy
}, {Acc
, PartialReductions
[Part
]})
5713 MI
.eraseFromParent();
5717 LegalizerHelper::LegalizeResult
5718 LegalizerHelper::fewerElementsVectorSeqReductions(MachineInstr
&MI
,
5719 unsigned int TypeIdx
,
5721 auto [DstReg
, DstTy
, ScalarReg
, ScalarTy
, SrcReg
, SrcTy
] =
5722 MI
.getFirst3RegLLTs();
5723 if (!NarrowTy
.isScalar() || TypeIdx
!= 2 || DstTy
!= ScalarTy
||
5725 return UnableToLegalize
;
5727 assert((MI
.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
||
5728 MI
.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FMUL
) &&
5729 "Unexpected vecreduce opcode");
5730 unsigned ScalarOpc
= MI
.getOpcode() == TargetOpcode::G_VECREDUCE_SEQ_FADD
5731 ? TargetOpcode::G_FADD
5732 : TargetOpcode::G_FMUL
;
5734 SmallVector
<Register
> SplitSrcs
;
5735 unsigned NumParts
= SrcTy
.getNumElements();
5736 extractParts(SrcReg
, NarrowTy
, NumParts
, SplitSrcs
, MIRBuilder
, MRI
);
5737 Register Acc
= ScalarReg
;
5738 for (unsigned i
= 0; i
< NumParts
; i
++)
5739 Acc
= MIRBuilder
.buildInstr(ScalarOpc
, {NarrowTy
}, {Acc
, SplitSrcs
[i
]})
5742 MIRBuilder
.buildCopy(DstReg
, Acc
);
5743 MI
.eraseFromParent();
5747 LegalizerHelper::LegalizeResult
5748 LegalizerHelper::tryNarrowPow2Reduction(MachineInstr
&MI
, Register SrcReg
,
5749 LLT SrcTy
, LLT NarrowTy
,
5750 unsigned ScalarOpc
) {
5751 SmallVector
<Register
> SplitSrcs
;
5752 // Split the sources into NarrowTy size pieces.
5753 extractParts(SrcReg
, NarrowTy
,
5754 SrcTy
.getNumElements() / NarrowTy
.getNumElements(), SplitSrcs
,
5756 // We're going to do a tree reduction using vector operations until we have
5757 // one NarrowTy size value left.
5758 while (SplitSrcs
.size() > 1) {
5759 SmallVector
<Register
> PartialRdxs
;
5760 for (unsigned Idx
= 0; Idx
< SplitSrcs
.size()-1; Idx
+= 2) {
5761 Register LHS
= SplitSrcs
[Idx
];
5762 Register RHS
= SplitSrcs
[Idx
+ 1];
5763 // Create the intermediate vector op.
5765 MIRBuilder
.buildInstr(ScalarOpc
, {NarrowTy
}, {LHS
, RHS
}).getReg(0);
5766 PartialRdxs
.push_back(Res
);
5768 SplitSrcs
= std::move(PartialRdxs
);
5770 // Finally generate the requested NarrowTy based reduction.
5771 Observer
.changingInstr(MI
);
5772 MI
.getOperand(1).setReg(SplitSrcs
[0]);
5773 Observer
.changedInstr(MI
);
5777 LegalizerHelper::LegalizeResult
5778 LegalizerHelper::narrowScalarShiftByConstant(MachineInstr
&MI
, const APInt
&Amt
,
5779 const LLT HalfTy
, const LLT AmtTy
) {
5781 Register InL
= MRI
.createGenericVirtualRegister(HalfTy
);
5782 Register InH
= MRI
.createGenericVirtualRegister(HalfTy
);
5783 MIRBuilder
.buildUnmerge({InL
, InH
}, MI
.getOperand(1));
5786 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(0), {InL
, InH
});
5787 MI
.eraseFromParent();
5792 unsigned NVTBits
= HalfTy
.getSizeInBits();
5793 unsigned VTBits
= 2 * NVTBits
;
5795 SrcOp
Lo(Register(0)), Hi(Register(0));
5796 if (MI
.getOpcode() == TargetOpcode::G_SHL
) {
5797 if (Amt
.ugt(VTBits
)) {
5798 Lo
= Hi
= MIRBuilder
.buildConstant(NVT
, 0);
5799 } else if (Amt
.ugt(NVTBits
)) {
5800 Lo
= MIRBuilder
.buildConstant(NVT
, 0);
5801 Hi
= MIRBuilder
.buildShl(NVT
, InL
,
5802 MIRBuilder
.buildConstant(AmtTy
, Amt
- NVTBits
));
5803 } else if (Amt
== NVTBits
) {
5804 Lo
= MIRBuilder
.buildConstant(NVT
, 0);
5807 Lo
= MIRBuilder
.buildShl(NVT
, InL
, MIRBuilder
.buildConstant(AmtTy
, Amt
));
5809 MIRBuilder
.buildShl(NVT
, InH
, MIRBuilder
.buildConstant(AmtTy
, Amt
));
5810 auto OrRHS
= MIRBuilder
.buildLShr(
5811 NVT
, InL
, MIRBuilder
.buildConstant(AmtTy
, -Amt
+ NVTBits
));
5812 Hi
= MIRBuilder
.buildOr(NVT
, OrLHS
, OrRHS
);
5814 } else if (MI
.getOpcode() == TargetOpcode::G_LSHR
) {
5815 if (Amt
.ugt(VTBits
)) {
5816 Lo
= Hi
= MIRBuilder
.buildConstant(NVT
, 0);
5817 } else if (Amt
.ugt(NVTBits
)) {
5818 Lo
= MIRBuilder
.buildLShr(NVT
, InH
,
5819 MIRBuilder
.buildConstant(AmtTy
, Amt
- NVTBits
));
5820 Hi
= MIRBuilder
.buildConstant(NVT
, 0);
5821 } else if (Amt
== NVTBits
) {
5823 Hi
= MIRBuilder
.buildConstant(NVT
, 0);
5825 auto ShiftAmtConst
= MIRBuilder
.buildConstant(AmtTy
, Amt
);
5827 auto OrLHS
= MIRBuilder
.buildLShr(NVT
, InL
, ShiftAmtConst
);
5828 auto OrRHS
= MIRBuilder
.buildShl(
5829 NVT
, InH
, MIRBuilder
.buildConstant(AmtTy
, -Amt
+ NVTBits
));
5831 Lo
= MIRBuilder
.buildOr(NVT
, OrLHS
, OrRHS
);
5832 Hi
= MIRBuilder
.buildLShr(NVT
, InH
, ShiftAmtConst
);
5835 if (Amt
.ugt(VTBits
)) {
5836 Hi
= Lo
= MIRBuilder
.buildAShr(
5837 NVT
, InH
, MIRBuilder
.buildConstant(AmtTy
, NVTBits
- 1));
5838 } else if (Amt
.ugt(NVTBits
)) {
5839 Lo
= MIRBuilder
.buildAShr(NVT
, InH
,
5840 MIRBuilder
.buildConstant(AmtTy
, Amt
- NVTBits
));
5841 Hi
= MIRBuilder
.buildAShr(NVT
, InH
,
5842 MIRBuilder
.buildConstant(AmtTy
, NVTBits
- 1));
5843 } else if (Amt
== NVTBits
) {
5845 Hi
= MIRBuilder
.buildAShr(NVT
, InH
,
5846 MIRBuilder
.buildConstant(AmtTy
, NVTBits
- 1));
5848 auto ShiftAmtConst
= MIRBuilder
.buildConstant(AmtTy
, Amt
);
5850 auto OrLHS
= MIRBuilder
.buildLShr(NVT
, InL
, ShiftAmtConst
);
5851 auto OrRHS
= MIRBuilder
.buildShl(
5852 NVT
, InH
, MIRBuilder
.buildConstant(AmtTy
, -Amt
+ NVTBits
));
5854 Lo
= MIRBuilder
.buildOr(NVT
, OrLHS
, OrRHS
);
5855 Hi
= MIRBuilder
.buildAShr(NVT
, InH
, ShiftAmtConst
);
5859 MIRBuilder
.buildMergeLikeInstr(MI
.getOperand(0), {Lo
, Hi
});
5860 MI
.eraseFromParent();
5865 // TODO: Optimize if constant shift amount.
5866 LegalizerHelper::LegalizeResult
5867 LegalizerHelper::narrowScalarShift(MachineInstr
&MI
, unsigned TypeIdx
,
5870 Observer
.changingInstr(MI
);
5871 narrowScalarSrc(MI
, RequestedTy
, 2);
5872 Observer
.changedInstr(MI
);
5876 Register DstReg
= MI
.getOperand(0).getReg();
5877 LLT DstTy
= MRI
.getType(DstReg
);
5878 if (DstTy
.isVector())
5879 return UnableToLegalize
;
5881 Register Amt
= MI
.getOperand(2).getReg();
5882 LLT ShiftAmtTy
= MRI
.getType(Amt
);
5883 const unsigned DstEltSize
= DstTy
.getScalarSizeInBits();
5884 if (DstEltSize
% 2 != 0)
5885 return UnableToLegalize
;
5887 // Ignore the input type. We can only go to exactly half the size of the
5888 // input. If that isn't small enough, the resulting pieces will be further
5890 const unsigned NewBitSize
= DstEltSize
/ 2;
5891 const LLT HalfTy
= LLT::scalar(NewBitSize
);
5892 const LLT CondTy
= LLT::scalar(1);
5894 if (auto VRegAndVal
= getIConstantVRegValWithLookThrough(Amt
, MRI
)) {
5895 return narrowScalarShiftByConstant(MI
, VRegAndVal
->Value
, HalfTy
,
5899 // TODO: Expand with known bits.
5901 // Handle the fully general expansion by an unknown amount.
5902 auto NewBits
= MIRBuilder
.buildConstant(ShiftAmtTy
, NewBitSize
);
5904 Register InL
= MRI
.createGenericVirtualRegister(HalfTy
);
5905 Register InH
= MRI
.createGenericVirtualRegister(HalfTy
);
5906 MIRBuilder
.buildUnmerge({InL
, InH
}, MI
.getOperand(1));
5908 auto AmtExcess
= MIRBuilder
.buildSub(ShiftAmtTy
, Amt
, NewBits
);
5909 auto AmtLack
= MIRBuilder
.buildSub(ShiftAmtTy
, NewBits
, Amt
);
5911 auto Zero
= MIRBuilder
.buildConstant(ShiftAmtTy
, 0);
5912 auto IsShort
= MIRBuilder
.buildICmp(ICmpInst::ICMP_ULT
, CondTy
, Amt
, NewBits
);
5913 auto IsZero
= MIRBuilder
.buildICmp(ICmpInst::ICMP_EQ
, CondTy
, Amt
, Zero
);
5915 Register ResultRegs
[2];
5916 switch (MI
.getOpcode()) {
5917 case TargetOpcode::G_SHL
: {
5918 // Short: ShAmt < NewBitSize
5919 auto LoS
= MIRBuilder
.buildShl(HalfTy
, InL
, Amt
);
5921 auto LoOr
= MIRBuilder
.buildLShr(HalfTy
, InL
, AmtLack
);
5922 auto HiOr
= MIRBuilder
.buildShl(HalfTy
, InH
, Amt
);
5923 auto HiS
= MIRBuilder
.buildOr(HalfTy
, LoOr
, HiOr
);
5925 // Long: ShAmt >= NewBitSize
5926 auto LoL
= MIRBuilder
.buildConstant(HalfTy
, 0); // Lo part is zero.
5927 auto HiL
= MIRBuilder
.buildShl(HalfTy
, InL
, AmtExcess
); // Hi from Lo part.
5929 auto Lo
= MIRBuilder
.buildSelect(HalfTy
, IsShort
, LoS
, LoL
);
5930 auto Hi
= MIRBuilder
.buildSelect(
5931 HalfTy
, IsZero
, InH
, MIRBuilder
.buildSelect(HalfTy
, IsShort
, HiS
, HiL
));
5933 ResultRegs
[0] = Lo
.getReg(0);
5934 ResultRegs
[1] = Hi
.getReg(0);
5937 case TargetOpcode::G_LSHR
:
5938 case TargetOpcode::G_ASHR
: {
5939 // Short: ShAmt < NewBitSize
5940 auto HiS
= MIRBuilder
.buildInstr(MI
.getOpcode(), {HalfTy
}, {InH
, Amt
});
5942 auto LoOr
= MIRBuilder
.buildLShr(HalfTy
, InL
, Amt
);
5943 auto HiOr
= MIRBuilder
.buildShl(HalfTy
, InH
, AmtLack
);
5944 auto LoS
= MIRBuilder
.buildOr(HalfTy
, LoOr
, HiOr
);
5946 // Long: ShAmt >= NewBitSize
5947 MachineInstrBuilder HiL
;
5948 if (MI
.getOpcode() == TargetOpcode::G_LSHR
) {
5949 HiL
= MIRBuilder
.buildConstant(HalfTy
, 0); // Hi part is zero.
5951 auto ShiftAmt
= MIRBuilder
.buildConstant(ShiftAmtTy
, NewBitSize
- 1);
5952 HiL
= MIRBuilder
.buildAShr(HalfTy
, InH
, ShiftAmt
); // Sign of Hi part.
5954 auto LoL
= MIRBuilder
.buildInstr(MI
.getOpcode(), {HalfTy
},
5955 {InH
, AmtExcess
}); // Lo from Hi part.
5957 auto Lo
= MIRBuilder
.buildSelect(
5958 HalfTy
, IsZero
, InL
, MIRBuilder
.buildSelect(HalfTy
, IsShort
, LoS
, LoL
));
5960 auto Hi
= MIRBuilder
.buildSelect(HalfTy
, IsShort
, HiS
, HiL
);
5962 ResultRegs
[0] = Lo
.getReg(0);
5963 ResultRegs
[1] = Hi
.getReg(0);
5967 llvm_unreachable("not a shift");
5970 MIRBuilder
.buildMergeLikeInstr(DstReg
, ResultRegs
);
5971 MI
.eraseFromParent();
5975 LegalizerHelper::LegalizeResult
5976 LegalizerHelper::moreElementsVectorPhi(MachineInstr
&MI
, unsigned TypeIdx
,
5978 assert(TypeIdx
== 0 && "Expecting only Idx 0");
5980 Observer
.changingInstr(MI
);
5981 for (unsigned I
= 1, E
= MI
.getNumOperands(); I
!= E
; I
+= 2) {
5982 MachineBasicBlock
&OpMBB
= *MI
.getOperand(I
+ 1).getMBB();
5983 MIRBuilder
.setInsertPt(OpMBB
, OpMBB
.getFirstTerminator());
5984 moreElementsVectorSrc(MI
, MoreTy
, I
);
5987 MachineBasicBlock
&MBB
= *MI
.getParent();
5988 MIRBuilder
.setInsertPt(MBB
, --MBB
.getFirstNonPHI());
5989 moreElementsVectorDst(MI
, MoreTy
, 0);
5990 Observer
.changedInstr(MI
);
5994 MachineInstrBuilder
LegalizerHelper::getNeutralElementForVecReduce(
5995 unsigned Opcode
, MachineIRBuilder
&MIRBuilder
, LLT Ty
) {
5996 assert(Ty
.isScalar() && "Expected scalar type to make neutral element for");
6001 "getNeutralElementForVecReduce called with invalid opcode!");
6002 case TargetOpcode::G_VECREDUCE_ADD
:
6003 case TargetOpcode::G_VECREDUCE_OR
:
6004 case TargetOpcode::G_VECREDUCE_XOR
:
6005 case TargetOpcode::G_VECREDUCE_UMAX
:
6006 return MIRBuilder
.buildConstant(Ty
, 0);
6007 case TargetOpcode::G_VECREDUCE_MUL
:
6008 return MIRBuilder
.buildConstant(Ty
, 1);
6009 case TargetOpcode::G_VECREDUCE_AND
:
6010 case TargetOpcode::G_VECREDUCE_UMIN
:
6011 return MIRBuilder
.buildConstant(
6012 Ty
, APInt::getAllOnes(Ty
.getScalarSizeInBits()));
6013 case TargetOpcode::G_VECREDUCE_SMAX
:
6014 return MIRBuilder
.buildConstant(
6015 Ty
, APInt::getSignedMinValue(Ty
.getSizeInBits()));
6016 case TargetOpcode::G_VECREDUCE_SMIN
:
6017 return MIRBuilder
.buildConstant(
6018 Ty
, APInt::getSignedMaxValue(Ty
.getSizeInBits()));
6019 case TargetOpcode::G_VECREDUCE_FADD
:
6020 return MIRBuilder
.buildFConstant(Ty
, -0.0);
6021 case TargetOpcode::G_VECREDUCE_FMUL
:
6022 return MIRBuilder
.buildFConstant(Ty
, 1.0);
6023 case TargetOpcode::G_VECREDUCE_FMINIMUM
:
6024 case TargetOpcode::G_VECREDUCE_FMAXIMUM
:
6025 assert(false && "getNeutralElementForVecReduce unimplemented for "
6026 "G_VECREDUCE_FMINIMUM and G_VECREDUCE_FMAXIMUM!");
6028 llvm_unreachable("switch expected to return!");
6031 LegalizerHelper::LegalizeResult
6032 LegalizerHelper::moreElementsVector(MachineInstr
&MI
, unsigned TypeIdx
,
6034 unsigned Opc
= MI
.getOpcode();
6036 case TargetOpcode::G_IMPLICIT_DEF
:
6037 case TargetOpcode::G_LOAD
: {
6039 return UnableToLegalize
;
6040 Observer
.changingInstr(MI
);
6041 moreElementsVectorDst(MI
, MoreTy
, 0);
6042 Observer
.changedInstr(MI
);
6045 case TargetOpcode::G_STORE
:
6047 return UnableToLegalize
;
6048 Observer
.changingInstr(MI
);
6049 moreElementsVectorSrc(MI
, MoreTy
, 0);
6050 Observer
.changedInstr(MI
);
6052 case TargetOpcode::G_AND
:
6053 case TargetOpcode::G_OR
:
6054 case TargetOpcode::G_XOR
:
6055 case TargetOpcode::G_ADD
:
6056 case TargetOpcode::G_SUB
:
6057 case TargetOpcode::G_MUL
:
6058 case TargetOpcode::G_FADD
:
6059 case TargetOpcode::G_FSUB
:
6060 case TargetOpcode::G_FMUL
:
6061 case TargetOpcode::G_FDIV
:
6062 case TargetOpcode::G_FCOPYSIGN
:
6063 case TargetOpcode::G_UADDSAT
:
6064 case TargetOpcode::G_USUBSAT
:
6065 case TargetOpcode::G_SADDSAT
:
6066 case TargetOpcode::G_SSUBSAT
:
6067 case TargetOpcode::G_SMIN
:
6068 case TargetOpcode::G_SMAX
:
6069 case TargetOpcode::G_UMIN
:
6070 case TargetOpcode::G_UMAX
:
6071 case TargetOpcode::G_FMINNUM
:
6072 case TargetOpcode::G_FMAXNUM
:
6073 case TargetOpcode::G_FMINNUM_IEEE
:
6074 case TargetOpcode::G_FMAXNUM_IEEE
:
6075 case TargetOpcode::G_FMINIMUM
:
6076 case TargetOpcode::G_FMAXIMUM
:
6077 case TargetOpcode::G_STRICT_FADD
:
6078 case TargetOpcode::G_STRICT_FSUB
:
6079 case TargetOpcode::G_STRICT_FMUL
:
6080 case TargetOpcode::G_SHL
:
6081 case TargetOpcode::G_ASHR
:
6082 case TargetOpcode::G_LSHR
: {
6083 Observer
.changingInstr(MI
);
6084 moreElementsVectorSrc(MI
, MoreTy
, 1);
6085 moreElementsVectorSrc(MI
, MoreTy
, 2);
6086 moreElementsVectorDst(MI
, MoreTy
, 0);
6087 Observer
.changedInstr(MI
);
6090 case TargetOpcode::G_FMA
:
6091 case TargetOpcode::G_STRICT_FMA
:
6092 case TargetOpcode::G_FSHR
:
6093 case TargetOpcode::G_FSHL
: {
6094 Observer
.changingInstr(MI
);
6095 moreElementsVectorSrc(MI
, MoreTy
, 1);
6096 moreElementsVectorSrc(MI
, MoreTy
, 2);
6097 moreElementsVectorSrc(MI
, MoreTy
, 3);
6098 moreElementsVectorDst(MI
, MoreTy
, 0);
6099 Observer
.changedInstr(MI
);
6102 case TargetOpcode::G_EXTRACT_VECTOR_ELT
:
6103 case TargetOpcode::G_EXTRACT
:
6105 return UnableToLegalize
;
6106 Observer
.changingInstr(MI
);
6107 moreElementsVectorSrc(MI
, MoreTy
, 1);
6108 Observer
.changedInstr(MI
);
6110 case TargetOpcode::G_INSERT
:
6111 case TargetOpcode::G_INSERT_VECTOR_ELT
:
6112 case TargetOpcode::G_FREEZE
:
6113 case TargetOpcode::G_FNEG
:
6114 case TargetOpcode::G_FABS
:
6115 case TargetOpcode::G_FSQRT
:
6116 case TargetOpcode::G_FCEIL
:
6117 case TargetOpcode::G_FFLOOR
:
6118 case TargetOpcode::G_FNEARBYINT
:
6119 case TargetOpcode::G_FRINT
:
6120 case TargetOpcode::G_INTRINSIC_ROUND
:
6121 case TargetOpcode::G_INTRINSIC_ROUNDEVEN
:
6122 case TargetOpcode::G_INTRINSIC_TRUNC
:
6123 case TargetOpcode::G_BSWAP
:
6124 case TargetOpcode::G_FCANONICALIZE
:
6125 case TargetOpcode::G_SEXT_INREG
:
6126 case TargetOpcode::G_ABS
:
6128 return UnableToLegalize
;
6129 Observer
.changingInstr(MI
);
6130 moreElementsVectorSrc(MI
, MoreTy
, 1);
6131 moreElementsVectorDst(MI
, MoreTy
, 0);
6132 Observer
.changedInstr(MI
);
6134 case TargetOpcode::G_SELECT
: {
6135 auto [DstReg
, DstTy
, CondReg
, CondTy
] = MI
.getFirst2RegLLTs();
6137 if (!CondTy
.isScalar() ||
6138 DstTy
.getElementCount() != MoreTy
.getElementCount())
6139 return UnableToLegalize
;
6141 // This is turning a scalar select of vectors into a vector
6142 // select. Broadcast the select condition.
6143 auto ShufSplat
= MIRBuilder
.buildShuffleSplat(MoreTy
, CondReg
);
6144 Observer
.changingInstr(MI
);
6145 MI
.getOperand(1).setReg(ShufSplat
.getReg(0));
6146 Observer
.changedInstr(MI
);
6150 if (CondTy
.isVector())
6151 return UnableToLegalize
;
6153 Observer
.changingInstr(MI
);
6154 moreElementsVectorSrc(MI
, MoreTy
, 2);
6155 moreElementsVectorSrc(MI
, MoreTy
, 3);
6156 moreElementsVectorDst(MI
, MoreTy
, 0);
6157 Observer
.changedInstr(MI
);
6160 case TargetOpcode::G_UNMERGE_VALUES
:
6161 return UnableToLegalize
;
6162 case TargetOpcode::G_PHI
:
6163 return moreElementsVectorPhi(MI
, TypeIdx
, MoreTy
);
6164 case TargetOpcode::G_SHUFFLE_VECTOR
:
6165 return moreElementsVectorShuffle(MI
, TypeIdx
, MoreTy
);
6166 case TargetOpcode::G_BUILD_VECTOR
: {
6167 SmallVector
<SrcOp
, 8> Elts
;
6168 for (auto Op
: MI
.uses()) {
6169 Elts
.push_back(Op
.getReg());
6172 for (unsigned i
= Elts
.size(); i
< MoreTy
.getNumElements(); ++i
) {
6173 Elts
.push_back(MIRBuilder
.buildUndef(MoreTy
.getScalarType()));
6176 MIRBuilder
.buildDeleteTrailingVectorElements(
6177 MI
.getOperand(0).getReg(), MIRBuilder
.buildInstr(Opc
, {MoreTy
}, Elts
));
6178 MI
.eraseFromParent();
6181 case TargetOpcode::G_SEXT
:
6182 case TargetOpcode::G_ZEXT
:
6183 case TargetOpcode::G_ANYEXT
:
6184 case TargetOpcode::G_TRUNC
:
6185 case TargetOpcode::G_FPTRUNC
:
6186 case TargetOpcode::G_FPEXT
:
6187 case TargetOpcode::G_FPTOSI
:
6188 case TargetOpcode::G_FPTOUI
:
6189 case TargetOpcode::G_FPTOSI_SAT
:
6190 case TargetOpcode::G_FPTOUI_SAT
:
6191 case TargetOpcode::G_SITOFP
:
6192 case TargetOpcode::G_UITOFP
: {
6193 Observer
.changingInstr(MI
);
6198 SrcExtTy
= LLT::fixed_vector(
6199 MoreTy
.getNumElements(),
6200 MRI
.getType(MI
.getOperand(1).getReg()).getElementType());
6202 DstExtTy
= LLT::fixed_vector(
6203 MoreTy
.getNumElements(),
6204 MRI
.getType(MI
.getOperand(0).getReg()).getElementType());
6207 moreElementsVectorSrc(MI
, SrcExtTy
, 1);
6208 moreElementsVectorDst(MI
, DstExtTy
, 0);
6209 Observer
.changedInstr(MI
);
6212 case TargetOpcode::G_ICMP
:
6213 case TargetOpcode::G_FCMP
: {
6215 return UnableToLegalize
;
6217 Observer
.changingInstr(MI
);
6218 moreElementsVectorSrc(MI
, MoreTy
, 2);
6219 moreElementsVectorSrc(MI
, MoreTy
, 3);
6220 LLT CondTy
= LLT::fixed_vector(
6221 MoreTy
.getNumElements(),
6222 MRI
.getType(MI
.getOperand(0).getReg()).getElementType());
6223 moreElementsVectorDst(MI
, CondTy
, 0);
6224 Observer
.changedInstr(MI
);
6227 case TargetOpcode::G_BITCAST
: {
6229 return UnableToLegalize
;
6231 LLT SrcTy
= MRI
.getType(MI
.getOperand(1).getReg());
6232 LLT DstTy
= MRI
.getType(MI
.getOperand(0).getReg());
6234 unsigned coefficient
= SrcTy
.getNumElements() * MoreTy
.getNumElements();
6235 if (coefficient
% DstTy
.getNumElements() != 0)
6236 return UnableToLegalize
;
6238 coefficient
= coefficient
/ DstTy
.getNumElements();
6240 LLT NewTy
= SrcTy
.changeElementCount(
6241 ElementCount::get(coefficient
, MoreTy
.isScalable()));
6242 Observer
.changingInstr(MI
);
6243 moreElementsVectorSrc(MI
, NewTy
, 1);
6244 moreElementsVectorDst(MI
, MoreTy
, 0);
6245 Observer
.changedInstr(MI
);
6248 case TargetOpcode::G_VECREDUCE_FADD
:
6249 case TargetOpcode::G_VECREDUCE_FMUL
:
6250 case TargetOpcode::G_VECREDUCE_ADD
:
6251 case TargetOpcode::G_VECREDUCE_MUL
:
6252 case TargetOpcode::G_VECREDUCE_AND
:
6253 case TargetOpcode::G_VECREDUCE_OR
:
6254 case TargetOpcode::G_VECREDUCE_XOR
:
6255 case TargetOpcode::G_VECREDUCE_SMAX
:
6256 case TargetOpcode::G_VECREDUCE_SMIN
:
6257 case TargetOpcode::G_VECREDUCE_UMAX
:
6258 case TargetOpcode::G_VECREDUCE_UMIN
: {
6259 LLT OrigTy
= MRI
.getType(MI
.getOperand(1).getReg());
6260 MachineOperand
&MO
= MI
.getOperand(1);
6261 auto NewVec
= MIRBuilder
.buildPadVectorWithUndefElements(MoreTy
, MO
);
6262 auto NeutralElement
= getNeutralElementForVecReduce(
6263 MI
.getOpcode(), MIRBuilder
, MoreTy
.getElementType());
6265 LLT
IdxTy(TLI
.getVectorIdxTy(MIRBuilder
.getDataLayout()));
6266 for (size_t i
= OrigTy
.getNumElements(), e
= MoreTy
.getNumElements();
6268 auto Idx
= MIRBuilder
.buildConstant(IdxTy
, i
);
6269 NewVec
= MIRBuilder
.buildInsertVectorElement(MoreTy
, NewVec
,
6270 NeutralElement
, Idx
);
6273 Observer
.changingInstr(MI
);
6274 MO
.setReg(NewVec
.getReg(0));
6275 Observer
.changedInstr(MI
);
6280 return UnableToLegalize
;
6284 LegalizerHelper::LegalizeResult
6285 LegalizerHelper::equalizeVectorShuffleLengths(MachineInstr
&MI
) {
6286 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
6287 ArrayRef
<int> Mask
= MI
.getOperand(3).getShuffleMask();
6288 unsigned MaskNumElts
= Mask
.size();
6289 unsigned SrcNumElts
= SrcTy
.getNumElements();
6290 LLT DestEltTy
= DstTy
.getElementType();
6292 if (MaskNumElts
== SrcNumElts
)
6295 if (MaskNumElts
< SrcNumElts
) {
6296 // Extend mask to match new destination vector size with
6298 SmallVector
<int, 16> NewMask(SrcNumElts
, -1);
6299 llvm::copy(Mask
, NewMask
.begin());
6301 moreElementsVectorDst(MI
, SrcTy
, 0);
6302 MIRBuilder
.setInstrAndDebugLoc(MI
);
6303 MIRBuilder
.buildShuffleVector(MI
.getOperand(0).getReg(),
6304 MI
.getOperand(1).getReg(),
6305 MI
.getOperand(2).getReg(), NewMask
);
6306 MI
.eraseFromParent();
6311 unsigned PaddedMaskNumElts
= alignTo(MaskNumElts
, SrcNumElts
);
6312 unsigned NumConcat
= PaddedMaskNumElts
/ SrcNumElts
;
6313 LLT PaddedTy
= LLT::fixed_vector(PaddedMaskNumElts
, DestEltTy
);
6315 // Create new source vectors by concatenating the initial
6316 // source vectors with undefined vectors of the same size.
6317 auto Undef
= MIRBuilder
.buildUndef(SrcTy
);
6318 SmallVector
<Register
, 8> MOps1(NumConcat
, Undef
.getReg(0));
6319 SmallVector
<Register
, 8> MOps2(NumConcat
, Undef
.getReg(0));
6320 MOps1
[0] = MI
.getOperand(1).getReg();
6321 MOps2
[0] = MI
.getOperand(2).getReg();
6323 auto Src1
= MIRBuilder
.buildConcatVectors(PaddedTy
, MOps1
);
6324 auto Src2
= MIRBuilder
.buildConcatVectors(PaddedTy
, MOps2
);
6326 // Readjust mask for new input vector length.
6327 SmallVector
<int, 8> MappedOps(PaddedMaskNumElts
, -1);
6328 for (unsigned I
= 0; I
!= MaskNumElts
; ++I
) {
6330 if (Idx
>= static_cast<int>(SrcNumElts
))
6331 Idx
+= PaddedMaskNumElts
- SrcNumElts
;
6335 // If we got more elements than required, extract subvector.
6336 if (MaskNumElts
!= PaddedMaskNumElts
) {
6338 MIRBuilder
.buildShuffleVector(PaddedTy
, Src1
, Src2
, MappedOps
);
6340 SmallVector
<Register
, 16> Elts(MaskNumElts
);
6341 for (unsigned I
= 0; I
< MaskNumElts
; ++I
) {
6343 MIRBuilder
.buildExtractVectorElementConstant(DestEltTy
, Shuffle
, I
)
6346 MIRBuilder
.buildBuildVector(DstReg
, Elts
);
6348 MIRBuilder
.buildShuffleVector(DstReg
, Src1
, Src2
, MappedOps
);
6351 MI
.eraseFromParent();
6352 return LegalizerHelper::LegalizeResult::Legalized
;
6355 LegalizerHelper::LegalizeResult
6356 LegalizerHelper::moreElementsVectorShuffle(MachineInstr
&MI
,
6357 unsigned int TypeIdx
, LLT MoreTy
) {
6358 auto [DstTy
, Src1Ty
, Src2Ty
] = MI
.getFirst3LLTs();
6359 ArrayRef
<int> Mask
= MI
.getOperand(3).getShuffleMask();
6360 unsigned NumElts
= DstTy
.getNumElements();
6361 unsigned WidenNumElts
= MoreTy
.getNumElements();
6363 if (DstTy
.isVector() && Src1Ty
.isVector() &&
6364 DstTy
.getNumElements() != Src1Ty
.getNumElements()) {
6365 return equalizeVectorShuffleLengths(MI
);
6369 return UnableToLegalize
;
6371 // Expect a canonicalized shuffle.
6372 if (DstTy
!= Src1Ty
|| DstTy
!= Src2Ty
)
6373 return UnableToLegalize
;
6375 moreElementsVectorSrc(MI
, MoreTy
, 1);
6376 moreElementsVectorSrc(MI
, MoreTy
, 2);
6378 // Adjust mask based on new input vector length.
6379 SmallVector
<int, 16> NewMask(WidenNumElts
, -1);
6380 for (unsigned I
= 0; I
!= NumElts
; ++I
) {
6382 if (Idx
< static_cast<int>(NumElts
))
6385 NewMask
[I
] = Idx
- NumElts
+ WidenNumElts
;
6387 moreElementsVectorDst(MI
, MoreTy
, 0);
6388 MIRBuilder
.setInstrAndDebugLoc(MI
);
6389 MIRBuilder
.buildShuffleVector(MI
.getOperand(0).getReg(),
6390 MI
.getOperand(1).getReg(),
6391 MI
.getOperand(2).getReg(), NewMask
);
6392 MI
.eraseFromParent();
6396 void LegalizerHelper::multiplyRegisters(SmallVectorImpl
<Register
> &DstRegs
,
6397 ArrayRef
<Register
> Src1Regs
,
6398 ArrayRef
<Register
> Src2Regs
,
6400 MachineIRBuilder
&B
= MIRBuilder
;
6401 unsigned SrcParts
= Src1Regs
.size();
6402 unsigned DstParts
= DstRegs
.size();
6404 unsigned DstIdx
= 0; // Low bits of the result.
6405 Register FactorSum
=
6406 B
.buildMul(NarrowTy
, Src1Regs
[DstIdx
], Src2Regs
[DstIdx
]).getReg(0);
6407 DstRegs
[DstIdx
] = FactorSum
;
6409 unsigned CarrySumPrevDstIdx
;
6410 SmallVector
<Register
, 4> Factors
;
6412 for (DstIdx
= 1; DstIdx
< DstParts
; DstIdx
++) {
6413 // Collect low parts of muls for DstIdx.
6414 for (unsigned i
= DstIdx
+ 1 < SrcParts
? 0 : DstIdx
- SrcParts
+ 1;
6415 i
<= std::min(DstIdx
, SrcParts
- 1); ++i
) {
6416 MachineInstrBuilder Mul
=
6417 B
.buildMul(NarrowTy
, Src1Regs
[DstIdx
- i
], Src2Regs
[i
]);
6418 Factors
.push_back(Mul
.getReg(0));
6420 // Collect high parts of muls from previous DstIdx.
6421 for (unsigned i
= DstIdx
< SrcParts
? 0 : DstIdx
- SrcParts
;
6422 i
<= std::min(DstIdx
- 1, SrcParts
- 1); ++i
) {
6423 MachineInstrBuilder Umulh
=
6424 B
.buildUMulH(NarrowTy
, Src1Regs
[DstIdx
- 1 - i
], Src2Regs
[i
]);
6425 Factors
.push_back(Umulh
.getReg(0));
6427 // Add CarrySum from additions calculated for previous DstIdx.
6429 Factors
.push_back(CarrySumPrevDstIdx
);
6433 // Add all factors and accumulate all carries into CarrySum.
6434 if (DstIdx
!= DstParts
- 1) {
6435 MachineInstrBuilder Uaddo
=
6436 B
.buildUAddo(NarrowTy
, LLT::scalar(1), Factors
[0], Factors
[1]);
6437 FactorSum
= Uaddo
.getReg(0);
6438 CarrySum
= B
.buildZExt(NarrowTy
, Uaddo
.getReg(1)).getReg(0);
6439 for (unsigned i
= 2; i
< Factors
.size(); ++i
) {
6440 MachineInstrBuilder Uaddo
=
6441 B
.buildUAddo(NarrowTy
, LLT::scalar(1), FactorSum
, Factors
[i
]);
6442 FactorSum
= Uaddo
.getReg(0);
6443 MachineInstrBuilder Carry
= B
.buildZExt(NarrowTy
, Uaddo
.getReg(1));
6444 CarrySum
= B
.buildAdd(NarrowTy
, CarrySum
, Carry
).getReg(0);
6447 // Since value for the next index is not calculated, neither is CarrySum.
6448 FactorSum
= B
.buildAdd(NarrowTy
, Factors
[0], Factors
[1]).getReg(0);
6449 for (unsigned i
= 2; i
< Factors
.size(); ++i
)
6450 FactorSum
= B
.buildAdd(NarrowTy
, FactorSum
, Factors
[i
]).getReg(0);
6453 CarrySumPrevDstIdx
= CarrySum
;
6454 DstRegs
[DstIdx
] = FactorSum
;
6459 LegalizerHelper::LegalizeResult
6460 LegalizerHelper::narrowScalarAddSub(MachineInstr
&MI
, unsigned TypeIdx
,
6463 return UnableToLegalize
;
6465 Register DstReg
= MI
.getOperand(0).getReg();
6466 LLT DstType
= MRI
.getType(DstReg
);
6467 // FIXME: add support for vector types
6468 if (DstType
.isVector())
6469 return UnableToLegalize
;
6471 unsigned Opcode
= MI
.getOpcode();
6472 unsigned OpO
, OpE
, OpF
;
6474 case TargetOpcode::G_SADDO
:
6475 case TargetOpcode::G_SADDE
:
6476 case TargetOpcode::G_UADDO
:
6477 case TargetOpcode::G_UADDE
:
6478 case TargetOpcode::G_ADD
:
6479 OpO
= TargetOpcode::G_UADDO
;
6480 OpE
= TargetOpcode::G_UADDE
;
6481 OpF
= TargetOpcode::G_UADDE
;
6482 if (Opcode
== TargetOpcode::G_SADDO
|| Opcode
== TargetOpcode::G_SADDE
)
6483 OpF
= TargetOpcode::G_SADDE
;
6485 case TargetOpcode::G_SSUBO
:
6486 case TargetOpcode::G_SSUBE
:
6487 case TargetOpcode::G_USUBO
:
6488 case TargetOpcode::G_USUBE
:
6489 case TargetOpcode::G_SUB
:
6490 OpO
= TargetOpcode::G_USUBO
;
6491 OpE
= TargetOpcode::G_USUBE
;
6492 OpF
= TargetOpcode::G_USUBE
;
6493 if (Opcode
== TargetOpcode::G_SSUBO
|| Opcode
== TargetOpcode::G_SSUBE
)
6494 OpF
= TargetOpcode::G_SSUBE
;
6497 llvm_unreachable("Unexpected add/sub opcode!");
6500 // 1 for a plain add/sub, 2 if this is an operation with a carry-out.
6501 unsigned NumDefs
= MI
.getNumExplicitDefs();
6502 Register Src1
= MI
.getOperand(NumDefs
).getReg();
6503 Register Src2
= MI
.getOperand(NumDefs
+ 1).getReg();
6504 Register CarryDst
, CarryIn
;
6506 CarryDst
= MI
.getOperand(1).getReg();
6507 if (MI
.getNumOperands() == NumDefs
+ 3)
6508 CarryIn
= MI
.getOperand(NumDefs
+ 2).getReg();
6510 LLT RegTy
= MRI
.getType(MI
.getOperand(0).getReg());
6511 LLT LeftoverTy
, DummyTy
;
6512 SmallVector
<Register
, 2> Src1Regs
, Src2Regs
, Src1Left
, Src2Left
, DstRegs
;
6513 extractParts(Src1
, RegTy
, NarrowTy
, LeftoverTy
, Src1Regs
, Src1Left
,
6515 extractParts(Src2
, RegTy
, NarrowTy
, DummyTy
, Src2Regs
, Src2Left
, MIRBuilder
,
6518 int NarrowParts
= Src1Regs
.size();
6519 Src1Regs
.append(Src1Left
);
6520 Src2Regs
.append(Src2Left
);
6521 DstRegs
.reserve(Src1Regs
.size());
6523 for (int i
= 0, e
= Src1Regs
.size(); i
!= e
; ++i
) {
6525 MRI
.createGenericVirtualRegister(MRI
.getType(Src1Regs
[i
]));
6527 // Forward the final carry-out to the destination register
6528 if (i
== e
- 1 && CarryDst
)
6529 CarryOut
= CarryDst
;
6531 CarryOut
= MRI
.createGenericVirtualRegister(LLT::scalar(1));
6534 MIRBuilder
.buildInstr(OpO
, {DstReg
, CarryOut
},
6535 {Src1Regs
[i
], Src2Regs
[i
]});
6536 } else if (i
== e
- 1) {
6537 MIRBuilder
.buildInstr(OpF
, {DstReg
, CarryOut
},
6538 {Src1Regs
[i
], Src2Regs
[i
], CarryIn
});
6540 MIRBuilder
.buildInstr(OpE
, {DstReg
, CarryOut
},
6541 {Src1Regs
[i
], Src2Regs
[i
], CarryIn
});
6544 DstRegs
.push_back(DstReg
);
6547 insertParts(MI
.getOperand(0).getReg(), RegTy
, NarrowTy
,
6548 ArrayRef(DstRegs
).take_front(NarrowParts
), LeftoverTy
,
6549 ArrayRef(DstRegs
).drop_front(NarrowParts
));
6551 MI
.eraseFromParent();
6555 LegalizerHelper::LegalizeResult
6556 LegalizerHelper::narrowScalarMul(MachineInstr
&MI
, LLT NarrowTy
) {
6557 auto [DstReg
, Src1
, Src2
] = MI
.getFirst3Regs();
6559 LLT Ty
= MRI
.getType(DstReg
);
6561 return UnableToLegalize
;
6563 unsigned Size
= Ty
.getSizeInBits();
6564 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
6565 if (Size
% NarrowSize
!= 0)
6566 return UnableToLegalize
;
6568 unsigned NumParts
= Size
/ NarrowSize
;
6569 bool IsMulHigh
= MI
.getOpcode() == TargetOpcode::G_UMULH
;
6570 unsigned DstTmpParts
= NumParts
* (IsMulHigh
? 2 : 1);
6572 SmallVector
<Register
, 2> Src1Parts
, Src2Parts
;
6573 SmallVector
<Register
, 2> DstTmpRegs(DstTmpParts
);
6574 extractParts(Src1
, NarrowTy
, NumParts
, Src1Parts
, MIRBuilder
, MRI
);
6575 extractParts(Src2
, NarrowTy
, NumParts
, Src2Parts
, MIRBuilder
, MRI
);
6576 multiplyRegisters(DstTmpRegs
, Src1Parts
, Src2Parts
, NarrowTy
);
6578 // Take only high half of registers if this is high mul.
6579 ArrayRef
<Register
> DstRegs(&DstTmpRegs
[DstTmpParts
- NumParts
], NumParts
);
6580 MIRBuilder
.buildMergeLikeInstr(DstReg
, DstRegs
);
6581 MI
.eraseFromParent();
6585 LegalizerHelper::LegalizeResult
6586 LegalizerHelper::narrowScalarFPTOI(MachineInstr
&MI
, unsigned TypeIdx
,
6589 return UnableToLegalize
;
6591 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_FPTOSI
;
6593 Register Src
= MI
.getOperand(1).getReg();
6594 LLT SrcTy
= MRI
.getType(Src
);
6596 // If all finite floats fit into the narrowed integer type, we can just swap
6597 // out the result type. This is practically only useful for conversions from
6598 // half to at least 16-bits, so just handle the one case.
6599 if (SrcTy
.getScalarType() != LLT::scalar(16) ||
6600 NarrowTy
.getScalarSizeInBits() < (IsSigned
? 17u : 16u))
6601 return UnableToLegalize
;
6603 Observer
.changingInstr(MI
);
6604 narrowScalarDst(MI
, NarrowTy
, 0,
6605 IsSigned
? TargetOpcode::G_SEXT
: TargetOpcode::G_ZEXT
);
6606 Observer
.changedInstr(MI
);
6610 LegalizerHelper::LegalizeResult
6611 LegalizerHelper::narrowScalarExtract(MachineInstr
&MI
, unsigned TypeIdx
,
6614 return UnableToLegalize
;
6616 uint64_t NarrowSize
= NarrowTy
.getSizeInBits();
6618 int64_t SizeOp1
= MRI
.getType(MI
.getOperand(1).getReg()).getSizeInBits();
6619 // FIXME: add support for when SizeOp1 isn't an exact multiple of
6621 if (SizeOp1
% NarrowSize
!= 0)
6622 return UnableToLegalize
;
6623 int NumParts
= SizeOp1
/ NarrowSize
;
6625 SmallVector
<Register
, 2> SrcRegs
, DstRegs
;
6626 SmallVector
<uint64_t, 2> Indexes
;
6627 extractParts(MI
.getOperand(1).getReg(), NarrowTy
, NumParts
, SrcRegs
,
6630 Register OpReg
= MI
.getOperand(0).getReg();
6631 uint64_t OpStart
= MI
.getOperand(2).getImm();
6632 uint64_t OpSize
= MRI
.getType(OpReg
).getSizeInBits();
6633 for (int i
= 0; i
< NumParts
; ++i
) {
6634 unsigned SrcStart
= i
* NarrowSize
;
6636 if (SrcStart
+ NarrowSize
<= OpStart
|| SrcStart
>= OpStart
+ OpSize
) {
6637 // No part of the extract uses this subregister, ignore it.
6639 } else if (SrcStart
== OpStart
&& NarrowTy
== MRI
.getType(OpReg
)) {
6640 // The entire subregister is extracted, forward the value.
6641 DstRegs
.push_back(SrcRegs
[i
]);
6645 // OpSegStart is where this destination segment would start in OpReg if it
6646 // extended infinitely in both directions.
6647 int64_t ExtractOffset
;
6649 if (OpStart
< SrcStart
) {
6651 SegSize
= std::min(NarrowSize
, OpStart
+ OpSize
- SrcStart
);
6653 ExtractOffset
= OpStart
- SrcStart
;
6654 SegSize
= std::min(SrcStart
+ NarrowSize
- OpStart
, OpSize
);
6657 Register SegReg
= SrcRegs
[i
];
6658 if (ExtractOffset
!= 0 || SegSize
!= NarrowSize
) {
6659 // A genuine extract is needed.
6660 SegReg
= MRI
.createGenericVirtualRegister(LLT::scalar(SegSize
));
6661 MIRBuilder
.buildExtract(SegReg
, SrcRegs
[i
], ExtractOffset
);
6664 DstRegs
.push_back(SegReg
);
6667 Register DstReg
= MI
.getOperand(0).getReg();
6668 if (MRI
.getType(DstReg
).isVector())
6669 MIRBuilder
.buildBuildVector(DstReg
, DstRegs
);
6670 else if (DstRegs
.size() > 1)
6671 MIRBuilder
.buildMergeLikeInstr(DstReg
, DstRegs
);
6673 MIRBuilder
.buildCopy(DstReg
, DstRegs
[0]);
6674 MI
.eraseFromParent();
6678 LegalizerHelper::LegalizeResult
6679 LegalizerHelper::narrowScalarInsert(MachineInstr
&MI
, unsigned TypeIdx
,
6681 // FIXME: Don't know how to handle secondary types yet.
6683 return UnableToLegalize
;
6685 SmallVector
<Register
, 2> SrcRegs
, LeftoverRegs
, DstRegs
;
6686 SmallVector
<uint64_t, 2> Indexes
;
6687 LLT RegTy
= MRI
.getType(MI
.getOperand(0).getReg());
6689 extractParts(MI
.getOperand(1).getReg(), RegTy
, NarrowTy
, LeftoverTy
, SrcRegs
,
6690 LeftoverRegs
, MIRBuilder
, MRI
);
6692 SrcRegs
.append(LeftoverRegs
);
6694 uint64_t NarrowSize
= NarrowTy
.getSizeInBits();
6695 Register OpReg
= MI
.getOperand(2).getReg();
6696 uint64_t OpStart
= MI
.getOperand(3).getImm();
6697 uint64_t OpSize
= MRI
.getType(OpReg
).getSizeInBits();
6698 for (int I
= 0, E
= SrcRegs
.size(); I
!= E
; ++I
) {
6699 unsigned DstStart
= I
* NarrowSize
;
6701 if (DstStart
== OpStart
&& NarrowTy
== MRI
.getType(OpReg
)) {
6702 // The entire subregister is defined by this insert, forward the new
6704 DstRegs
.push_back(OpReg
);
6708 Register SrcReg
= SrcRegs
[I
];
6709 if (MRI
.getType(SrcRegs
[I
]) == LeftoverTy
) {
6710 // The leftover reg is smaller than NarrowTy, so we need to extend it.
6711 SrcReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
6712 MIRBuilder
.buildAnyExt(SrcReg
, SrcRegs
[I
]);
6715 if (DstStart
+ NarrowSize
<= OpStart
|| DstStart
>= OpStart
+ OpSize
) {
6716 // No part of the insert affects this subregister, forward the original.
6717 DstRegs
.push_back(SrcReg
);
6721 // OpSegStart is where this destination segment would start in OpReg if it
6722 // extended infinitely in both directions.
6723 int64_t ExtractOffset
, InsertOffset
;
6725 if (OpStart
< DstStart
) {
6727 ExtractOffset
= DstStart
- OpStart
;
6728 SegSize
= std::min(NarrowSize
, OpStart
+ OpSize
- DstStart
);
6730 InsertOffset
= OpStart
- DstStart
;
6733 std::min(NarrowSize
- InsertOffset
, OpStart
+ OpSize
- DstStart
);
6736 Register SegReg
= OpReg
;
6737 if (ExtractOffset
!= 0 || SegSize
!= OpSize
) {
6738 // A genuine extract is needed.
6739 SegReg
= MRI
.createGenericVirtualRegister(LLT::scalar(SegSize
));
6740 MIRBuilder
.buildExtract(SegReg
, OpReg
, ExtractOffset
);
6743 Register DstReg
= MRI
.createGenericVirtualRegister(NarrowTy
);
6744 MIRBuilder
.buildInsert(DstReg
, SrcReg
, SegReg
, InsertOffset
);
6745 DstRegs
.push_back(DstReg
);
6748 uint64_t WideSize
= DstRegs
.size() * NarrowSize
;
6749 Register DstReg
= MI
.getOperand(0).getReg();
6750 if (WideSize
> RegTy
.getSizeInBits()) {
6751 Register MergeReg
= MRI
.createGenericVirtualRegister(LLT::scalar(WideSize
));
6752 MIRBuilder
.buildMergeLikeInstr(MergeReg
, DstRegs
);
6753 MIRBuilder
.buildTrunc(DstReg
, MergeReg
);
6755 MIRBuilder
.buildMergeLikeInstr(DstReg
, DstRegs
);
6757 MI
.eraseFromParent();
6761 LegalizerHelper::LegalizeResult
6762 LegalizerHelper::narrowScalarBasic(MachineInstr
&MI
, unsigned TypeIdx
,
6764 Register DstReg
= MI
.getOperand(0).getReg();
6765 LLT DstTy
= MRI
.getType(DstReg
);
6767 assert(MI
.getNumOperands() == 3 && TypeIdx
== 0);
6769 SmallVector
<Register
, 4> DstRegs
, DstLeftoverRegs
;
6770 SmallVector
<Register
, 4> Src0Regs
, Src0LeftoverRegs
;
6771 SmallVector
<Register
, 4> Src1Regs
, Src1LeftoverRegs
;
6773 if (!extractParts(MI
.getOperand(1).getReg(), DstTy
, NarrowTy
, LeftoverTy
,
6774 Src0Regs
, Src0LeftoverRegs
, MIRBuilder
, MRI
))
6775 return UnableToLegalize
;
6778 if (!extractParts(MI
.getOperand(2).getReg(), DstTy
, NarrowTy
, Unused
,
6779 Src1Regs
, Src1LeftoverRegs
, MIRBuilder
, MRI
))
6780 llvm_unreachable("inconsistent extractParts result");
6782 for (unsigned I
= 0, E
= Src1Regs
.size(); I
!= E
; ++I
) {
6783 auto Inst
= MIRBuilder
.buildInstr(MI
.getOpcode(), {NarrowTy
},
6784 {Src0Regs
[I
], Src1Regs
[I
]});
6785 DstRegs
.push_back(Inst
.getReg(0));
6788 for (unsigned I
= 0, E
= Src1LeftoverRegs
.size(); I
!= E
; ++I
) {
6789 auto Inst
= MIRBuilder
.buildInstr(
6791 {LeftoverTy
}, {Src0LeftoverRegs
[I
], Src1LeftoverRegs
[I
]});
6792 DstLeftoverRegs
.push_back(Inst
.getReg(0));
6795 insertParts(DstReg
, DstTy
, NarrowTy
, DstRegs
,
6796 LeftoverTy
, DstLeftoverRegs
);
6798 MI
.eraseFromParent();
6802 LegalizerHelper::LegalizeResult
6803 LegalizerHelper::narrowScalarExt(MachineInstr
&MI
, unsigned TypeIdx
,
6806 return UnableToLegalize
;
6808 auto [DstReg
, SrcReg
] = MI
.getFirst2Regs();
6810 LLT DstTy
= MRI
.getType(DstReg
);
6811 if (DstTy
.isVector())
6812 return UnableToLegalize
;
6814 SmallVector
<Register
, 8> Parts
;
6815 LLT GCDTy
= extractGCDType(Parts
, DstTy
, NarrowTy
, SrcReg
);
6816 LLT LCMTy
= buildLCMMergePieces(DstTy
, NarrowTy
, GCDTy
, Parts
, MI
.getOpcode());
6817 buildWidenedRemergeToDst(DstReg
, LCMTy
, Parts
);
6819 MI
.eraseFromParent();
6823 LegalizerHelper::LegalizeResult
6824 LegalizerHelper::narrowScalarSelect(MachineInstr
&MI
, unsigned TypeIdx
,
6827 return UnableToLegalize
;
6829 Register CondReg
= MI
.getOperand(1).getReg();
6830 LLT CondTy
= MRI
.getType(CondReg
);
6831 if (CondTy
.isVector()) // TODO: Handle vselect
6832 return UnableToLegalize
;
6834 Register DstReg
= MI
.getOperand(0).getReg();
6835 LLT DstTy
= MRI
.getType(DstReg
);
6837 SmallVector
<Register
, 4> DstRegs
, DstLeftoverRegs
;
6838 SmallVector
<Register
, 4> Src1Regs
, Src1LeftoverRegs
;
6839 SmallVector
<Register
, 4> Src2Regs
, Src2LeftoverRegs
;
6841 if (!extractParts(MI
.getOperand(2).getReg(), DstTy
, NarrowTy
, LeftoverTy
,
6842 Src1Regs
, Src1LeftoverRegs
, MIRBuilder
, MRI
))
6843 return UnableToLegalize
;
6846 if (!extractParts(MI
.getOperand(3).getReg(), DstTy
, NarrowTy
, Unused
,
6847 Src2Regs
, Src2LeftoverRegs
, MIRBuilder
, MRI
))
6848 llvm_unreachable("inconsistent extractParts result");
6850 for (unsigned I
= 0, E
= Src1Regs
.size(); I
!= E
; ++I
) {
6851 auto Select
= MIRBuilder
.buildSelect(NarrowTy
,
6852 CondReg
, Src1Regs
[I
], Src2Regs
[I
]);
6853 DstRegs
.push_back(Select
.getReg(0));
6856 for (unsigned I
= 0, E
= Src1LeftoverRegs
.size(); I
!= E
; ++I
) {
6857 auto Select
= MIRBuilder
.buildSelect(
6858 LeftoverTy
, CondReg
, Src1LeftoverRegs
[I
], Src2LeftoverRegs
[I
]);
6859 DstLeftoverRegs
.push_back(Select
.getReg(0));
6862 insertParts(DstReg
, DstTy
, NarrowTy
, DstRegs
,
6863 LeftoverTy
, DstLeftoverRegs
);
6865 MI
.eraseFromParent();
6869 LegalizerHelper::LegalizeResult
6870 LegalizerHelper::narrowScalarCTLZ(MachineInstr
&MI
, unsigned TypeIdx
,
6873 return UnableToLegalize
;
6875 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
6876 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
6878 if (SrcTy
.isScalar() && SrcTy
.getSizeInBits() == 2 * NarrowSize
) {
6879 const bool IsUndef
= MI
.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF
;
6881 MachineIRBuilder
&B
= MIRBuilder
;
6882 auto UnmergeSrc
= B
.buildUnmerge(NarrowTy
, SrcReg
);
6883 // ctlz(Hi:Lo) -> Hi == 0 ? (NarrowSize + ctlz(Lo)) : ctlz(Hi)
6884 auto C_0
= B
.buildConstant(NarrowTy
, 0);
6885 auto HiIsZero
= B
.buildICmp(CmpInst::ICMP_EQ
, LLT::scalar(1),
6886 UnmergeSrc
.getReg(1), C_0
);
6887 auto LoCTLZ
= IsUndef
?
6888 B
.buildCTLZ_ZERO_UNDEF(DstTy
, UnmergeSrc
.getReg(0)) :
6889 B
.buildCTLZ(DstTy
, UnmergeSrc
.getReg(0));
6890 auto C_NarrowSize
= B
.buildConstant(DstTy
, NarrowSize
);
6891 auto HiIsZeroCTLZ
= B
.buildAdd(DstTy
, LoCTLZ
, C_NarrowSize
);
6892 auto HiCTLZ
= B
.buildCTLZ_ZERO_UNDEF(DstTy
, UnmergeSrc
.getReg(1));
6893 B
.buildSelect(DstReg
, HiIsZero
, HiIsZeroCTLZ
, HiCTLZ
);
6895 MI
.eraseFromParent();
6899 return UnableToLegalize
;
6902 LegalizerHelper::LegalizeResult
6903 LegalizerHelper::narrowScalarCTTZ(MachineInstr
&MI
, unsigned TypeIdx
,
6906 return UnableToLegalize
;
6908 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
6909 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
6911 if (SrcTy
.isScalar() && SrcTy
.getSizeInBits() == 2 * NarrowSize
) {
6912 const bool IsUndef
= MI
.getOpcode() == TargetOpcode::G_CTTZ_ZERO_UNDEF
;
6914 MachineIRBuilder
&B
= MIRBuilder
;
6915 auto UnmergeSrc
= B
.buildUnmerge(NarrowTy
, SrcReg
);
6916 // cttz(Hi:Lo) -> Lo == 0 ? (cttz(Hi) + NarrowSize) : cttz(Lo)
6917 auto C_0
= B
.buildConstant(NarrowTy
, 0);
6918 auto LoIsZero
= B
.buildICmp(CmpInst::ICMP_EQ
, LLT::scalar(1),
6919 UnmergeSrc
.getReg(0), C_0
);
6920 auto HiCTTZ
= IsUndef
?
6921 B
.buildCTTZ_ZERO_UNDEF(DstTy
, UnmergeSrc
.getReg(1)) :
6922 B
.buildCTTZ(DstTy
, UnmergeSrc
.getReg(1));
6923 auto C_NarrowSize
= B
.buildConstant(DstTy
, NarrowSize
);
6924 auto LoIsZeroCTTZ
= B
.buildAdd(DstTy
, HiCTTZ
, C_NarrowSize
);
6925 auto LoCTTZ
= B
.buildCTTZ_ZERO_UNDEF(DstTy
, UnmergeSrc
.getReg(0));
6926 B
.buildSelect(DstReg
, LoIsZero
, LoIsZeroCTTZ
, LoCTTZ
);
6928 MI
.eraseFromParent();
6932 return UnableToLegalize
;
6935 LegalizerHelper::LegalizeResult
6936 LegalizerHelper::narrowScalarCTPOP(MachineInstr
&MI
, unsigned TypeIdx
,
6939 return UnableToLegalize
;
6941 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
6942 unsigned NarrowSize
= NarrowTy
.getSizeInBits();
6944 if (SrcTy
.isScalar() && SrcTy
.getSizeInBits() == 2 * NarrowSize
) {
6945 auto UnmergeSrc
= MIRBuilder
.buildUnmerge(NarrowTy
, MI
.getOperand(1));
6947 auto LoCTPOP
= MIRBuilder
.buildCTPOP(DstTy
, UnmergeSrc
.getReg(0));
6948 auto HiCTPOP
= MIRBuilder
.buildCTPOP(DstTy
, UnmergeSrc
.getReg(1));
6949 MIRBuilder
.buildAdd(DstReg
, HiCTPOP
, LoCTPOP
);
6951 MI
.eraseFromParent();
6955 return UnableToLegalize
;
6958 LegalizerHelper::LegalizeResult
6959 LegalizerHelper::narrowScalarFLDEXP(MachineInstr
&MI
, unsigned TypeIdx
,
6962 return UnableToLegalize
;
6964 MachineIRBuilder
&B
= MIRBuilder
;
6965 Register ExpReg
= MI
.getOperand(2).getReg();
6966 LLT ExpTy
= MRI
.getType(ExpReg
);
6968 unsigned ClampSize
= NarrowTy
.getScalarSizeInBits();
6970 // Clamp the exponent to the range of the target type.
6971 auto MinExp
= B
.buildConstant(ExpTy
, minIntN(ClampSize
));
6972 auto ClampMin
= B
.buildSMax(ExpTy
, ExpReg
, MinExp
);
6973 auto MaxExp
= B
.buildConstant(ExpTy
, maxIntN(ClampSize
));
6974 auto Clamp
= B
.buildSMin(ExpTy
, ClampMin
, MaxExp
);
6976 auto Trunc
= B
.buildTrunc(NarrowTy
, Clamp
);
6977 Observer
.changingInstr(MI
);
6978 MI
.getOperand(2).setReg(Trunc
.getReg(0));
6979 Observer
.changedInstr(MI
);
6983 LegalizerHelper::LegalizeResult
6984 LegalizerHelper::lowerBitCount(MachineInstr
&MI
) {
6985 unsigned Opc
= MI
.getOpcode();
6986 const auto &TII
= MIRBuilder
.getTII();
6987 auto isSupported
= [this](const LegalityQuery
&Q
) {
6988 auto QAction
= LI
.getAction(Q
).Action
;
6989 return QAction
== Legal
|| QAction
== Libcall
|| QAction
== Custom
;
6993 return UnableToLegalize
;
6994 case TargetOpcode::G_CTLZ_ZERO_UNDEF
: {
6995 // This trivially expands to CTLZ.
6996 Observer
.changingInstr(MI
);
6997 MI
.setDesc(TII
.get(TargetOpcode::G_CTLZ
));
6998 Observer
.changedInstr(MI
);
7001 case TargetOpcode::G_CTLZ
: {
7002 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
7003 unsigned Len
= SrcTy
.getSizeInBits();
7005 if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF
, {DstTy
, SrcTy
}})) {
7006 // If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
7007 auto CtlzZU
= MIRBuilder
.buildCTLZ_ZERO_UNDEF(DstTy
, SrcReg
);
7008 auto ZeroSrc
= MIRBuilder
.buildConstant(SrcTy
, 0);
7009 auto ICmp
= MIRBuilder
.buildICmp(
7010 CmpInst::ICMP_EQ
, SrcTy
.changeElementSize(1), SrcReg
, ZeroSrc
);
7011 auto LenConst
= MIRBuilder
.buildConstant(DstTy
, Len
);
7012 MIRBuilder
.buildSelect(DstReg
, ICmp
, LenConst
, CtlzZU
);
7013 MI
.eraseFromParent();
7016 // for now, we do this:
7017 // NewLen = NextPowerOf2(Len);
7018 // x = x | (x >> 1);
7019 // x = x | (x >> 2);
7021 // x = x | (x >>16);
7022 // x = x | (x >>32); // for 64-bit input
7024 // return Len - popcount(x);
7026 // Ref: "Hacker's Delight" by Henry Warren
7027 Register Op
= SrcReg
;
7028 unsigned NewLen
= PowerOf2Ceil(Len
);
7029 for (unsigned i
= 0; (1U << i
) <= (NewLen
/ 2); ++i
) {
7030 auto MIBShiftAmt
= MIRBuilder
.buildConstant(SrcTy
, 1ULL << i
);
7031 auto MIBOp
= MIRBuilder
.buildOr(
7032 SrcTy
, Op
, MIRBuilder
.buildLShr(SrcTy
, Op
, MIBShiftAmt
));
7033 Op
= MIBOp
.getReg(0);
7035 auto MIBPop
= MIRBuilder
.buildCTPOP(DstTy
, Op
);
7036 MIRBuilder
.buildSub(MI
.getOperand(0), MIRBuilder
.buildConstant(DstTy
, Len
),
7038 MI
.eraseFromParent();
7041 case TargetOpcode::G_CTTZ_ZERO_UNDEF
: {
7042 // This trivially expands to CTTZ.
7043 Observer
.changingInstr(MI
);
7044 MI
.setDesc(TII
.get(TargetOpcode::G_CTTZ
));
7045 Observer
.changedInstr(MI
);
7048 case TargetOpcode::G_CTTZ
: {
7049 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
7051 unsigned Len
= SrcTy
.getSizeInBits();
7052 if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF
, {DstTy
, SrcTy
}})) {
7053 // If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
7055 auto CttzZU
= MIRBuilder
.buildCTTZ_ZERO_UNDEF(DstTy
, SrcReg
);
7056 auto Zero
= MIRBuilder
.buildConstant(SrcTy
, 0);
7057 auto ICmp
= MIRBuilder
.buildICmp(
7058 CmpInst::ICMP_EQ
, DstTy
.changeElementSize(1), SrcReg
, Zero
);
7059 auto LenConst
= MIRBuilder
.buildConstant(DstTy
, Len
);
7060 MIRBuilder
.buildSelect(DstReg
, ICmp
, LenConst
, CttzZU
);
7061 MI
.eraseFromParent();
7064 // for now, we use: { return popcount(~x & (x - 1)); }
7065 // unless the target has ctlz but not ctpop, in which case we use:
7066 // { return 32 - nlz(~x & (x-1)); }
7067 // Ref: "Hacker's Delight" by Henry Warren
7068 auto MIBCstNeg1
= MIRBuilder
.buildConstant(SrcTy
, -1);
7069 auto MIBNot
= MIRBuilder
.buildXor(SrcTy
, SrcReg
, MIBCstNeg1
);
7070 auto MIBTmp
= MIRBuilder
.buildAnd(
7071 SrcTy
, MIBNot
, MIRBuilder
.buildAdd(SrcTy
, SrcReg
, MIBCstNeg1
));
7072 if (!isSupported({TargetOpcode::G_CTPOP
, {SrcTy
, SrcTy
}}) &&
7073 isSupported({TargetOpcode::G_CTLZ
, {SrcTy
, SrcTy
}})) {
7074 auto MIBCstLen
= MIRBuilder
.buildConstant(SrcTy
, Len
);
7075 MIRBuilder
.buildSub(MI
.getOperand(0), MIBCstLen
,
7076 MIRBuilder
.buildCTLZ(SrcTy
, MIBTmp
));
7077 MI
.eraseFromParent();
7080 Observer
.changingInstr(MI
);
7081 MI
.setDesc(TII
.get(TargetOpcode::G_CTPOP
));
7082 MI
.getOperand(1).setReg(MIBTmp
.getReg(0));
7083 Observer
.changedInstr(MI
);
7086 case TargetOpcode::G_CTPOP
: {
7087 Register SrcReg
= MI
.getOperand(1).getReg();
7088 LLT Ty
= MRI
.getType(SrcReg
);
7089 unsigned Size
= Ty
.getSizeInBits();
7090 MachineIRBuilder
&B
= MIRBuilder
;
7092 // Count set bits in blocks of 2 bits. Default approach would be
7093 // B2Count = { val & 0x55555555 } + { (val >> 1) & 0x55555555 }
7094 // We use following formula instead:
7095 // B2Count = val - { (val >> 1) & 0x55555555 }
7096 // since it gives same result in blocks of 2 with one instruction less.
7097 auto C_1
= B
.buildConstant(Ty
, 1);
7098 auto B2Set1LoTo1Hi
= B
.buildLShr(Ty
, SrcReg
, C_1
);
7099 APInt B2Mask1HiTo0
= APInt::getSplat(Size
, APInt(8, 0x55));
7100 auto C_B2Mask1HiTo0
= B
.buildConstant(Ty
, B2Mask1HiTo0
);
7101 auto B2Count1Hi
= B
.buildAnd(Ty
, B2Set1LoTo1Hi
, C_B2Mask1HiTo0
);
7102 auto B2Count
= B
.buildSub(Ty
, SrcReg
, B2Count1Hi
);
7104 // In order to get count in blocks of 4 add values from adjacent block of 2.
7105 // B4Count = { B2Count & 0x33333333 } + { (B2Count >> 2) & 0x33333333 }
7106 auto C_2
= B
.buildConstant(Ty
, 2);
7107 auto B4Set2LoTo2Hi
= B
.buildLShr(Ty
, B2Count
, C_2
);
7108 APInt B4Mask2HiTo0
= APInt::getSplat(Size
, APInt(8, 0x33));
7109 auto C_B4Mask2HiTo0
= B
.buildConstant(Ty
, B4Mask2HiTo0
);
7110 auto B4HiB2Count
= B
.buildAnd(Ty
, B4Set2LoTo2Hi
, C_B4Mask2HiTo0
);
7111 auto B4LoB2Count
= B
.buildAnd(Ty
, B2Count
, C_B4Mask2HiTo0
);
7112 auto B4Count
= B
.buildAdd(Ty
, B4HiB2Count
, B4LoB2Count
);
7114 // For count in blocks of 8 bits we don't have to mask high 4 bits before
7115 // addition since count value sits in range {0,...,8} and 4 bits are enough
7116 // to hold such binary values. After addition high 4 bits still hold count
7117 // of set bits in high 4 bit block, set them to zero and get 8 bit result.
7118 // B8Count = { B4Count + (B4Count >> 4) } & 0x0F0F0F0F
7119 auto C_4
= B
.buildConstant(Ty
, 4);
7120 auto B8HiB4Count
= B
.buildLShr(Ty
, B4Count
, C_4
);
7121 auto B8CountDirty4Hi
= B
.buildAdd(Ty
, B8HiB4Count
, B4Count
);
7122 APInt B8Mask4HiTo0
= APInt::getSplat(Size
, APInt(8, 0x0F));
7123 auto C_B8Mask4HiTo0
= B
.buildConstant(Ty
, B8Mask4HiTo0
);
7124 auto B8Count
= B
.buildAnd(Ty
, B8CountDirty4Hi
, C_B8Mask4HiTo0
);
7126 assert(Size
<=128 && "Scalar size is too large for CTPOP lower algorithm");
7127 // 8 bits can hold CTPOP result of 128 bit int or smaller. Mul with this
7128 // bitmask will set 8 msb in ResTmp to sum of all B8Counts in 8 bit blocks.
7129 auto MulMask
= B
.buildConstant(Ty
, APInt::getSplat(Size
, APInt(8, 0x01)));
7131 // Shift count result from 8 high bits to low bits.
7132 auto C_SizeM8
= B
.buildConstant(Ty
, Size
- 8);
7134 auto IsMulSupported
= [this](const LLT Ty
) {
7135 auto Action
= LI
.getAction({TargetOpcode::G_MUL
, {Ty
}}).Action
;
7136 return Action
== Legal
|| Action
== WidenScalar
|| Action
== Custom
;
7138 if (IsMulSupported(Ty
)) {
7139 auto ResTmp
= B
.buildMul(Ty
, B8Count
, MulMask
);
7140 B
.buildLShr(MI
.getOperand(0).getReg(), ResTmp
, C_SizeM8
);
7142 auto ResTmp
= B8Count
;
7143 for (unsigned Shift
= 8; Shift
< Size
; Shift
*= 2) {
7144 auto ShiftC
= B
.buildConstant(Ty
, Shift
);
7145 auto Shl
= B
.buildShl(Ty
, ResTmp
, ShiftC
);
7146 ResTmp
= B
.buildAdd(Ty
, ResTmp
, Shl
);
7148 B
.buildLShr(MI
.getOperand(0).getReg(), ResTmp
, C_SizeM8
);
7150 MI
.eraseFromParent();
7156 // Check that (every element of) Reg is undef or not an exact multiple of BW.
7157 static bool isNonZeroModBitWidthOrUndef(const MachineRegisterInfo
&MRI
,
7158 Register Reg
, unsigned BW
) {
7159 return matchUnaryPredicate(
7161 [=](const Constant
*C
) {
7162 // Null constant here means an undef.
7163 const ConstantInt
*CI
= dyn_cast_or_null
<ConstantInt
>(C
);
7164 return !CI
|| CI
->getValue().urem(BW
) != 0;
7166 /*AllowUndefs*/ true);
7169 LegalizerHelper::LegalizeResult
7170 LegalizerHelper::lowerFunnelShiftWithInverse(MachineInstr
&MI
) {
7171 auto [Dst
, X
, Y
, Z
] = MI
.getFirst4Regs();
7172 LLT Ty
= MRI
.getType(Dst
);
7173 LLT ShTy
= MRI
.getType(Z
);
7175 unsigned BW
= Ty
.getScalarSizeInBits();
7177 if (!isPowerOf2_32(BW
))
7178 return UnableToLegalize
;
7180 const bool IsFSHL
= MI
.getOpcode() == TargetOpcode::G_FSHL
;
7181 unsigned RevOpcode
= IsFSHL
? TargetOpcode::G_FSHR
: TargetOpcode::G_FSHL
;
7183 if (isNonZeroModBitWidthOrUndef(MRI
, Z
, BW
)) {
7184 // fshl X, Y, Z -> fshr X, Y, -Z
7185 // fshr X, Y, Z -> fshl X, Y, -Z
7186 auto Zero
= MIRBuilder
.buildConstant(ShTy
, 0);
7187 Z
= MIRBuilder
.buildSub(Ty
, Zero
, Z
).getReg(0);
7189 // fshl X, Y, Z -> fshr (srl X, 1), (fshr X, Y, 1), ~Z
7190 // fshr X, Y, Z -> fshl (fshl X, Y, 1), (shl Y, 1), ~Z
7191 auto One
= MIRBuilder
.buildConstant(ShTy
, 1);
7193 Y
= MIRBuilder
.buildInstr(RevOpcode
, {Ty
}, {X
, Y
, One
}).getReg(0);
7194 X
= MIRBuilder
.buildLShr(Ty
, X
, One
).getReg(0);
7196 X
= MIRBuilder
.buildInstr(RevOpcode
, {Ty
}, {X
, Y
, One
}).getReg(0);
7197 Y
= MIRBuilder
.buildShl(Ty
, Y
, One
).getReg(0);
7200 Z
= MIRBuilder
.buildNot(ShTy
, Z
).getReg(0);
7203 MIRBuilder
.buildInstr(RevOpcode
, {Dst
}, {X
, Y
, Z
});
7204 MI
.eraseFromParent();
7208 LegalizerHelper::LegalizeResult
7209 LegalizerHelper::lowerFunnelShiftAsShifts(MachineInstr
&MI
) {
7210 auto [Dst
, X
, Y
, Z
] = MI
.getFirst4Regs();
7211 LLT Ty
= MRI
.getType(Dst
);
7212 LLT ShTy
= MRI
.getType(Z
);
7214 const unsigned BW
= Ty
.getScalarSizeInBits();
7215 const bool IsFSHL
= MI
.getOpcode() == TargetOpcode::G_FSHL
;
7218 Register ShAmt
, InvShAmt
;
7220 // FIXME: Emit optimized urem by constant instead of letting it expand later.
7221 if (isNonZeroModBitWidthOrUndef(MRI
, Z
, BW
)) {
7222 // fshl: X << C | Y >> (BW - C)
7223 // fshr: X << (BW - C) | Y >> C
7224 // where C = Z % BW is not zero
7225 auto BitWidthC
= MIRBuilder
.buildConstant(ShTy
, BW
);
7226 ShAmt
= MIRBuilder
.buildURem(ShTy
, Z
, BitWidthC
).getReg(0);
7227 InvShAmt
= MIRBuilder
.buildSub(ShTy
, BitWidthC
, ShAmt
).getReg(0);
7228 ShX
= MIRBuilder
.buildShl(Ty
, X
, IsFSHL
? ShAmt
: InvShAmt
).getReg(0);
7229 ShY
= MIRBuilder
.buildLShr(Ty
, Y
, IsFSHL
? InvShAmt
: ShAmt
).getReg(0);
7231 // fshl: X << (Z % BW) | Y >> 1 >> (BW - 1 - (Z % BW))
7232 // fshr: X << 1 << (BW - 1 - (Z % BW)) | Y >> (Z % BW)
7233 auto Mask
= MIRBuilder
.buildConstant(ShTy
, BW
- 1);
7234 if (isPowerOf2_32(BW
)) {
7235 // Z % BW -> Z & (BW - 1)
7236 ShAmt
= MIRBuilder
.buildAnd(ShTy
, Z
, Mask
).getReg(0);
7237 // (BW - 1) - (Z % BW) -> ~Z & (BW - 1)
7238 auto NotZ
= MIRBuilder
.buildNot(ShTy
, Z
);
7239 InvShAmt
= MIRBuilder
.buildAnd(ShTy
, NotZ
, Mask
).getReg(0);
7241 auto BitWidthC
= MIRBuilder
.buildConstant(ShTy
, BW
);
7242 ShAmt
= MIRBuilder
.buildURem(ShTy
, Z
, BitWidthC
).getReg(0);
7243 InvShAmt
= MIRBuilder
.buildSub(ShTy
, Mask
, ShAmt
).getReg(0);
7246 auto One
= MIRBuilder
.buildConstant(ShTy
, 1);
7248 ShX
= MIRBuilder
.buildShl(Ty
, X
, ShAmt
).getReg(0);
7249 auto ShY1
= MIRBuilder
.buildLShr(Ty
, Y
, One
);
7250 ShY
= MIRBuilder
.buildLShr(Ty
, ShY1
, InvShAmt
).getReg(0);
7252 auto ShX1
= MIRBuilder
.buildShl(Ty
, X
, One
);
7253 ShX
= MIRBuilder
.buildShl(Ty
, ShX1
, InvShAmt
).getReg(0);
7254 ShY
= MIRBuilder
.buildLShr(Ty
, Y
, ShAmt
).getReg(0);
7258 MIRBuilder
.buildOr(Dst
, ShX
, ShY
);
7259 MI
.eraseFromParent();
7263 LegalizerHelper::LegalizeResult
7264 LegalizerHelper::lowerFunnelShift(MachineInstr
&MI
) {
7265 // These operations approximately do the following (while avoiding undefined
7267 // G_FSHL: (X << (Z % BW)) | (Y >> (BW - (Z % BW)))
7268 // G_FSHR: (X << (BW - (Z % BW))) | (Y >> (Z % BW))
7269 Register Dst
= MI
.getOperand(0).getReg();
7270 LLT Ty
= MRI
.getType(Dst
);
7271 LLT ShTy
= MRI
.getType(MI
.getOperand(3).getReg());
7273 bool IsFSHL
= MI
.getOpcode() == TargetOpcode::G_FSHL
;
7274 unsigned RevOpcode
= IsFSHL
? TargetOpcode::G_FSHR
: TargetOpcode::G_FSHL
;
7276 // TODO: Use smarter heuristic that accounts for vector legalization.
7277 if (LI
.getAction({RevOpcode
, {Ty
, ShTy
}}).Action
== Lower
)
7278 return lowerFunnelShiftAsShifts(MI
);
7280 // This only works for powers of 2, fallback to shifts if it fails.
7281 LegalizerHelper::LegalizeResult Result
= lowerFunnelShiftWithInverse(MI
);
7282 if (Result
== UnableToLegalize
)
7283 return lowerFunnelShiftAsShifts(MI
);
7287 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerEXT(MachineInstr
&MI
) {
7288 auto [Dst
, Src
] = MI
.getFirst2Regs();
7289 LLT DstTy
= MRI
.getType(Dst
);
7290 LLT SrcTy
= MRI
.getType(Src
);
7292 uint32_t DstTySize
= DstTy
.getSizeInBits();
7293 uint32_t DstTyScalarSize
= DstTy
.getScalarSizeInBits();
7294 uint32_t SrcTyScalarSize
= SrcTy
.getScalarSizeInBits();
7296 if (!isPowerOf2_32(DstTySize
) || !isPowerOf2_32(DstTyScalarSize
) ||
7297 !isPowerOf2_32(SrcTyScalarSize
))
7298 return UnableToLegalize
;
7300 // The step between extend is too large, split it by creating an intermediate
7301 // extend instruction
7302 if (SrcTyScalarSize
* 2 < DstTyScalarSize
) {
7303 LLT MidTy
= SrcTy
.changeElementSize(SrcTyScalarSize
* 2);
7304 // If the destination type is illegal, split it into multiple statements
7305 // zext x -> zext(merge(zext(unmerge), zext(unmerge)))
7306 auto NewExt
= MIRBuilder
.buildInstr(MI
.getOpcode(), {MidTy
}, {Src
});
7307 // Unmerge the vector
7308 LLT EltTy
= MidTy
.changeElementCount(
7309 MidTy
.getElementCount().divideCoefficientBy(2));
7310 auto UnmergeSrc
= MIRBuilder
.buildUnmerge(EltTy
, NewExt
);
7313 LLT ZExtResTy
= DstTy
.changeElementCount(
7314 DstTy
.getElementCount().divideCoefficientBy(2));
7315 auto ZExtRes1
= MIRBuilder
.buildInstr(MI
.getOpcode(), {ZExtResTy
},
7316 {UnmergeSrc
.getReg(0)});
7317 auto ZExtRes2
= MIRBuilder
.buildInstr(MI
.getOpcode(), {ZExtResTy
},
7318 {UnmergeSrc
.getReg(1)});
7320 // Merge the ending vectors
7321 MIRBuilder
.buildMergeLikeInstr(Dst
, {ZExtRes1
, ZExtRes2
});
7323 MI
.eraseFromParent();
7326 return UnableToLegalize
;
7329 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerTRUNC(MachineInstr
&MI
) {
7330 // MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
7331 MachineRegisterInfo
&MRI
= *MIRBuilder
.getMRI();
7332 // Similar to how operand splitting is done in SelectiondDAG, we can handle
7333 // %res(v8s8) = G_TRUNC %in(v8s32) by generating:
7334 // %inlo(<4x s32>), %inhi(<4 x s32>) = G_UNMERGE %in(<8 x s32>)
7335 // %lo16(<4 x s16>) = G_TRUNC %inlo
7336 // %hi16(<4 x s16>) = G_TRUNC %inhi
7337 // %in16(<8 x s16>) = G_CONCAT_VECTORS %lo16, %hi16
7338 // %res(<8 x s8>) = G_TRUNC %in16
7340 assert(MI
.getOpcode() == TargetOpcode::G_TRUNC
);
7342 Register DstReg
= MI
.getOperand(0).getReg();
7343 Register SrcReg
= MI
.getOperand(1).getReg();
7344 LLT DstTy
= MRI
.getType(DstReg
);
7345 LLT SrcTy
= MRI
.getType(SrcReg
);
7347 if (DstTy
.isVector() && isPowerOf2_32(DstTy
.getNumElements()) &&
7348 isPowerOf2_32(DstTy
.getScalarSizeInBits()) &&
7349 isPowerOf2_32(SrcTy
.getNumElements()) &&
7350 isPowerOf2_32(SrcTy
.getScalarSizeInBits())) {
7351 // Split input type.
7352 LLT SplitSrcTy
= SrcTy
.changeElementCount(
7353 SrcTy
.getElementCount().divideCoefficientBy(2));
7355 // First, split the source into two smaller vectors.
7356 SmallVector
<Register
, 2> SplitSrcs
;
7357 extractParts(SrcReg
, SplitSrcTy
, 2, SplitSrcs
, MIRBuilder
, MRI
);
7359 // Truncate the splits into intermediate narrower elements.
7361 if (DstTy
.getScalarSizeInBits() * 2 < SrcTy
.getScalarSizeInBits())
7362 InterTy
= SplitSrcTy
.changeElementSize(DstTy
.getScalarSizeInBits() * 2);
7364 InterTy
= SplitSrcTy
.changeElementSize(DstTy
.getScalarSizeInBits());
7365 for (unsigned I
= 0; I
< SplitSrcs
.size(); ++I
) {
7366 SplitSrcs
[I
] = MIRBuilder
.buildTrunc(InterTy
, SplitSrcs
[I
]).getReg(0);
7369 // Combine the new truncates into one vector
7370 auto Merge
= MIRBuilder
.buildMergeLikeInstr(
7371 DstTy
.changeElementSize(InterTy
.getScalarSizeInBits()), SplitSrcs
);
7373 // Truncate the new vector to the final result type
7374 if (DstTy
.getScalarSizeInBits() * 2 < SrcTy
.getScalarSizeInBits())
7375 MIRBuilder
.buildTrunc(MI
.getOperand(0).getReg(), Merge
.getReg(0));
7377 MIRBuilder
.buildCopy(MI
.getOperand(0).getReg(), Merge
.getReg(0));
7379 MI
.eraseFromParent();
7383 return UnableToLegalize
;
7386 LegalizerHelper::LegalizeResult
7387 LegalizerHelper::lowerRotateWithReverseRotate(MachineInstr
&MI
) {
7388 auto [Dst
, DstTy
, Src
, SrcTy
, Amt
, AmtTy
] = MI
.getFirst3RegLLTs();
7389 auto Zero
= MIRBuilder
.buildConstant(AmtTy
, 0);
7390 bool IsLeft
= MI
.getOpcode() == TargetOpcode::G_ROTL
;
7391 unsigned RevRot
= IsLeft
? TargetOpcode::G_ROTR
: TargetOpcode::G_ROTL
;
7392 auto Neg
= MIRBuilder
.buildSub(AmtTy
, Zero
, Amt
);
7393 MIRBuilder
.buildInstr(RevRot
, {Dst
}, {Src
, Neg
});
7394 MI
.eraseFromParent();
7398 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerRotate(MachineInstr
&MI
) {
7399 auto [Dst
, DstTy
, Src
, SrcTy
, Amt
, AmtTy
] = MI
.getFirst3RegLLTs();
7401 unsigned EltSizeInBits
= DstTy
.getScalarSizeInBits();
7402 bool IsLeft
= MI
.getOpcode() == TargetOpcode::G_ROTL
;
7404 MIRBuilder
.setInstrAndDebugLoc(MI
);
7406 // If a rotate in the other direction is supported, use it.
7407 unsigned RevRot
= IsLeft
? TargetOpcode::G_ROTR
: TargetOpcode::G_ROTL
;
7408 if (LI
.isLegalOrCustom({RevRot
, {DstTy
, SrcTy
}}) &&
7409 isPowerOf2_32(EltSizeInBits
))
7410 return lowerRotateWithReverseRotate(MI
);
7412 // If a funnel shift is supported, use it.
7413 unsigned FShOpc
= IsLeft
? TargetOpcode::G_FSHL
: TargetOpcode::G_FSHR
;
7414 unsigned RevFsh
= !IsLeft
? TargetOpcode::G_FSHL
: TargetOpcode::G_FSHR
;
7415 bool IsFShLegal
= false;
7416 if ((IsFShLegal
= LI
.isLegalOrCustom({FShOpc
, {DstTy
, AmtTy
}})) ||
7417 LI
.isLegalOrCustom({RevFsh
, {DstTy
, AmtTy
}})) {
7418 auto buildFunnelShift
= [&](unsigned Opc
, Register R1
, Register R2
,
7420 MIRBuilder
.buildInstr(Opc
, {R1
}, {R2
, R2
, R3
});
7421 MI
.eraseFromParent();
7424 // If a funnel shift in the other direction is supported, use it.
7426 return buildFunnelShift(FShOpc
, Dst
, Src
, Amt
);
7427 } else if (isPowerOf2_32(EltSizeInBits
)) {
7428 Amt
= MIRBuilder
.buildNeg(DstTy
, Amt
).getReg(0);
7429 return buildFunnelShift(RevFsh
, Dst
, Src
, Amt
);
7433 auto Zero
= MIRBuilder
.buildConstant(AmtTy
, 0);
7434 unsigned ShOpc
= IsLeft
? TargetOpcode::G_SHL
: TargetOpcode::G_LSHR
;
7435 unsigned RevShiftOpc
= IsLeft
? TargetOpcode::G_LSHR
: TargetOpcode::G_SHL
;
7436 auto BitWidthMinusOneC
= MIRBuilder
.buildConstant(AmtTy
, EltSizeInBits
- 1);
7438 Register RevShiftVal
;
7439 if (isPowerOf2_32(EltSizeInBits
)) {
7440 // (rotl x, c) -> x << (c & (w - 1)) | x >> (-c & (w - 1))
7441 // (rotr x, c) -> x >> (c & (w - 1)) | x << (-c & (w - 1))
7442 auto NegAmt
= MIRBuilder
.buildSub(AmtTy
, Zero
, Amt
);
7443 auto ShAmt
= MIRBuilder
.buildAnd(AmtTy
, Amt
, BitWidthMinusOneC
);
7444 ShVal
= MIRBuilder
.buildInstr(ShOpc
, {DstTy
}, {Src
, ShAmt
}).getReg(0);
7445 auto RevAmt
= MIRBuilder
.buildAnd(AmtTy
, NegAmt
, BitWidthMinusOneC
);
7447 MIRBuilder
.buildInstr(RevShiftOpc
, {DstTy
}, {Src
, RevAmt
}).getReg(0);
7449 // (rotl x, c) -> x << (c % w) | x >> 1 >> (w - 1 - (c % w))
7450 // (rotr x, c) -> x >> (c % w) | x << 1 << (w - 1 - (c % w))
7451 auto BitWidthC
= MIRBuilder
.buildConstant(AmtTy
, EltSizeInBits
);
7452 auto ShAmt
= MIRBuilder
.buildURem(AmtTy
, Amt
, BitWidthC
);
7453 ShVal
= MIRBuilder
.buildInstr(ShOpc
, {DstTy
}, {Src
, ShAmt
}).getReg(0);
7454 auto RevAmt
= MIRBuilder
.buildSub(AmtTy
, BitWidthMinusOneC
, ShAmt
);
7455 auto One
= MIRBuilder
.buildConstant(AmtTy
, 1);
7456 auto Inner
= MIRBuilder
.buildInstr(RevShiftOpc
, {DstTy
}, {Src
, One
});
7458 MIRBuilder
.buildInstr(RevShiftOpc
, {DstTy
}, {Inner
, RevAmt
}).getReg(0);
7460 MIRBuilder
.buildOr(Dst
, ShVal
, RevShiftVal
);
7461 MI
.eraseFromParent();
7465 // Expand s32 = G_UITOFP s64 using bit operations to an IEEE float
7467 LegalizerHelper::LegalizeResult
7468 LegalizerHelper::lowerU64ToF32BitOps(MachineInstr
&MI
) {
7469 auto [Dst
, Src
] = MI
.getFirst2Regs();
7470 const LLT S64
= LLT::scalar(64);
7471 const LLT S32
= LLT::scalar(32);
7472 const LLT S1
= LLT::scalar(1);
7474 assert(MRI
.getType(Src
) == S64
&& MRI
.getType(Dst
) == S32
);
7476 // unsigned cul2f(ulong u) {
7477 // uint lz = clz(u);
7478 // uint e = (u != 0) ? 127U + 63U - lz : 0;
7479 // u = (u << lz) & 0x7fffffffffffffffUL;
7480 // ulong t = u & 0xffffffffffUL;
7481 // uint v = (e << 23) | (uint)(u >> 40);
7482 // uint r = t > 0x8000000000UL ? 1U : (t == 0x8000000000UL ? v & 1U : 0U);
7483 // return as_float(v + r);
7486 auto Zero32
= MIRBuilder
.buildConstant(S32
, 0);
7487 auto Zero64
= MIRBuilder
.buildConstant(S64
, 0);
7489 auto LZ
= MIRBuilder
.buildCTLZ_ZERO_UNDEF(S32
, Src
);
7491 auto K
= MIRBuilder
.buildConstant(S32
, 127U + 63U);
7492 auto Sub
= MIRBuilder
.buildSub(S32
, K
, LZ
);
7494 auto NotZero
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, S1
, Src
, Zero64
);
7495 auto E
= MIRBuilder
.buildSelect(S32
, NotZero
, Sub
, Zero32
);
7497 auto Mask0
= MIRBuilder
.buildConstant(S64
, (-1ULL) >> 1);
7498 auto ShlLZ
= MIRBuilder
.buildShl(S64
, Src
, LZ
);
7500 auto U
= MIRBuilder
.buildAnd(S64
, ShlLZ
, Mask0
);
7502 auto Mask1
= MIRBuilder
.buildConstant(S64
, 0xffffffffffULL
);
7503 auto T
= MIRBuilder
.buildAnd(S64
, U
, Mask1
);
7505 auto UShl
= MIRBuilder
.buildLShr(S64
, U
, MIRBuilder
.buildConstant(S64
, 40));
7506 auto ShlE
= MIRBuilder
.buildShl(S32
, E
, MIRBuilder
.buildConstant(S32
, 23));
7507 auto V
= MIRBuilder
.buildOr(S32
, ShlE
, MIRBuilder
.buildTrunc(S32
, UShl
));
7509 auto C
= MIRBuilder
.buildConstant(S64
, 0x8000000000ULL
);
7510 auto RCmp
= MIRBuilder
.buildICmp(CmpInst::ICMP_UGT
, S1
, T
, C
);
7511 auto TCmp
= MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, S1
, T
, C
);
7512 auto One
= MIRBuilder
.buildConstant(S32
, 1);
7514 auto VTrunc1
= MIRBuilder
.buildAnd(S32
, V
, One
);
7515 auto Select0
= MIRBuilder
.buildSelect(S32
, TCmp
, VTrunc1
, Zero32
);
7516 auto R
= MIRBuilder
.buildSelect(S32
, RCmp
, One
, Select0
);
7517 MIRBuilder
.buildAdd(Dst
, V
, R
);
7519 MI
.eraseFromParent();
7523 // Expand s32 = G_UITOFP s64 to an IEEE float representation using bit
7524 // operations and G_SITOFP
7525 LegalizerHelper::LegalizeResult
7526 LegalizerHelper::lowerU64ToF32WithSITOFP(MachineInstr
&MI
) {
7527 auto [Dst
, Src
] = MI
.getFirst2Regs();
7528 const LLT S64
= LLT::scalar(64);
7529 const LLT S32
= LLT::scalar(32);
7530 const LLT S1
= LLT::scalar(1);
7532 assert(MRI
.getType(Src
) == S64
&& MRI
.getType(Dst
) == S32
);
7534 // For i64 < INT_MAX we simply reuse SITOFP.
7535 // Otherwise, divide i64 by 2, round result by ORing with the lowest bit
7536 // saved before division, convert to float by SITOFP, multiply the result
7538 auto One
= MIRBuilder
.buildConstant(S64
, 1);
7539 auto Zero
= MIRBuilder
.buildConstant(S64
, 0);
7540 // Result if Src < INT_MAX
7541 auto SmallResult
= MIRBuilder
.buildSITOFP(S32
, Src
);
7542 // Result if Src >= INT_MAX
7543 auto Halved
= MIRBuilder
.buildLShr(S64
, Src
, One
);
7544 auto LowerBit
= MIRBuilder
.buildAnd(S64
, Src
, One
);
7545 auto RoundedHalved
= MIRBuilder
.buildOr(S64
, Halved
, LowerBit
);
7546 auto HalvedFP
= MIRBuilder
.buildSITOFP(S32
, RoundedHalved
);
7547 auto LargeResult
= MIRBuilder
.buildFAdd(S32
, HalvedFP
, HalvedFP
);
7548 // Check if the original value is larger than INT_MAX by comparing with
7549 // zero to pick one of the two conversions.
7551 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_SLT
, S1
, Src
, Zero
);
7552 MIRBuilder
.buildSelect(Dst
, IsLarge
, LargeResult
, SmallResult
);
7554 MI
.eraseFromParent();
7558 // Expand s64 = G_UITOFP s64 using bit and float arithmetic operations to an
7559 // IEEE double representation.
7560 LegalizerHelper::LegalizeResult
7561 LegalizerHelper::lowerU64ToF64BitFloatOps(MachineInstr
&MI
) {
7562 auto [Dst
, Src
] = MI
.getFirst2Regs();
7563 const LLT S64
= LLT::scalar(64);
7564 const LLT S32
= LLT::scalar(32);
7566 assert(MRI
.getType(Src
) == S64
&& MRI
.getType(Dst
) == S64
);
7568 // We create double value from 32 bit parts with 32 exponent difference.
7569 // Note that + and - are float operations that adjust the implicit leading
7570 // one, the bases 2^52 and 2^84 are for illustrative purposes.
7572 // X = 2^52 * 1.0...LowBits
7573 // Y = 2^84 * 1.0...HighBits
7574 // Scratch = 2^84 * 1.0...HighBits - 2^84 * 1.0 - 2^52 * 1.0
7575 // = - 2^52 * 1.0...HighBits
7576 // Result = - 2^52 * 1.0...HighBits + 2^52 * 1.0...LowBits
7577 auto TwoP52
= MIRBuilder
.buildConstant(S64
, UINT64_C(0x4330000000000000));
7578 auto TwoP84
= MIRBuilder
.buildConstant(S64
, UINT64_C(0x4530000000000000));
7579 auto TwoP52P84
= llvm::bit_cast
<double>(UINT64_C(0x4530000000100000));
7580 auto TwoP52P84FP
= MIRBuilder
.buildFConstant(S64
, TwoP52P84
);
7581 auto HalfWidth
= MIRBuilder
.buildConstant(S64
, 32);
7583 auto LowBits
= MIRBuilder
.buildTrunc(S32
, Src
);
7584 LowBits
= MIRBuilder
.buildZExt(S64
, LowBits
);
7585 auto LowBitsFP
= MIRBuilder
.buildOr(S64
, TwoP52
, LowBits
);
7586 auto HighBits
= MIRBuilder
.buildLShr(S64
, Src
, HalfWidth
);
7587 auto HighBitsFP
= MIRBuilder
.buildOr(S64
, TwoP84
, HighBits
);
7588 auto Scratch
= MIRBuilder
.buildFSub(S64
, HighBitsFP
, TwoP52P84FP
);
7589 MIRBuilder
.buildFAdd(Dst
, Scratch
, LowBitsFP
);
7591 MI
.eraseFromParent();
7595 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerUITOFP(MachineInstr
&MI
) {
7596 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
7598 if (SrcTy
== LLT::scalar(1)) {
7599 auto True
= MIRBuilder
.buildFConstant(DstTy
, 1.0);
7600 auto False
= MIRBuilder
.buildFConstant(DstTy
, 0.0);
7601 MIRBuilder
.buildSelect(Dst
, Src
, True
, False
);
7602 MI
.eraseFromParent();
7606 if (SrcTy
!= LLT::scalar(64))
7607 return UnableToLegalize
;
7609 if (DstTy
== LLT::scalar(32))
7610 // TODO: SelectionDAG has several alternative expansions to port which may
7611 // be more reasonable depending on the available instructions. We also need
7612 // a more advanced mechanism to choose an optimal version depending on
7613 // target features such as sitofp or CTLZ availability.
7614 return lowerU64ToF32WithSITOFP(MI
);
7616 if (DstTy
== LLT::scalar(64))
7617 return lowerU64ToF64BitFloatOps(MI
);
7619 return UnableToLegalize
;
7622 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerSITOFP(MachineInstr
&MI
) {
7623 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
7625 const LLT S64
= LLT::scalar(64);
7626 const LLT S32
= LLT::scalar(32);
7627 const LLT S1
= LLT::scalar(1);
7630 auto True
= MIRBuilder
.buildFConstant(DstTy
, -1.0);
7631 auto False
= MIRBuilder
.buildFConstant(DstTy
, 0.0);
7632 MIRBuilder
.buildSelect(Dst
, Src
, True
, False
);
7633 MI
.eraseFromParent();
7638 return UnableToLegalize
;
7641 // signed cl2f(long l) {
7642 // long s = l >> 63;
7643 // float r = cul2f((l + s) ^ s);
7644 // return s ? -r : r;
7647 auto SignBit
= MIRBuilder
.buildConstant(S64
, 63);
7648 auto S
= MIRBuilder
.buildAShr(S64
, L
, SignBit
);
7650 auto LPlusS
= MIRBuilder
.buildAdd(S64
, L
, S
);
7651 auto Xor
= MIRBuilder
.buildXor(S64
, LPlusS
, S
);
7652 auto R
= MIRBuilder
.buildUITOFP(S32
, Xor
);
7654 auto RNeg
= MIRBuilder
.buildFNeg(S32
, R
);
7655 auto SignNotZero
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, S1
, S
,
7656 MIRBuilder
.buildConstant(S64
, 0));
7657 MIRBuilder
.buildSelect(Dst
, SignNotZero
, RNeg
, R
);
7658 MI
.eraseFromParent();
7662 return UnableToLegalize
;
7665 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTOUI(MachineInstr
&MI
) {
7666 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
7667 const LLT S64
= LLT::scalar(64);
7668 const LLT S32
= LLT::scalar(32);
7670 if (SrcTy
!= S64
&& SrcTy
!= S32
)
7671 return UnableToLegalize
;
7672 if (DstTy
!= S32
&& DstTy
!= S64
)
7673 return UnableToLegalize
;
7675 // FPTOSI gives same result as FPTOUI for positive signed integers.
7676 // FPTOUI needs to deal with fp values that convert to unsigned integers
7677 // greater or equal to 2^31 for float or 2^63 for double. For brevity 2^Exp.
7679 APInt TwoPExpInt
= APInt::getSignMask(DstTy
.getSizeInBits());
7680 APFloat
TwoPExpFP(SrcTy
.getSizeInBits() == 32 ? APFloat::IEEEsingle()
7681 : APFloat::IEEEdouble(),
7682 APInt::getZero(SrcTy
.getSizeInBits()));
7683 TwoPExpFP
.convertFromAPInt(TwoPExpInt
, false, APFloat::rmNearestTiesToEven
);
7685 MachineInstrBuilder FPTOSI
= MIRBuilder
.buildFPTOSI(DstTy
, Src
);
7687 MachineInstrBuilder Threshold
= MIRBuilder
.buildFConstant(SrcTy
, TwoPExpFP
);
7688 // For fp Value greater or equal to Threshold(2^Exp), we use FPTOSI on
7689 // (Value - 2^Exp) and add 2^Exp by setting highest bit in result to 1.
7690 MachineInstrBuilder FSub
= MIRBuilder
.buildFSub(SrcTy
, Src
, Threshold
);
7691 MachineInstrBuilder ResLowBits
= MIRBuilder
.buildFPTOSI(DstTy
, FSub
);
7692 MachineInstrBuilder ResHighBit
= MIRBuilder
.buildConstant(DstTy
, TwoPExpInt
);
7693 MachineInstrBuilder Res
= MIRBuilder
.buildXor(DstTy
, ResLowBits
, ResHighBit
);
7695 const LLT S1
= LLT::scalar(1);
7697 MachineInstrBuilder FCMP
=
7698 MIRBuilder
.buildFCmp(CmpInst::FCMP_ULT
, S1
, Src
, Threshold
);
7699 MIRBuilder
.buildSelect(Dst
, FCMP
, FPTOSI
, Res
);
7701 MI
.eraseFromParent();
7705 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPTOSI(MachineInstr
&MI
) {
7706 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
7707 const LLT S64
= LLT::scalar(64);
7708 const LLT S32
= LLT::scalar(32);
7710 // FIXME: Only f32 to i64 conversions are supported.
7711 if (SrcTy
.getScalarType() != S32
|| DstTy
.getScalarType() != S64
)
7712 return UnableToLegalize
;
7714 // Expand f32 -> i64 conversion
7715 // This algorithm comes from compiler-rt's implementation of fixsfdi:
7716 // https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/fixsfdi.c
7718 unsigned SrcEltBits
= SrcTy
.getScalarSizeInBits();
7720 auto ExponentMask
= MIRBuilder
.buildConstant(SrcTy
, 0x7F800000);
7721 auto ExponentLoBit
= MIRBuilder
.buildConstant(SrcTy
, 23);
7723 auto AndExpMask
= MIRBuilder
.buildAnd(SrcTy
, Src
, ExponentMask
);
7724 auto ExponentBits
= MIRBuilder
.buildLShr(SrcTy
, AndExpMask
, ExponentLoBit
);
7726 auto SignMask
= MIRBuilder
.buildConstant(SrcTy
,
7727 APInt::getSignMask(SrcEltBits
));
7728 auto AndSignMask
= MIRBuilder
.buildAnd(SrcTy
, Src
, SignMask
);
7729 auto SignLowBit
= MIRBuilder
.buildConstant(SrcTy
, SrcEltBits
- 1);
7730 auto Sign
= MIRBuilder
.buildAShr(SrcTy
, AndSignMask
, SignLowBit
);
7731 Sign
= MIRBuilder
.buildSExt(DstTy
, Sign
);
7733 auto MantissaMask
= MIRBuilder
.buildConstant(SrcTy
, 0x007FFFFF);
7734 auto AndMantissaMask
= MIRBuilder
.buildAnd(SrcTy
, Src
, MantissaMask
);
7735 auto K
= MIRBuilder
.buildConstant(SrcTy
, 0x00800000);
7737 auto R
= MIRBuilder
.buildOr(SrcTy
, AndMantissaMask
, K
);
7738 R
= MIRBuilder
.buildZExt(DstTy
, R
);
7740 auto Bias
= MIRBuilder
.buildConstant(SrcTy
, 127);
7741 auto Exponent
= MIRBuilder
.buildSub(SrcTy
, ExponentBits
, Bias
);
7742 auto SubExponent
= MIRBuilder
.buildSub(SrcTy
, Exponent
, ExponentLoBit
);
7743 auto ExponentSub
= MIRBuilder
.buildSub(SrcTy
, ExponentLoBit
, Exponent
);
7745 auto Shl
= MIRBuilder
.buildShl(DstTy
, R
, SubExponent
);
7746 auto Srl
= MIRBuilder
.buildLShr(DstTy
, R
, ExponentSub
);
7748 const LLT S1
= LLT::scalar(1);
7749 auto CmpGt
= MIRBuilder
.buildICmp(CmpInst::ICMP_SGT
,
7750 S1
, Exponent
, ExponentLoBit
);
7752 R
= MIRBuilder
.buildSelect(DstTy
, CmpGt
, Shl
, Srl
);
7754 auto XorSign
= MIRBuilder
.buildXor(DstTy
, R
, Sign
);
7755 auto Ret
= MIRBuilder
.buildSub(DstTy
, XorSign
, Sign
);
7757 auto ZeroSrcTy
= MIRBuilder
.buildConstant(SrcTy
, 0);
7759 auto ExponentLt0
= MIRBuilder
.buildICmp(CmpInst::ICMP_SLT
,
7760 S1
, Exponent
, ZeroSrcTy
);
7762 auto ZeroDstTy
= MIRBuilder
.buildConstant(DstTy
, 0);
7763 MIRBuilder
.buildSelect(Dst
, ExponentLt0
, ZeroDstTy
, Ret
);
7765 MI
.eraseFromParent();
7769 LegalizerHelper::LegalizeResult
7770 LegalizerHelper::lowerFPTOINT_SAT(MachineInstr
&MI
) {
7771 auto [Dst
, DstTy
, Src
, SrcTy
] = MI
.getFirst2RegLLTs();
7773 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_FPTOSI_SAT
;
7774 unsigned SatWidth
= DstTy
.getScalarSizeInBits();
7776 // Determine minimum and maximum integer values and their corresponding
7777 // floating-point values.
7778 APInt MinInt
, MaxInt
;
7780 MinInt
= APInt::getSignedMinValue(SatWidth
);
7781 MaxInt
= APInt::getSignedMaxValue(SatWidth
);
7783 MinInt
= APInt::getMinValue(SatWidth
);
7784 MaxInt
= APInt::getMaxValue(SatWidth
);
7787 const fltSemantics
&Semantics
= getFltSemanticForLLT(SrcTy
.getScalarType());
7788 APFloat
MinFloat(Semantics
);
7789 APFloat
MaxFloat(Semantics
);
7791 APFloat::opStatus MinStatus
=
7792 MinFloat
.convertFromAPInt(MinInt
, IsSigned
, APFloat::rmTowardZero
);
7793 APFloat::opStatus MaxStatus
=
7794 MaxFloat
.convertFromAPInt(MaxInt
, IsSigned
, APFloat::rmTowardZero
);
7795 bool AreExactFloatBounds
= !(MinStatus
& APFloat::opStatus::opInexact
) &&
7796 !(MaxStatus
& APFloat::opStatus::opInexact
);
7798 // If the integer bounds are exactly representable as floats, emit a
7799 // min+max+fptoi sequence. Otherwise we have to use a sequence of comparisons
7801 if (AreExactFloatBounds
) {
7802 // Clamp Src by MinFloat from below. If Src is NaN the result is MinFloat.
7803 auto MaxC
= MIRBuilder
.buildFConstant(SrcTy
, MinFloat
);
7804 auto MaxP
= MIRBuilder
.buildFCmp(CmpInst::FCMP_ULT
,
7805 SrcTy
.changeElementSize(1), Src
, MaxC
);
7806 auto Max
= MIRBuilder
.buildSelect(SrcTy
, MaxP
, Src
, MaxC
);
7807 // Clamp by MaxFloat from above. NaN cannot occur.
7808 auto MinC
= MIRBuilder
.buildFConstant(SrcTy
, MaxFloat
);
7810 MIRBuilder
.buildFCmp(CmpInst::FCMP_OGT
, SrcTy
.changeElementSize(1), Max
,
7811 MinC
, MachineInstr::FmNoNans
);
7813 MIRBuilder
.buildSelect(SrcTy
, MinP
, Max
, MinC
, MachineInstr::FmNoNans
);
7814 // Convert clamped value to integer. In the unsigned case we're done,
7815 // because we mapped NaN to MinFloat, which will cast to zero.
7817 MIRBuilder
.buildFPTOUI(Dst
, Min
);
7818 MI
.eraseFromParent();
7822 // Otherwise, select 0 if Src is NaN.
7823 auto FpToInt
= MIRBuilder
.buildFPTOSI(DstTy
, Min
);
7824 auto IsZero
= MIRBuilder
.buildFCmp(CmpInst::FCMP_UNO
,
7825 DstTy
.changeElementSize(1), Src
, Src
);
7826 MIRBuilder
.buildSelect(Dst
, IsZero
, MIRBuilder
.buildConstant(DstTy
, 0),
7828 MI
.eraseFromParent();
7832 // Result of direct conversion. The assumption here is that the operation is
7833 // non-trapping and it's fine to apply it to an out-of-range value if we
7834 // select it away later.
7835 auto FpToInt
= IsSigned
? MIRBuilder
.buildFPTOSI(DstTy
, Src
)
7836 : MIRBuilder
.buildFPTOUI(DstTy
, Src
);
7838 // If Src ULT MinFloat, select MinInt. In particular, this also selects
7839 // MinInt if Src is NaN.
7841 MIRBuilder
.buildFCmp(CmpInst::FCMP_ULT
, SrcTy
.changeElementSize(1), Src
,
7842 MIRBuilder
.buildFConstant(SrcTy
, MinFloat
));
7843 auto Max
= MIRBuilder
.buildSelect(
7844 DstTy
, ULT
, MIRBuilder
.buildConstant(DstTy
, MinInt
), FpToInt
);
7845 // If Src OGT MaxFloat, select MaxInt.
7847 MIRBuilder
.buildFCmp(CmpInst::FCMP_OGT
, SrcTy
.changeElementSize(1), Src
,
7848 MIRBuilder
.buildFConstant(SrcTy
, MaxFloat
));
7850 // In the unsigned case we are done, because we mapped NaN to MinInt, which
7853 MIRBuilder
.buildSelect(Dst
, OGT
, MIRBuilder
.buildConstant(DstTy
, MaxInt
),
7855 MI
.eraseFromParent();
7859 // Otherwise, select 0 if Src is NaN.
7860 auto Min
= MIRBuilder
.buildSelect(
7861 DstTy
, OGT
, MIRBuilder
.buildConstant(DstTy
, MaxInt
), Max
);
7862 auto IsZero
= MIRBuilder
.buildFCmp(CmpInst::FCMP_UNO
,
7863 DstTy
.changeElementSize(1), Src
, Src
);
7864 MIRBuilder
.buildSelect(Dst
, IsZero
, MIRBuilder
.buildConstant(DstTy
, 0), Min
);
7865 MI
.eraseFromParent();
7869 // f64 -> f16 conversion using round-to-nearest-even rounding mode.
7870 LegalizerHelper::LegalizeResult
7871 LegalizerHelper::lowerFPTRUNC_F64_TO_F16(MachineInstr
&MI
) {
7872 const LLT S1
= LLT::scalar(1);
7873 const LLT S32
= LLT::scalar(32);
7875 auto [Dst
, Src
] = MI
.getFirst2Regs();
7876 assert(MRI
.getType(Dst
).getScalarType() == LLT::scalar(16) &&
7877 MRI
.getType(Src
).getScalarType() == LLT::scalar(64));
7879 if (MRI
.getType(Src
).isVector()) // TODO: Handle vectors directly.
7880 return UnableToLegalize
;
7882 if (MIRBuilder
.getMF().getTarget().Options
.UnsafeFPMath
) {
7883 unsigned Flags
= MI
.getFlags();
7884 auto Src32
= MIRBuilder
.buildFPTrunc(S32
, Src
, Flags
);
7885 MIRBuilder
.buildFPTrunc(Dst
, Src32
, Flags
);
7886 MI
.eraseFromParent();
7890 const unsigned ExpMask
= 0x7ff;
7891 const unsigned ExpBiasf64
= 1023;
7892 const unsigned ExpBiasf16
= 15;
7894 auto Unmerge
= MIRBuilder
.buildUnmerge(S32
, Src
);
7895 Register U
= Unmerge
.getReg(0);
7896 Register UH
= Unmerge
.getReg(1);
7898 auto E
= MIRBuilder
.buildLShr(S32
, UH
, MIRBuilder
.buildConstant(S32
, 20));
7899 E
= MIRBuilder
.buildAnd(S32
, E
, MIRBuilder
.buildConstant(S32
, ExpMask
));
7901 // Subtract the fp64 exponent bias (1023) to get the real exponent and
7902 // add the f16 bias (15) to get the biased exponent for the f16 format.
7903 E
= MIRBuilder
.buildAdd(
7904 S32
, E
, MIRBuilder
.buildConstant(S32
, -ExpBiasf64
+ ExpBiasf16
));
7906 auto M
= MIRBuilder
.buildLShr(S32
, UH
, MIRBuilder
.buildConstant(S32
, 8));
7907 M
= MIRBuilder
.buildAnd(S32
, M
, MIRBuilder
.buildConstant(S32
, 0xffe));
7909 auto MaskedSig
= MIRBuilder
.buildAnd(S32
, UH
,
7910 MIRBuilder
.buildConstant(S32
, 0x1ff));
7911 MaskedSig
= MIRBuilder
.buildOr(S32
, MaskedSig
, U
);
7913 auto Zero
= MIRBuilder
.buildConstant(S32
, 0);
7914 auto SigCmpNE0
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, S1
, MaskedSig
, Zero
);
7915 auto Lo40Set
= MIRBuilder
.buildZExt(S32
, SigCmpNE0
);
7916 M
= MIRBuilder
.buildOr(S32
, M
, Lo40Set
);
7918 // (M != 0 ? 0x0200 : 0) | 0x7c00;
7919 auto Bits0x200
= MIRBuilder
.buildConstant(S32
, 0x0200);
7920 auto CmpM_NE0
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, S1
, M
, Zero
);
7921 auto SelectCC
= MIRBuilder
.buildSelect(S32
, CmpM_NE0
, Bits0x200
, Zero
);
7923 auto Bits0x7c00
= MIRBuilder
.buildConstant(S32
, 0x7c00);
7924 auto I
= MIRBuilder
.buildOr(S32
, SelectCC
, Bits0x7c00
);
7926 // N = M | (E << 12);
7927 auto EShl12
= MIRBuilder
.buildShl(S32
, E
, MIRBuilder
.buildConstant(S32
, 12));
7928 auto N
= MIRBuilder
.buildOr(S32
, M
, EShl12
);
7930 // B = clamp(1-E, 0, 13);
7931 auto One
= MIRBuilder
.buildConstant(S32
, 1);
7932 auto OneSubExp
= MIRBuilder
.buildSub(S32
, One
, E
);
7933 auto B
= MIRBuilder
.buildSMax(S32
, OneSubExp
, Zero
);
7934 B
= MIRBuilder
.buildSMin(S32
, B
, MIRBuilder
.buildConstant(S32
, 13));
7936 auto SigSetHigh
= MIRBuilder
.buildOr(S32
, M
,
7937 MIRBuilder
.buildConstant(S32
, 0x1000));
7939 auto D
= MIRBuilder
.buildLShr(S32
, SigSetHigh
, B
);
7940 auto D0
= MIRBuilder
.buildShl(S32
, D
, B
);
7942 auto D0_NE_SigSetHigh
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, S1
,
7944 auto D1
= MIRBuilder
.buildZExt(S32
, D0_NE_SigSetHigh
);
7945 D
= MIRBuilder
.buildOr(S32
, D
, D1
);
7947 auto CmpELtOne
= MIRBuilder
.buildICmp(CmpInst::ICMP_SLT
, S1
, E
, One
);
7948 auto V
= MIRBuilder
.buildSelect(S32
, CmpELtOne
, D
, N
);
7950 auto VLow3
= MIRBuilder
.buildAnd(S32
, V
, MIRBuilder
.buildConstant(S32
, 7));
7951 V
= MIRBuilder
.buildLShr(S32
, V
, MIRBuilder
.buildConstant(S32
, 2));
7953 auto VLow3Eq3
= MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, S1
, VLow3
,
7954 MIRBuilder
.buildConstant(S32
, 3));
7955 auto V0
= MIRBuilder
.buildZExt(S32
, VLow3Eq3
);
7957 auto VLow3Gt5
= MIRBuilder
.buildICmp(CmpInst::ICMP_SGT
, S1
, VLow3
,
7958 MIRBuilder
.buildConstant(S32
, 5));
7959 auto V1
= MIRBuilder
.buildZExt(S32
, VLow3Gt5
);
7961 V1
= MIRBuilder
.buildOr(S32
, V0
, V1
);
7962 V
= MIRBuilder
.buildAdd(S32
, V
, V1
);
7964 auto CmpEGt30
= MIRBuilder
.buildICmp(CmpInst::ICMP_SGT
, S1
,
7965 E
, MIRBuilder
.buildConstant(S32
, 30));
7966 V
= MIRBuilder
.buildSelect(S32
, CmpEGt30
,
7967 MIRBuilder
.buildConstant(S32
, 0x7c00), V
);
7969 auto CmpEGt1039
= MIRBuilder
.buildICmp(CmpInst::ICMP_EQ
, S1
,
7970 E
, MIRBuilder
.buildConstant(S32
, 1039));
7971 V
= MIRBuilder
.buildSelect(S32
, CmpEGt1039
, I
, V
);
7973 // Extract the sign bit.
7974 auto Sign
= MIRBuilder
.buildLShr(S32
, UH
, MIRBuilder
.buildConstant(S32
, 16));
7975 Sign
= MIRBuilder
.buildAnd(S32
, Sign
, MIRBuilder
.buildConstant(S32
, 0x8000));
7977 // Insert the sign bit
7978 V
= MIRBuilder
.buildOr(S32
, Sign
, V
);
7980 MIRBuilder
.buildTrunc(Dst
, V
);
7981 MI
.eraseFromParent();
7985 LegalizerHelper::LegalizeResult
7986 LegalizerHelper::lowerFPTRUNC(MachineInstr
&MI
) {
7987 auto [DstTy
, SrcTy
] = MI
.getFirst2LLTs();
7988 const LLT S64
= LLT::scalar(64);
7989 const LLT S16
= LLT::scalar(16);
7991 if (DstTy
.getScalarType() == S16
&& SrcTy
.getScalarType() == S64
)
7992 return lowerFPTRUNC_F64_TO_F16(MI
);
7994 return UnableToLegalize
;
7997 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFPOWI(MachineInstr
&MI
) {
7998 auto [Dst
, Src0
, Src1
] = MI
.getFirst3Regs();
7999 LLT Ty
= MRI
.getType(Dst
);
8001 auto CvtSrc1
= MIRBuilder
.buildSITOFP(Ty
, Src1
);
8002 MIRBuilder
.buildFPow(Dst
, Src0
, CvtSrc1
, MI
.getFlags());
8003 MI
.eraseFromParent();
8007 static CmpInst::Predicate
minMaxToCompare(unsigned Opc
) {
8009 case TargetOpcode::G_SMIN
:
8010 return CmpInst::ICMP_SLT
;
8011 case TargetOpcode::G_SMAX
:
8012 return CmpInst::ICMP_SGT
;
8013 case TargetOpcode::G_UMIN
:
8014 return CmpInst::ICMP_ULT
;
8015 case TargetOpcode::G_UMAX
:
8016 return CmpInst::ICMP_UGT
;
8018 llvm_unreachable("not in integer min/max");
8022 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerMinMax(MachineInstr
&MI
) {
8023 auto [Dst
, Src0
, Src1
] = MI
.getFirst3Regs();
8025 const CmpInst::Predicate Pred
= minMaxToCompare(MI
.getOpcode());
8026 LLT CmpType
= MRI
.getType(Dst
).changeElementSize(1);
8028 auto Cmp
= MIRBuilder
.buildICmp(Pred
, CmpType
, Src0
, Src1
);
8029 MIRBuilder
.buildSelect(Dst
, Cmp
, Src0
, Src1
);
8031 MI
.eraseFromParent();
8035 LegalizerHelper::LegalizeResult
8036 LegalizerHelper::lowerThreewayCompare(MachineInstr
&MI
) {
8037 GSUCmp
*Cmp
= cast
<GSUCmp
>(&MI
);
8039 Register Dst
= Cmp
->getReg(0);
8040 LLT DstTy
= MRI
.getType(Dst
);
8041 LLT SrcTy
= MRI
.getType(Cmp
->getReg(1));
8042 LLT CmpTy
= DstTy
.changeElementSize(1);
8044 CmpInst::Predicate LTPredicate
= Cmp
->isSigned()
8045 ? CmpInst::Predicate::ICMP_SLT
8046 : CmpInst::Predicate::ICMP_ULT
;
8047 CmpInst::Predicate GTPredicate
= Cmp
->isSigned()
8048 ? CmpInst::Predicate::ICMP_SGT
8049 : CmpInst::Predicate::ICMP_UGT
;
8051 auto Zero
= MIRBuilder
.buildConstant(DstTy
, 0);
8052 auto IsGT
= MIRBuilder
.buildICmp(GTPredicate
, CmpTy
, Cmp
->getLHSReg(),
8054 auto IsLT
= MIRBuilder
.buildICmp(LTPredicate
, CmpTy
, Cmp
->getLHSReg(),
8057 auto &Ctx
= MIRBuilder
.getMF().getFunction().getContext();
8058 auto BC
= TLI
.getBooleanContents(DstTy
.isVector(), /*isFP=*/false);
8059 if (TLI
.shouldExpandCmpUsingSelects(getApproximateEVTForLLT(SrcTy
, Ctx
)) ||
8060 BC
== TargetLowering::UndefinedBooleanContent
) {
8061 auto One
= MIRBuilder
.buildConstant(DstTy
, 1);
8062 auto SelectZeroOrOne
= MIRBuilder
.buildSelect(DstTy
, IsGT
, One
, Zero
);
8064 auto MinusOne
= MIRBuilder
.buildConstant(DstTy
, -1);
8065 MIRBuilder
.buildSelect(Dst
, IsLT
, MinusOne
, SelectZeroOrOne
);
8067 if (BC
== TargetLowering::ZeroOrNegativeOneBooleanContent
)
8068 std::swap(IsGT
, IsLT
);
8069 // Extend boolean results to DstTy, which is at least i2, before subtracting
8071 unsigned BoolExtOp
=
8072 MIRBuilder
.getBoolExtOp(DstTy
.isVector(), /*isFP=*/false);
8073 IsGT
= MIRBuilder
.buildInstr(BoolExtOp
, {DstTy
}, {IsGT
});
8074 IsLT
= MIRBuilder
.buildInstr(BoolExtOp
, {DstTy
}, {IsLT
});
8075 MIRBuilder
.buildSub(Dst
, IsGT
, IsLT
);
8078 MI
.eraseFromParent();
8082 LegalizerHelper::LegalizeResult
8083 LegalizerHelper::lowerFCopySign(MachineInstr
&MI
) {
8084 auto [Dst
, DstTy
, Src0
, Src0Ty
, Src1
, Src1Ty
] = MI
.getFirst3RegLLTs();
8085 const int Src0Size
= Src0Ty
.getScalarSizeInBits();
8086 const int Src1Size
= Src1Ty
.getScalarSizeInBits();
8088 auto SignBitMask
= MIRBuilder
.buildConstant(
8089 Src0Ty
, APInt::getSignMask(Src0Size
));
8091 auto NotSignBitMask
= MIRBuilder
.buildConstant(
8092 Src0Ty
, APInt::getLowBitsSet(Src0Size
, Src0Size
- 1));
8094 Register And0
= MIRBuilder
.buildAnd(Src0Ty
, Src0
, NotSignBitMask
).getReg(0);
8096 if (Src0Ty
== Src1Ty
) {
8097 And1
= MIRBuilder
.buildAnd(Src1Ty
, Src1
, SignBitMask
).getReg(0);
8098 } else if (Src0Size
> Src1Size
) {
8099 auto ShiftAmt
= MIRBuilder
.buildConstant(Src0Ty
, Src0Size
- Src1Size
);
8100 auto Zext
= MIRBuilder
.buildZExt(Src0Ty
, Src1
);
8101 auto Shift
= MIRBuilder
.buildShl(Src0Ty
, Zext
, ShiftAmt
);
8102 And1
= MIRBuilder
.buildAnd(Src0Ty
, Shift
, SignBitMask
).getReg(0);
8104 auto ShiftAmt
= MIRBuilder
.buildConstant(Src1Ty
, Src1Size
- Src0Size
);
8105 auto Shift
= MIRBuilder
.buildLShr(Src1Ty
, Src1
, ShiftAmt
);
8106 auto Trunc
= MIRBuilder
.buildTrunc(Src0Ty
, Shift
);
8107 And1
= MIRBuilder
.buildAnd(Src0Ty
, Trunc
, SignBitMask
).getReg(0);
8110 // Be careful about setting nsz/nnan/ninf on every instruction, since the
8111 // constants are a nan and -0.0, but the final result should preserve
8113 unsigned Flags
= MI
.getFlags();
8115 // We masked the sign bit and the not-sign bit, so these are disjoint.
8116 Flags
|= MachineInstr::Disjoint
;
8118 MIRBuilder
.buildOr(Dst
, And0
, And1
, Flags
);
8120 MI
.eraseFromParent();
8124 LegalizerHelper::LegalizeResult
8125 LegalizerHelper::lowerFMinNumMaxNum(MachineInstr
&MI
) {
8126 unsigned NewOp
= MI
.getOpcode() == TargetOpcode::G_FMINNUM
?
8127 TargetOpcode::G_FMINNUM_IEEE
: TargetOpcode::G_FMAXNUM_IEEE
;
8129 auto [Dst
, Src0
, Src1
] = MI
.getFirst3Regs();
8130 LLT Ty
= MRI
.getType(Dst
);
8132 if (!MI
.getFlag(MachineInstr::FmNoNans
)) {
8133 // Insert canonicalizes if it's possible we need to quiet to get correct
8136 // Note this must be done here, and not as an optimization combine in the
8137 // absence of a dedicate quiet-snan instruction as we're using an
8138 // omni-purpose G_FCANONICALIZE.
8139 if (!isKnownNeverSNaN(Src0
, MRI
))
8140 Src0
= MIRBuilder
.buildFCanonicalize(Ty
, Src0
, MI
.getFlags()).getReg(0);
8142 if (!isKnownNeverSNaN(Src1
, MRI
))
8143 Src1
= MIRBuilder
.buildFCanonicalize(Ty
, Src1
, MI
.getFlags()).getReg(0);
8146 // If there are no nans, it's safe to simply replace this with the non-IEEE
8148 MIRBuilder
.buildInstr(NewOp
, {Dst
}, {Src0
, Src1
}, MI
.getFlags());
8149 MI
.eraseFromParent();
8153 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFMad(MachineInstr
&MI
) {
8154 // Expand G_FMAD a, b, c -> G_FADD (G_FMUL a, b), c
8155 Register DstReg
= MI
.getOperand(0).getReg();
8156 LLT Ty
= MRI
.getType(DstReg
);
8157 unsigned Flags
= MI
.getFlags();
8159 auto Mul
= MIRBuilder
.buildFMul(Ty
, MI
.getOperand(1), MI
.getOperand(2),
8161 MIRBuilder
.buildFAdd(DstReg
, Mul
, MI
.getOperand(3), Flags
);
8162 MI
.eraseFromParent();
8166 LegalizerHelper::LegalizeResult
8167 LegalizerHelper::lowerIntrinsicRound(MachineInstr
&MI
) {
8168 auto [DstReg
, X
] = MI
.getFirst2Regs();
8169 const unsigned Flags
= MI
.getFlags();
8170 const LLT Ty
= MRI
.getType(DstReg
);
8171 const LLT CondTy
= Ty
.changeElementSize(1);
8176 // o = copysign(d >= 0.5 ? 1.0 : 0.0, x);
8179 auto T
= MIRBuilder
.buildIntrinsicTrunc(Ty
, X
, Flags
);
8181 auto Diff
= MIRBuilder
.buildFSub(Ty
, X
, T
, Flags
);
8182 auto AbsDiff
= MIRBuilder
.buildFAbs(Ty
, Diff
, Flags
);
8184 auto Half
= MIRBuilder
.buildFConstant(Ty
, 0.5);
8186 MIRBuilder
.buildFCmp(CmpInst::FCMP_OGE
, CondTy
, AbsDiff
, Half
, Flags
);
8188 // Could emit G_UITOFP instead
8189 auto One
= MIRBuilder
.buildFConstant(Ty
, 1.0);
8190 auto Zero
= MIRBuilder
.buildFConstant(Ty
, 0.0);
8191 auto BoolFP
= MIRBuilder
.buildSelect(Ty
, Cmp
, One
, Zero
);
8192 auto SignedOffset
= MIRBuilder
.buildFCopysign(Ty
, BoolFP
, X
);
8194 MIRBuilder
.buildFAdd(DstReg
, T
, SignedOffset
, Flags
);
8196 MI
.eraseFromParent();
8200 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFFloor(MachineInstr
&MI
) {
8201 auto [DstReg
, SrcReg
] = MI
.getFirst2Regs();
8202 unsigned Flags
= MI
.getFlags();
8203 LLT Ty
= MRI
.getType(DstReg
);
8204 const LLT CondTy
= Ty
.changeElementSize(1);
8206 // result = trunc(src);
8207 // if (src < 0.0 && src != result)
8210 auto Trunc
= MIRBuilder
.buildIntrinsicTrunc(Ty
, SrcReg
, Flags
);
8211 auto Zero
= MIRBuilder
.buildFConstant(Ty
, 0.0);
8213 auto Lt0
= MIRBuilder
.buildFCmp(CmpInst::FCMP_OLT
, CondTy
,
8214 SrcReg
, Zero
, Flags
);
8215 auto NeTrunc
= MIRBuilder
.buildFCmp(CmpInst::FCMP_ONE
, CondTy
,
8216 SrcReg
, Trunc
, Flags
);
8217 auto And
= MIRBuilder
.buildAnd(CondTy
, Lt0
, NeTrunc
);
8218 auto AddVal
= MIRBuilder
.buildSITOFP(Ty
, And
);
8220 MIRBuilder
.buildFAdd(DstReg
, Trunc
, AddVal
, Flags
);
8221 MI
.eraseFromParent();
8225 LegalizerHelper::LegalizeResult
8226 LegalizerHelper::lowerMergeValues(MachineInstr
&MI
) {
8227 const unsigned NumOps
= MI
.getNumOperands();
8228 auto [DstReg
, DstTy
, Src0Reg
, Src0Ty
] = MI
.getFirst2RegLLTs();
8229 unsigned PartSize
= Src0Ty
.getSizeInBits();
8231 LLT WideTy
= LLT::scalar(DstTy
.getSizeInBits());
8232 Register ResultReg
= MIRBuilder
.buildZExt(WideTy
, Src0Reg
).getReg(0);
8234 for (unsigned I
= 2; I
!= NumOps
; ++I
) {
8235 const unsigned Offset
= (I
- 1) * PartSize
;
8237 Register SrcReg
= MI
.getOperand(I
).getReg();
8238 auto ZextInput
= MIRBuilder
.buildZExt(WideTy
, SrcReg
);
8240 Register NextResult
= I
+ 1 == NumOps
&& WideTy
== DstTy
? DstReg
:
8241 MRI
.createGenericVirtualRegister(WideTy
);
8243 auto ShiftAmt
= MIRBuilder
.buildConstant(WideTy
, Offset
);
8244 auto Shl
= MIRBuilder
.buildShl(WideTy
, ZextInput
, ShiftAmt
);
8245 MIRBuilder
.buildOr(NextResult
, ResultReg
, Shl
);
8246 ResultReg
= NextResult
;
8249 if (DstTy
.isPointer()) {
8250 if (MIRBuilder
.getDataLayout().isNonIntegralAddressSpace(
8251 DstTy
.getAddressSpace())) {
8252 LLVM_DEBUG(dbgs() << "Not casting nonintegral address space\n");
8253 return UnableToLegalize
;
8256 MIRBuilder
.buildIntToPtr(DstReg
, ResultReg
);
8259 MI
.eraseFromParent();
8263 LegalizerHelper::LegalizeResult
8264 LegalizerHelper::lowerUnmergeValues(MachineInstr
&MI
) {
8265 const unsigned NumDst
= MI
.getNumOperands() - 1;
8266 Register SrcReg
= MI
.getOperand(NumDst
).getReg();
8267 Register Dst0Reg
= MI
.getOperand(0).getReg();
8268 LLT DstTy
= MRI
.getType(Dst0Reg
);
8269 if (DstTy
.isPointer())
8270 return UnableToLegalize
; // TODO
8272 SrcReg
= coerceToScalar(SrcReg
);
8274 return UnableToLegalize
;
8276 // Expand scalarizing unmerge as bitcast to integer and shift.
8277 LLT IntTy
= MRI
.getType(SrcReg
);
8279 MIRBuilder
.buildTrunc(Dst0Reg
, SrcReg
);
8281 const unsigned DstSize
= DstTy
.getSizeInBits();
8282 unsigned Offset
= DstSize
;
8283 for (unsigned I
= 1; I
!= NumDst
; ++I
, Offset
+= DstSize
) {
8284 auto ShiftAmt
= MIRBuilder
.buildConstant(IntTy
, Offset
);
8285 auto Shift
= MIRBuilder
.buildLShr(IntTy
, SrcReg
, ShiftAmt
);
8286 MIRBuilder
.buildTrunc(MI
.getOperand(I
), Shift
);
8289 MI
.eraseFromParent();
8293 /// Lower a vector extract or insert by writing the vector to a stack temporary
8294 /// and reloading the element or vector.
8296 /// %dst = G_EXTRACT_VECTOR_ELT %vec, %idx
8298 /// %stack_temp = G_FRAME_INDEX
8299 /// G_STORE %vec, %stack_temp
8300 /// %idx = clamp(%idx, %vec.getNumElements())
8301 /// %element_ptr = G_PTR_ADD %stack_temp, %idx
8302 /// %dst = G_LOAD %element_ptr
8303 LegalizerHelper::LegalizeResult
8304 LegalizerHelper::lowerExtractInsertVectorElt(MachineInstr
&MI
) {
8305 Register DstReg
= MI
.getOperand(0).getReg();
8306 Register SrcVec
= MI
.getOperand(1).getReg();
8308 if (MI
.getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT
)
8309 InsertVal
= MI
.getOperand(2).getReg();
8311 Register Idx
= MI
.getOperand(MI
.getNumOperands() - 1).getReg();
8313 LLT VecTy
= MRI
.getType(SrcVec
);
8314 LLT EltTy
= VecTy
.getElementType();
8315 unsigned NumElts
= VecTy
.getNumElements();
8318 if (mi_match(Idx
, MRI
, m_ICst(IdxVal
)) && IdxVal
<= NumElts
) {
8319 SmallVector
<Register
, 8> SrcRegs
;
8320 extractParts(SrcVec
, EltTy
, NumElts
, SrcRegs
, MIRBuilder
, MRI
);
8323 SrcRegs
[IdxVal
] = MI
.getOperand(2).getReg();
8324 MIRBuilder
.buildMergeLikeInstr(DstReg
, SrcRegs
);
8326 MIRBuilder
.buildCopy(DstReg
, SrcRegs
[IdxVal
]);
8329 MI
.eraseFromParent();
8333 if (!EltTy
.isByteSized()) { // Not implemented.
8334 LLVM_DEBUG(dbgs() << "Can't handle non-byte element vectors yet\n");
8335 return UnableToLegalize
;
8338 unsigned EltBytes
= EltTy
.getSizeInBytes();
8339 Align VecAlign
= getStackTemporaryAlignment(VecTy
);
8342 MachinePointerInfo PtrInfo
;
8343 auto StackTemp
= createStackTemporary(
8344 TypeSize::getFixed(VecTy
.getSizeInBytes()), VecAlign
, PtrInfo
);
8345 MIRBuilder
.buildStore(SrcVec
, StackTemp
, PtrInfo
, VecAlign
);
8347 // Get the pointer to the element, and be sure not to hit undefined behavior
8348 // if the index is out of bounds.
8349 Register EltPtr
= getVectorElementPointer(StackTemp
.getReg(0), VecTy
, Idx
);
8351 if (mi_match(Idx
, MRI
, m_ICst(IdxVal
))) {
8352 int64_t Offset
= IdxVal
* EltBytes
;
8353 PtrInfo
= PtrInfo
.getWithOffset(Offset
);
8354 EltAlign
= commonAlignment(VecAlign
, Offset
);
8356 // We lose information with a variable offset.
8357 EltAlign
= getStackTemporaryAlignment(EltTy
);
8358 PtrInfo
= MachinePointerInfo(MRI
.getType(EltPtr
).getAddressSpace());
8362 // Write the inserted element
8363 MIRBuilder
.buildStore(InsertVal
, EltPtr
, PtrInfo
, EltAlign
);
8365 // Reload the whole vector.
8366 MIRBuilder
.buildLoad(DstReg
, StackTemp
, PtrInfo
, VecAlign
);
8368 MIRBuilder
.buildLoad(DstReg
, EltPtr
, PtrInfo
, EltAlign
);
8371 MI
.eraseFromParent();
8375 LegalizerHelper::LegalizeResult
8376 LegalizerHelper::lowerShuffleVector(MachineInstr
&MI
) {
8377 auto [DstReg
, DstTy
, Src0Reg
, Src0Ty
, Src1Reg
, Src1Ty
] =
8378 MI
.getFirst3RegLLTs();
8379 LLT IdxTy
= LLT::scalar(32);
8381 ArrayRef
<int> Mask
= MI
.getOperand(3).getShuffleMask();
8383 SmallVector
<Register
, 32> BuildVec
;
8384 LLT EltTy
= DstTy
.getScalarType();
8386 for (int Idx
: Mask
) {
8388 if (!Undef
.isValid())
8389 Undef
= MIRBuilder
.buildUndef(EltTy
).getReg(0);
8390 BuildVec
.push_back(Undef
);
8394 if (Src0Ty
.isScalar()) {
8395 BuildVec
.push_back(Idx
== 0 ? Src0Reg
: Src1Reg
);
8397 int NumElts
= Src0Ty
.getNumElements();
8398 Register SrcVec
= Idx
< NumElts
? Src0Reg
: Src1Reg
;
8399 int ExtractIdx
= Idx
< NumElts
? Idx
: Idx
- NumElts
;
8400 auto IdxK
= MIRBuilder
.buildConstant(IdxTy
, ExtractIdx
);
8401 auto Extract
= MIRBuilder
.buildExtractVectorElement(EltTy
, SrcVec
, IdxK
);
8402 BuildVec
.push_back(Extract
.getReg(0));
8406 if (DstTy
.isScalar())
8407 MIRBuilder
.buildCopy(DstReg
, BuildVec
[0]);
8409 MIRBuilder
.buildBuildVector(DstReg
, BuildVec
);
8410 MI
.eraseFromParent();
8414 LegalizerHelper::LegalizeResult
8415 LegalizerHelper::lowerVECTOR_COMPRESS(llvm::MachineInstr
&MI
) {
8416 auto [Dst
, DstTy
, Vec
, VecTy
, Mask
, MaskTy
, Passthru
, PassthruTy
] =
8417 MI
.getFirst4RegLLTs();
8419 if (VecTy
.isScalableVector())
8420 report_fatal_error("Cannot expand masked_compress for scalable vectors.");
8422 Align VecAlign
= getStackTemporaryAlignment(VecTy
);
8423 MachinePointerInfo PtrInfo
;
8425 createStackTemporary(TypeSize::getFixed(VecTy
.getSizeInBytes()), VecAlign
,
8428 MachinePointerInfo ValPtrInfo
=
8429 MachinePointerInfo::getUnknownStack(*MI
.getMF());
8431 LLT IdxTy
= LLT::scalar(32);
8432 LLT ValTy
= VecTy
.getElementType();
8433 Align ValAlign
= getStackTemporaryAlignment(ValTy
);
8435 auto OutPos
= MIRBuilder
.buildConstant(IdxTy
, 0);
8438 MRI
.getVRegDef(Passthru
)->getOpcode() != TargetOpcode::G_IMPLICIT_DEF
;
8441 MIRBuilder
.buildStore(Passthru
, StackPtr
, PtrInfo
, VecAlign
);
8443 Register LastWriteVal
;
8444 std::optional
<APInt
> PassthruSplatVal
=
8445 isConstantOrConstantSplatVector(*MRI
.getVRegDef(Passthru
), MRI
);
8447 if (PassthruSplatVal
.has_value()) {
8449 MIRBuilder
.buildConstant(ValTy
, PassthruSplatVal
.value()).getReg(0);
8450 } else if (HasPassthru
) {
8451 auto Popcount
= MIRBuilder
.buildZExt(MaskTy
.changeElementSize(32), Mask
);
8452 Popcount
= MIRBuilder
.buildInstr(TargetOpcode::G_VECREDUCE_ADD
,
8453 {LLT::scalar(32)}, {Popcount
});
8455 Register LastElmtPtr
=
8456 getVectorElementPointer(StackPtr
, VecTy
, Popcount
.getReg(0));
8458 MIRBuilder
.buildLoad(ValTy
, LastElmtPtr
, ValPtrInfo
, ValAlign
)
8462 unsigned NumElmts
= VecTy
.getNumElements();
8463 for (unsigned I
= 0; I
< NumElmts
; ++I
) {
8464 auto Idx
= MIRBuilder
.buildConstant(IdxTy
, I
);
8465 auto Val
= MIRBuilder
.buildExtractVectorElement(ValTy
, Vec
, Idx
);
8467 getVectorElementPointer(StackPtr
, VecTy
, OutPos
.getReg(0));
8468 MIRBuilder
.buildStore(Val
, ElmtPtr
, ValPtrInfo
, ValAlign
);
8470 LLT MaskITy
= MaskTy
.getElementType();
8471 auto MaskI
= MIRBuilder
.buildExtractVectorElement(MaskITy
, Mask
, Idx
);
8472 if (MaskITy
.getSizeInBits() > 1)
8473 MaskI
= MIRBuilder
.buildTrunc(LLT::scalar(1), MaskI
);
8475 MaskI
= MIRBuilder
.buildZExt(IdxTy
, MaskI
);
8476 OutPos
= MIRBuilder
.buildAdd(IdxTy
, OutPos
, MaskI
);
8478 if (HasPassthru
&& I
== NumElmts
- 1) {
8480 MIRBuilder
.buildConstant(IdxTy
, VecTy
.getNumElements() - 1);
8481 auto AllLanesSelected
= MIRBuilder
.buildICmp(
8482 CmpInst::ICMP_UGT
, LLT::scalar(1), OutPos
, EndOfVector
);
8483 OutPos
= MIRBuilder
.buildInstr(TargetOpcode::G_UMIN
, {IdxTy
},
8484 {OutPos
, EndOfVector
});
8485 ElmtPtr
= getVectorElementPointer(StackPtr
, VecTy
, OutPos
.getReg(0));
8488 MIRBuilder
.buildSelect(ValTy
, AllLanesSelected
, Val
, LastWriteVal
)
8490 MIRBuilder
.buildStore(LastWriteVal
, ElmtPtr
, ValPtrInfo
, ValAlign
);
8494 // TODO: Use StackPtr's FrameIndex alignment.
8495 MIRBuilder
.buildLoad(Dst
, StackPtr
, PtrInfo
, VecAlign
);
8497 MI
.eraseFromParent();
8501 Register
LegalizerHelper::getDynStackAllocTargetPtr(Register SPReg
,
8505 LLT IntPtrTy
= LLT::scalar(PtrTy
.getSizeInBits());
8507 auto SPTmp
= MIRBuilder
.buildCopy(PtrTy
, SPReg
);
8508 SPTmp
= MIRBuilder
.buildCast(IntPtrTy
, SPTmp
);
8510 // Subtract the final alloc from the SP. We use G_PTRTOINT here so we don't
8511 // have to generate an extra instruction to negate the alloc and then use
8512 // G_PTR_ADD to add the negative offset.
8513 auto Alloc
= MIRBuilder
.buildSub(IntPtrTy
, SPTmp
, AllocSize
);
8514 if (Alignment
> Align(1)) {
8515 APInt
AlignMask(IntPtrTy
.getSizeInBits(), Alignment
.value(), true);
8517 auto AlignCst
= MIRBuilder
.buildConstant(IntPtrTy
, AlignMask
);
8518 Alloc
= MIRBuilder
.buildAnd(IntPtrTy
, Alloc
, AlignCst
);
8521 return MIRBuilder
.buildCast(PtrTy
, Alloc
).getReg(0);
8524 LegalizerHelper::LegalizeResult
8525 LegalizerHelper::lowerDynStackAlloc(MachineInstr
&MI
) {
8526 const auto &MF
= *MI
.getMF();
8527 const auto &TFI
= *MF
.getSubtarget().getFrameLowering();
8528 if (TFI
.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp
)
8529 return UnableToLegalize
;
8531 Register Dst
= MI
.getOperand(0).getReg();
8532 Register AllocSize
= MI
.getOperand(1).getReg();
8533 Align Alignment
= assumeAligned(MI
.getOperand(2).getImm());
8535 LLT PtrTy
= MRI
.getType(Dst
);
8536 Register SPReg
= TLI
.getStackPointerRegisterToSaveRestore();
8538 getDynStackAllocTargetPtr(SPReg
, AllocSize
, Alignment
, PtrTy
);
8540 MIRBuilder
.buildCopy(SPReg
, SPTmp
);
8541 MIRBuilder
.buildCopy(Dst
, SPTmp
);
8543 MI
.eraseFromParent();
8547 LegalizerHelper::LegalizeResult
8548 LegalizerHelper::lowerStackSave(MachineInstr
&MI
) {
8549 Register StackPtr
= TLI
.getStackPointerRegisterToSaveRestore();
8551 return UnableToLegalize
;
8553 MIRBuilder
.buildCopy(MI
.getOperand(0), StackPtr
);
8554 MI
.eraseFromParent();
8558 LegalizerHelper::LegalizeResult
8559 LegalizerHelper::lowerStackRestore(MachineInstr
&MI
) {
8560 Register StackPtr
= TLI
.getStackPointerRegisterToSaveRestore();
8562 return UnableToLegalize
;
8564 MIRBuilder
.buildCopy(StackPtr
, MI
.getOperand(0));
8565 MI
.eraseFromParent();
8569 LegalizerHelper::LegalizeResult
8570 LegalizerHelper::lowerExtract(MachineInstr
&MI
) {
8571 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
8572 unsigned Offset
= MI
.getOperand(2).getImm();
8574 // Extract sub-vector or one element
8575 if (SrcTy
.isVector()) {
8576 unsigned SrcEltSize
= SrcTy
.getElementType().getSizeInBits();
8577 unsigned DstSize
= DstTy
.getSizeInBits();
8579 if ((Offset
% SrcEltSize
== 0) && (DstSize
% SrcEltSize
== 0) &&
8580 (Offset
+ DstSize
<= SrcTy
.getSizeInBits())) {
8581 // Unmerge and allow access to each Src element for the artifact combiner.
8582 auto Unmerge
= MIRBuilder
.buildUnmerge(SrcTy
.getElementType(), SrcReg
);
8584 // Take element(s) we need to extract and copy it (merge them).
8585 SmallVector
<Register
, 8> SubVectorElts
;
8586 for (unsigned Idx
= Offset
/ SrcEltSize
;
8587 Idx
< (Offset
+ DstSize
) / SrcEltSize
; ++Idx
) {
8588 SubVectorElts
.push_back(Unmerge
.getReg(Idx
));
8590 if (SubVectorElts
.size() == 1)
8591 MIRBuilder
.buildCopy(DstReg
, SubVectorElts
[0]);
8593 MIRBuilder
.buildMergeLikeInstr(DstReg
, SubVectorElts
);
8595 MI
.eraseFromParent();
8600 if (DstTy
.isScalar() &&
8601 (SrcTy
.isScalar() ||
8602 (SrcTy
.isVector() && DstTy
== SrcTy
.getElementType()))) {
8603 LLT SrcIntTy
= SrcTy
;
8604 if (!SrcTy
.isScalar()) {
8605 SrcIntTy
= LLT::scalar(SrcTy
.getSizeInBits());
8606 SrcReg
= MIRBuilder
.buildBitcast(SrcIntTy
, SrcReg
).getReg(0);
8610 MIRBuilder
.buildTrunc(DstReg
, SrcReg
);
8612 auto ShiftAmt
= MIRBuilder
.buildConstant(SrcIntTy
, Offset
);
8613 auto Shr
= MIRBuilder
.buildLShr(SrcIntTy
, SrcReg
, ShiftAmt
);
8614 MIRBuilder
.buildTrunc(DstReg
, Shr
);
8617 MI
.eraseFromParent();
8621 return UnableToLegalize
;
8624 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerInsert(MachineInstr
&MI
) {
8625 auto [Dst
, Src
, InsertSrc
] = MI
.getFirst3Regs();
8626 uint64_t Offset
= MI
.getOperand(3).getImm();
8628 LLT DstTy
= MRI
.getType(Src
);
8629 LLT InsertTy
= MRI
.getType(InsertSrc
);
8631 // Insert sub-vector or one element
8632 if (DstTy
.isVector() && !InsertTy
.isPointer()) {
8633 LLT EltTy
= DstTy
.getElementType();
8634 unsigned EltSize
= EltTy
.getSizeInBits();
8635 unsigned InsertSize
= InsertTy
.getSizeInBits();
8637 if ((Offset
% EltSize
== 0) && (InsertSize
% EltSize
== 0) &&
8638 (Offset
+ InsertSize
<= DstTy
.getSizeInBits())) {
8639 auto UnmergeSrc
= MIRBuilder
.buildUnmerge(EltTy
, Src
);
8640 SmallVector
<Register
, 8> DstElts
;
8642 // Elements from Src before insert start Offset
8643 for (; Idx
< Offset
/ EltSize
; ++Idx
) {
8644 DstElts
.push_back(UnmergeSrc
.getReg(Idx
));
8647 // Replace elements in Src with elements from InsertSrc
8648 if (InsertTy
.getSizeInBits() > EltSize
) {
8649 auto UnmergeInsertSrc
= MIRBuilder
.buildUnmerge(EltTy
, InsertSrc
);
8650 for (unsigned i
= 0; Idx
< (Offset
+ InsertSize
) / EltSize
;
8652 DstElts
.push_back(UnmergeInsertSrc
.getReg(i
));
8655 DstElts
.push_back(InsertSrc
);
8659 // Remaining elements from Src after insert
8660 for (; Idx
< DstTy
.getNumElements(); ++Idx
) {
8661 DstElts
.push_back(UnmergeSrc
.getReg(Idx
));
8664 MIRBuilder
.buildMergeLikeInstr(Dst
, DstElts
);
8665 MI
.eraseFromParent();
8670 if (InsertTy
.isVector() ||
8671 (DstTy
.isVector() && DstTy
.getElementType() != InsertTy
))
8672 return UnableToLegalize
;
8674 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
8675 if ((DstTy
.isPointer() &&
8676 DL
.isNonIntegralAddressSpace(DstTy
.getAddressSpace())) ||
8677 (InsertTy
.isPointer() &&
8678 DL
.isNonIntegralAddressSpace(InsertTy
.getAddressSpace()))) {
8679 LLVM_DEBUG(dbgs() << "Not casting non-integral address space integer\n");
8680 return UnableToLegalize
;
8683 LLT IntDstTy
= DstTy
;
8685 if (!DstTy
.isScalar()) {
8686 IntDstTy
= LLT::scalar(DstTy
.getSizeInBits());
8687 Src
= MIRBuilder
.buildCast(IntDstTy
, Src
).getReg(0);
8690 if (!InsertTy
.isScalar()) {
8691 const LLT IntInsertTy
= LLT::scalar(InsertTy
.getSizeInBits());
8692 InsertSrc
= MIRBuilder
.buildPtrToInt(IntInsertTy
, InsertSrc
).getReg(0);
8695 Register ExtInsSrc
= MIRBuilder
.buildZExt(IntDstTy
, InsertSrc
).getReg(0);
8697 auto ShiftAmt
= MIRBuilder
.buildConstant(IntDstTy
, Offset
);
8698 ExtInsSrc
= MIRBuilder
.buildShl(IntDstTy
, ExtInsSrc
, ShiftAmt
).getReg(0);
8701 APInt MaskVal
= APInt::getBitsSetWithWrap(
8702 DstTy
.getSizeInBits(), Offset
+ InsertTy
.getSizeInBits(), Offset
);
8704 auto Mask
= MIRBuilder
.buildConstant(IntDstTy
, MaskVal
);
8705 auto MaskedSrc
= MIRBuilder
.buildAnd(IntDstTy
, Src
, Mask
);
8706 auto Or
= MIRBuilder
.buildOr(IntDstTy
, MaskedSrc
, ExtInsSrc
);
8708 MIRBuilder
.buildCast(Dst
, Or
);
8709 MI
.eraseFromParent();
8713 LegalizerHelper::LegalizeResult
8714 LegalizerHelper::lowerSADDO_SSUBO(MachineInstr
&MI
) {
8715 auto [Dst0
, Dst0Ty
, Dst1
, Dst1Ty
, LHS
, LHSTy
, RHS
, RHSTy
] =
8716 MI
.getFirst4RegLLTs();
8717 const bool IsAdd
= MI
.getOpcode() == TargetOpcode::G_SADDO
;
8720 LLT BoolTy
= Dst1Ty
;
8722 Register NewDst0
= MRI
.cloneVirtualRegister(Dst0
);
8725 MIRBuilder
.buildAdd(NewDst0
, LHS
, RHS
);
8727 MIRBuilder
.buildSub(NewDst0
, LHS
, RHS
);
8729 // TODO: If SADDSAT/SSUBSAT is legal, compare results to detect overflow.
8731 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
8733 // For an addition, the result should be less than one of the operands (LHS)
8734 // if and only if the other operand (RHS) is negative, otherwise there will
8736 // For a subtraction, the result should be less than one of the operands
8737 // (LHS) if and only if the other operand (RHS) is (non-zero) positive,
8738 // otherwise there will be overflow.
8739 auto ResultLowerThanLHS
=
8740 MIRBuilder
.buildICmp(CmpInst::ICMP_SLT
, BoolTy
, NewDst0
, LHS
);
8741 auto ConditionRHS
= MIRBuilder
.buildICmp(
8742 IsAdd
? CmpInst::ICMP_SLT
: CmpInst::ICMP_SGT
, BoolTy
, RHS
, Zero
);
8744 MIRBuilder
.buildXor(Dst1
, ConditionRHS
, ResultLowerThanLHS
);
8746 MIRBuilder
.buildCopy(Dst0
, NewDst0
);
8747 MI
.eraseFromParent();
8752 LegalizerHelper::LegalizeResult
8753 LegalizerHelper::lowerAddSubSatToMinMax(MachineInstr
&MI
) {
8754 auto [Res
, LHS
, RHS
] = MI
.getFirst3Regs();
8755 LLT Ty
= MRI
.getType(Res
);
8759 switch (MI
.getOpcode()) {
8761 llvm_unreachable("unexpected addsat/subsat opcode");
8762 case TargetOpcode::G_UADDSAT
:
8765 BaseOp
= TargetOpcode::G_ADD
;
8767 case TargetOpcode::G_SADDSAT
:
8770 BaseOp
= TargetOpcode::G_ADD
;
8772 case TargetOpcode::G_USUBSAT
:
8775 BaseOp
= TargetOpcode::G_SUB
;
8777 case TargetOpcode::G_SSUBSAT
:
8780 BaseOp
= TargetOpcode::G_SUB
;
8785 // sadd.sat(a, b) ->
8786 // hi = 0x7fffffff - smax(a, 0)
8787 // lo = 0x80000000 - smin(a, 0)
8788 // a + smin(smax(lo, b), hi)
8789 // ssub.sat(a, b) ->
8790 // lo = smax(a, -1) - 0x7fffffff
8791 // hi = smin(a, -1) - 0x80000000
8792 // a - smin(smax(lo, b), hi)
8793 // TODO: AMDGPU can use a "median of 3" instruction here:
8794 // a +/- med3(lo, b, hi)
8795 uint64_t NumBits
= Ty
.getScalarSizeInBits();
8797 MIRBuilder
.buildConstant(Ty
, APInt::getSignedMaxValue(NumBits
));
8799 MIRBuilder
.buildConstant(Ty
, APInt::getSignedMinValue(NumBits
));
8800 MachineInstrBuilder Hi
, Lo
;
8802 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
8803 Hi
= MIRBuilder
.buildSub(Ty
, MaxVal
, MIRBuilder
.buildSMax(Ty
, LHS
, Zero
));
8804 Lo
= MIRBuilder
.buildSub(Ty
, MinVal
, MIRBuilder
.buildSMin(Ty
, LHS
, Zero
));
8806 auto NegOne
= MIRBuilder
.buildConstant(Ty
, -1);
8807 Lo
= MIRBuilder
.buildSub(Ty
, MIRBuilder
.buildSMax(Ty
, LHS
, NegOne
),
8809 Hi
= MIRBuilder
.buildSub(Ty
, MIRBuilder
.buildSMin(Ty
, LHS
, NegOne
),
8813 MIRBuilder
.buildSMin(Ty
, MIRBuilder
.buildSMax(Ty
, Lo
, RHS
), Hi
);
8814 MIRBuilder
.buildInstr(BaseOp
, {Res
}, {LHS
, RHSClamped
});
8816 // uadd.sat(a, b) -> a + umin(~a, b)
8817 // usub.sat(a, b) -> a - umin(a, b)
8818 Register Not
= IsAdd
? MIRBuilder
.buildNot(Ty
, LHS
).getReg(0) : LHS
;
8819 auto Min
= MIRBuilder
.buildUMin(Ty
, Not
, RHS
);
8820 MIRBuilder
.buildInstr(BaseOp
, {Res
}, {LHS
, Min
});
8823 MI
.eraseFromParent();
8827 LegalizerHelper::LegalizeResult
8828 LegalizerHelper::lowerAddSubSatToAddoSubo(MachineInstr
&MI
) {
8829 auto [Res
, LHS
, RHS
] = MI
.getFirst3Regs();
8830 LLT Ty
= MRI
.getType(Res
);
8831 LLT BoolTy
= Ty
.changeElementSize(1);
8834 unsigned OverflowOp
;
8835 switch (MI
.getOpcode()) {
8837 llvm_unreachable("unexpected addsat/subsat opcode");
8838 case TargetOpcode::G_UADDSAT
:
8841 OverflowOp
= TargetOpcode::G_UADDO
;
8843 case TargetOpcode::G_SADDSAT
:
8846 OverflowOp
= TargetOpcode::G_SADDO
;
8848 case TargetOpcode::G_USUBSAT
:
8851 OverflowOp
= TargetOpcode::G_USUBO
;
8853 case TargetOpcode::G_SSUBSAT
:
8856 OverflowOp
= TargetOpcode::G_SSUBO
;
8861 MIRBuilder
.buildInstr(OverflowOp
, {Ty
, BoolTy
}, {LHS
, RHS
});
8862 Register Tmp
= OverflowRes
.getReg(0);
8863 Register Ov
= OverflowRes
.getReg(1);
8864 MachineInstrBuilder Clamp
;
8866 // sadd.sat(a, b) ->
8867 // {tmp, ov} = saddo(a, b)
8868 // ov ? (tmp >>s 31) + 0x80000000 : r
8869 // ssub.sat(a, b) ->
8870 // {tmp, ov} = ssubo(a, b)
8871 // ov ? (tmp >>s 31) + 0x80000000 : r
8872 uint64_t NumBits
= Ty
.getScalarSizeInBits();
8873 auto ShiftAmount
= MIRBuilder
.buildConstant(Ty
, NumBits
- 1);
8874 auto Sign
= MIRBuilder
.buildAShr(Ty
, Tmp
, ShiftAmount
);
8876 MIRBuilder
.buildConstant(Ty
, APInt::getSignedMinValue(NumBits
));
8877 Clamp
= MIRBuilder
.buildAdd(Ty
, Sign
, MinVal
);
8879 // uadd.sat(a, b) ->
8880 // {tmp, ov} = uaddo(a, b)
8881 // ov ? 0xffffffff : tmp
8882 // usub.sat(a, b) ->
8883 // {tmp, ov} = usubo(a, b)
8885 Clamp
= MIRBuilder
.buildConstant(Ty
, IsAdd
? -1 : 0);
8887 MIRBuilder
.buildSelect(Res
, Ov
, Clamp
, Tmp
);
8889 MI
.eraseFromParent();
8893 LegalizerHelper::LegalizeResult
8894 LegalizerHelper::lowerShlSat(MachineInstr
&MI
) {
8895 assert((MI
.getOpcode() == TargetOpcode::G_SSHLSAT
||
8896 MI
.getOpcode() == TargetOpcode::G_USHLSAT
) &&
8897 "Expected shlsat opcode!");
8898 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_SSHLSAT
;
8899 auto [Res
, LHS
, RHS
] = MI
.getFirst3Regs();
8900 LLT Ty
= MRI
.getType(Res
);
8901 LLT BoolTy
= Ty
.changeElementSize(1);
8903 unsigned BW
= Ty
.getScalarSizeInBits();
8904 auto Result
= MIRBuilder
.buildShl(Ty
, LHS
, RHS
);
8905 auto Orig
= IsSigned
? MIRBuilder
.buildAShr(Ty
, Result
, RHS
)
8906 : MIRBuilder
.buildLShr(Ty
, Result
, RHS
);
8908 MachineInstrBuilder SatVal
;
8910 auto SatMin
= MIRBuilder
.buildConstant(Ty
, APInt::getSignedMinValue(BW
));
8911 auto SatMax
= MIRBuilder
.buildConstant(Ty
, APInt::getSignedMaxValue(BW
));
8912 auto Cmp
= MIRBuilder
.buildICmp(CmpInst::ICMP_SLT
, BoolTy
, LHS
,
8913 MIRBuilder
.buildConstant(Ty
, 0));
8914 SatVal
= MIRBuilder
.buildSelect(Ty
, Cmp
, SatMin
, SatMax
);
8916 SatVal
= MIRBuilder
.buildConstant(Ty
, APInt::getMaxValue(BW
));
8918 auto Ov
= MIRBuilder
.buildICmp(CmpInst::ICMP_NE
, BoolTy
, LHS
, Orig
);
8919 MIRBuilder
.buildSelect(Res
, Ov
, SatVal
, Result
);
8921 MI
.eraseFromParent();
8925 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerBswap(MachineInstr
&MI
) {
8926 auto [Dst
, Src
] = MI
.getFirst2Regs();
8927 const LLT Ty
= MRI
.getType(Src
);
8928 unsigned SizeInBytes
= (Ty
.getScalarSizeInBits() + 7) / 8;
8929 unsigned BaseShiftAmt
= (SizeInBytes
- 1) * 8;
8931 // Swap most and least significant byte, set remaining bytes in Res to zero.
8932 auto ShiftAmt
= MIRBuilder
.buildConstant(Ty
, BaseShiftAmt
);
8933 auto LSByteShiftedLeft
= MIRBuilder
.buildShl(Ty
, Src
, ShiftAmt
);
8934 auto MSByteShiftedRight
= MIRBuilder
.buildLShr(Ty
, Src
, ShiftAmt
);
8935 auto Res
= MIRBuilder
.buildOr(Ty
, MSByteShiftedRight
, LSByteShiftedLeft
);
8937 // Set i-th high/low byte in Res to i-th low/high byte from Src.
8938 for (unsigned i
= 1; i
< SizeInBytes
/ 2; ++i
) {
8939 // AND with Mask leaves byte i unchanged and sets remaining bytes to 0.
8940 APInt
APMask(SizeInBytes
* 8, 0xFF << (i
* 8));
8941 auto Mask
= MIRBuilder
.buildConstant(Ty
, APMask
);
8942 auto ShiftAmt
= MIRBuilder
.buildConstant(Ty
, BaseShiftAmt
- 16 * i
);
8943 // Low byte shifted left to place of high byte: (Src & Mask) << ShiftAmt.
8944 auto LoByte
= MIRBuilder
.buildAnd(Ty
, Src
, Mask
);
8945 auto LoShiftedLeft
= MIRBuilder
.buildShl(Ty
, LoByte
, ShiftAmt
);
8946 Res
= MIRBuilder
.buildOr(Ty
, Res
, LoShiftedLeft
);
8947 // High byte shifted right to place of low byte: (Src >> ShiftAmt) & Mask.
8948 auto SrcShiftedRight
= MIRBuilder
.buildLShr(Ty
, Src
, ShiftAmt
);
8949 auto HiShiftedRight
= MIRBuilder
.buildAnd(Ty
, SrcShiftedRight
, Mask
);
8950 Res
= MIRBuilder
.buildOr(Ty
, Res
, HiShiftedRight
);
8952 Res
.getInstr()->getOperand(0).setReg(Dst
);
8954 MI
.eraseFromParent();
8958 //{ (Src & Mask) >> N } | { (Src << N) & Mask }
8959 static MachineInstrBuilder
SwapN(unsigned N
, DstOp Dst
, MachineIRBuilder
&B
,
8960 MachineInstrBuilder Src
, const APInt
&Mask
) {
8961 const LLT Ty
= Dst
.getLLTTy(*B
.getMRI());
8962 MachineInstrBuilder C_N
= B
.buildConstant(Ty
, N
);
8963 MachineInstrBuilder MaskLoNTo0
= B
.buildConstant(Ty
, Mask
);
8964 auto LHS
= B
.buildLShr(Ty
, B
.buildAnd(Ty
, Src
, MaskLoNTo0
), C_N
);
8965 auto RHS
= B
.buildAnd(Ty
, B
.buildShl(Ty
, Src
, C_N
), MaskLoNTo0
);
8966 return B
.buildOr(Dst
, LHS
, RHS
);
8969 LegalizerHelper::LegalizeResult
8970 LegalizerHelper::lowerBitreverse(MachineInstr
&MI
) {
8971 auto [Dst
, Src
] = MI
.getFirst2Regs();
8972 const LLT Ty
= MRI
.getType(Src
);
8973 unsigned Size
= Ty
.getScalarSizeInBits();
8976 MachineInstrBuilder BSWAP
=
8977 MIRBuilder
.buildInstr(TargetOpcode::G_BSWAP
, {Ty
}, {Src
});
8979 // swap high and low 4 bits in 8 bit blocks 7654|3210 -> 3210|7654
8980 // [(val & 0xF0F0F0F0) >> 4] | [(val & 0x0F0F0F0F) << 4]
8981 // -> [(val & 0xF0F0F0F0) >> 4] | [(val << 4) & 0xF0F0F0F0]
8982 MachineInstrBuilder Swap4
=
8983 SwapN(4, Ty
, MIRBuilder
, BSWAP
, APInt::getSplat(Size
, APInt(8, 0xF0)));
8985 // swap high and low 2 bits in 4 bit blocks 32|10 76|54 -> 10|32 54|76
8986 // [(val & 0xCCCCCCCC) >> 2] & [(val & 0x33333333) << 2]
8987 // -> [(val & 0xCCCCCCCC) >> 2] & [(val << 2) & 0xCCCCCCCC]
8988 MachineInstrBuilder Swap2
=
8989 SwapN(2, Ty
, MIRBuilder
, Swap4
, APInt::getSplat(Size
, APInt(8, 0xCC)));
8991 // swap high and low 1 bit in 2 bit blocks 1|0 3|2 5|4 7|6 -> 0|1 2|3 4|5
8993 // [(val & 0xAAAAAAAA) >> 1] & [(val & 0x55555555) << 1]
8994 // -> [(val & 0xAAAAAAAA) >> 1] & [(val << 1) & 0xAAAAAAAA]
8995 SwapN(1, Dst
, MIRBuilder
, Swap2
, APInt::getSplat(Size
, APInt(8, 0xAA)));
8997 // Expand bitreverse for types smaller than 8 bits.
8998 MachineInstrBuilder Tmp
;
8999 for (unsigned I
= 0, J
= Size
- 1; I
< Size
; ++I
, --J
) {
9000 MachineInstrBuilder Tmp2
;
9002 auto ShAmt
= MIRBuilder
.buildConstant(Ty
, J
- I
);
9003 Tmp2
= MIRBuilder
.buildShl(Ty
, Src
, ShAmt
);
9005 auto ShAmt
= MIRBuilder
.buildConstant(Ty
, I
- J
);
9006 Tmp2
= MIRBuilder
.buildLShr(Ty
, Src
, ShAmt
);
9009 auto Mask
= MIRBuilder
.buildConstant(Ty
, 1ULL << J
);
9010 Tmp2
= MIRBuilder
.buildAnd(Ty
, Tmp2
, Mask
);
9014 Tmp
= MIRBuilder
.buildOr(Ty
, Tmp
, Tmp2
);
9016 MIRBuilder
.buildCopy(Dst
, Tmp
);
9019 MI
.eraseFromParent();
9023 LegalizerHelper::LegalizeResult
9024 LegalizerHelper::lowerReadWriteRegister(MachineInstr
&MI
) {
9025 MachineFunction
&MF
= MIRBuilder
.getMF();
9027 bool IsRead
= MI
.getOpcode() == TargetOpcode::G_READ_REGISTER
;
9028 int NameOpIdx
= IsRead
? 1 : 0;
9029 int ValRegIndex
= IsRead
? 0 : 1;
9031 Register ValReg
= MI
.getOperand(ValRegIndex
).getReg();
9032 const LLT Ty
= MRI
.getType(ValReg
);
9033 const MDString
*RegStr
= cast
<MDString
>(
9034 cast
<MDNode
>(MI
.getOperand(NameOpIdx
).getMetadata())->getOperand(0));
9036 Register PhysReg
= TLI
.getRegisterByName(RegStr
->getString().data(), Ty
, MF
);
9037 if (!PhysReg
.isValid())
9038 return UnableToLegalize
;
9041 MIRBuilder
.buildCopy(ValReg
, PhysReg
);
9043 MIRBuilder
.buildCopy(PhysReg
, ValReg
);
9045 MI
.eraseFromParent();
9049 LegalizerHelper::LegalizeResult
9050 LegalizerHelper::lowerSMULH_UMULH(MachineInstr
&MI
) {
9051 bool IsSigned
= MI
.getOpcode() == TargetOpcode::G_SMULH
;
9052 unsigned ExtOp
= IsSigned
? TargetOpcode::G_SEXT
: TargetOpcode::G_ZEXT
;
9053 Register Result
= MI
.getOperand(0).getReg();
9054 LLT OrigTy
= MRI
.getType(Result
);
9055 auto SizeInBits
= OrigTy
.getScalarSizeInBits();
9056 LLT WideTy
= OrigTy
.changeElementSize(SizeInBits
* 2);
9058 auto LHS
= MIRBuilder
.buildInstr(ExtOp
, {WideTy
}, {MI
.getOperand(1)});
9059 auto RHS
= MIRBuilder
.buildInstr(ExtOp
, {WideTy
}, {MI
.getOperand(2)});
9060 auto Mul
= MIRBuilder
.buildMul(WideTy
, LHS
, RHS
);
9061 unsigned ShiftOp
= IsSigned
? TargetOpcode::G_ASHR
: TargetOpcode::G_LSHR
;
9063 auto ShiftAmt
= MIRBuilder
.buildConstant(WideTy
, SizeInBits
);
9064 auto Shifted
= MIRBuilder
.buildInstr(ShiftOp
, {WideTy
}, {Mul
, ShiftAmt
});
9065 MIRBuilder
.buildTrunc(Result
, Shifted
);
9067 MI
.eraseFromParent();
9071 LegalizerHelper::LegalizeResult
9072 LegalizerHelper::lowerISFPCLASS(MachineInstr
&MI
) {
9073 auto [DstReg
, DstTy
, SrcReg
, SrcTy
] = MI
.getFirst2RegLLTs();
9074 FPClassTest Mask
= static_cast<FPClassTest
>(MI
.getOperand(2).getImm());
9076 if (Mask
== fcNone
) {
9077 MIRBuilder
.buildConstant(DstReg
, 0);
9078 MI
.eraseFromParent();
9081 if (Mask
== fcAllFlags
) {
9082 MIRBuilder
.buildConstant(DstReg
, 1);
9083 MI
.eraseFromParent();
9087 // TODO: Try inverting the test with getInvertedFPClassTest like the DAG
9090 unsigned BitSize
= SrcTy
.getScalarSizeInBits();
9091 const fltSemantics
&Semantics
= getFltSemanticForLLT(SrcTy
.getScalarType());
9093 LLT IntTy
= LLT::scalar(BitSize
);
9094 if (SrcTy
.isVector())
9095 IntTy
= LLT::vector(SrcTy
.getElementCount(), IntTy
);
9096 auto AsInt
= MIRBuilder
.buildCopy(IntTy
, SrcReg
);
9099 APInt SignBit
= APInt::getSignMask(BitSize
);
9100 APInt ValueMask
= APInt::getSignedMaxValue(BitSize
); // All bits but sign.
9101 APInt Inf
= APFloat::getInf(Semantics
).bitcastToAPInt(); // Exp and int bit.
9102 APInt ExpMask
= Inf
;
9103 APInt AllOneMantissa
= APFloat::getLargest(Semantics
).bitcastToAPInt() & ~Inf
;
9105 APInt::getOneBitSet(BitSize
, AllOneMantissa
.getActiveBits() - 1);
9106 APInt InvertionMask
= APInt::getAllOnes(DstTy
.getScalarSizeInBits());
9108 auto SignBitC
= MIRBuilder
.buildConstant(IntTy
, SignBit
);
9109 auto ValueMaskC
= MIRBuilder
.buildConstant(IntTy
, ValueMask
);
9110 auto InfC
= MIRBuilder
.buildConstant(IntTy
, Inf
);
9111 auto ExpMaskC
= MIRBuilder
.buildConstant(IntTy
, ExpMask
);
9112 auto ZeroC
= MIRBuilder
.buildConstant(IntTy
, 0);
9114 auto Abs
= MIRBuilder
.buildAnd(IntTy
, AsInt
, ValueMaskC
);
9116 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_NE
, DstTy
, AsInt
, Abs
);
9118 auto Res
= MIRBuilder
.buildConstant(DstTy
, 0);
9119 // Clang doesn't support capture of structured bindings:
9120 LLT DstTyCopy
= DstTy
;
9121 const auto appendToRes
= [&](MachineInstrBuilder ToAppend
) {
9122 Res
= MIRBuilder
.buildOr(DstTyCopy
, Res
, ToAppend
);
9125 // Tests that involve more than one class should be processed first.
9126 if ((Mask
& fcFinite
) == fcFinite
) {
9127 // finite(V) ==> abs(V) u< exp_mask
9128 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
, Abs
,
9131 } else if ((Mask
& fcFinite
) == fcPosFinite
) {
9132 // finite(V) && V > 0 ==> V u< exp_mask
9133 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
, AsInt
,
9135 Mask
&= ~fcPosFinite
;
9136 } else if ((Mask
& fcFinite
) == fcNegFinite
) {
9137 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
9138 auto Cmp
= MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
, Abs
,
9140 auto And
= MIRBuilder
.buildAnd(DstTy
, Cmp
, Sign
);
9142 Mask
&= ~fcNegFinite
;
9145 if (FPClassTest PartialCheck
= Mask
& (fcZero
| fcSubnormal
)) {
9146 // fcZero | fcSubnormal => test all exponent bits are 0
9147 // TODO: Handle sign bit specific cases
9148 // TODO: Handle inverted case
9149 if (PartialCheck
== (fcZero
| fcSubnormal
)) {
9150 auto ExpBits
= MIRBuilder
.buildAnd(IntTy
, AsInt
, ExpMaskC
);
9151 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
,
9153 Mask
&= ~PartialCheck
;
9157 // Check for individual classes.
9158 if (FPClassTest PartialCheck
= Mask
& fcZero
) {
9159 if (PartialCheck
== fcPosZero
)
9160 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
,
9162 else if (PartialCheck
== fcZero
)
9164 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
, Abs
, ZeroC
));
9166 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
,
9170 if (FPClassTest PartialCheck
= Mask
& fcSubnormal
) {
9171 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
9172 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
9173 auto V
= (PartialCheck
== fcPosSubnormal
) ? AsInt
: Abs
;
9174 auto OneC
= MIRBuilder
.buildConstant(IntTy
, 1);
9175 auto VMinusOne
= MIRBuilder
.buildSub(IntTy
, V
, OneC
);
9177 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
, VMinusOne
,
9178 MIRBuilder
.buildConstant(IntTy
, AllOneMantissa
));
9179 if (PartialCheck
== fcNegSubnormal
)
9180 SubnormalRes
= MIRBuilder
.buildAnd(DstTy
, SubnormalRes
, Sign
);
9181 appendToRes(SubnormalRes
);
9184 if (FPClassTest PartialCheck
= Mask
& fcInf
) {
9185 if (PartialCheck
== fcPosInf
)
9186 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
,
9188 else if (PartialCheck
== fcInf
)
9190 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
, Abs
, InfC
));
9192 APInt NegInf
= APFloat::getInf(Semantics
, true).bitcastToAPInt();
9193 auto NegInfC
= MIRBuilder
.buildConstant(IntTy
, NegInf
);
9194 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_EQ
, DstTy
,
9199 if (FPClassTest PartialCheck
= Mask
& fcNan
) {
9200 auto InfWithQnanBitC
= MIRBuilder
.buildConstant(IntTy
, Inf
| QNaNBitMask
);
9201 if (PartialCheck
== fcNan
) {
9202 // isnan(V) ==> abs(V) u> int(inf)
9204 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_UGT
, DstTy
, Abs
, InfC
));
9205 } else if (PartialCheck
== fcQNan
) {
9206 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
9207 appendToRes(MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_UGE
, DstTy
, Abs
,
9210 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
9211 // abs(V) u< (unsigned(Inf) | quiet_bit)
9213 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_UGT
, DstTy
, Abs
, InfC
);
9214 auto IsNotQnan
= MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
,
9215 Abs
, InfWithQnanBitC
);
9216 appendToRes(MIRBuilder
.buildAnd(DstTy
, IsNan
, IsNotQnan
));
9220 if (FPClassTest PartialCheck
= Mask
& fcNormal
) {
9221 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
9223 APInt ExpLSB
= ExpMask
& ~(ExpMask
.shl(1));
9224 auto ExpMinusOne
= MIRBuilder
.buildSub(
9225 IntTy
, Abs
, MIRBuilder
.buildConstant(IntTy
, ExpLSB
));
9226 APInt MaxExpMinusOne
= ExpMask
- ExpLSB
;
9228 MIRBuilder
.buildICmp(CmpInst::Predicate::ICMP_ULT
, DstTy
, ExpMinusOne
,
9229 MIRBuilder
.buildConstant(IntTy
, MaxExpMinusOne
));
9230 if (PartialCheck
== fcNegNormal
)
9231 NormalRes
= MIRBuilder
.buildAnd(DstTy
, NormalRes
, Sign
);
9232 else if (PartialCheck
== fcPosNormal
) {
9233 auto PosSign
= MIRBuilder
.buildXor(
9234 DstTy
, Sign
, MIRBuilder
.buildConstant(DstTy
, InvertionMask
));
9235 NormalRes
= MIRBuilder
.buildAnd(DstTy
, NormalRes
, PosSign
);
9237 appendToRes(NormalRes
);
9240 MIRBuilder
.buildCopy(DstReg
, Res
);
9241 MI
.eraseFromParent();
9245 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerSelect(MachineInstr
&MI
) {
9246 // Implement G_SELECT in terms of XOR, AND, OR.
9247 auto [DstReg
, DstTy
, MaskReg
, MaskTy
, Op1Reg
, Op1Ty
, Op2Reg
, Op2Ty
] =
9248 MI
.getFirst4RegLLTs();
9250 bool IsEltPtr
= DstTy
.isPointerOrPointerVector();
9252 LLT ScalarPtrTy
= LLT::scalar(DstTy
.getScalarSizeInBits());
9253 LLT NewTy
= DstTy
.changeElementType(ScalarPtrTy
);
9254 Op1Reg
= MIRBuilder
.buildPtrToInt(NewTy
, Op1Reg
).getReg(0);
9255 Op2Reg
= MIRBuilder
.buildPtrToInt(NewTy
, Op2Reg
).getReg(0);
9259 if (MaskTy
.isScalar()) {
9260 // Turn the scalar condition into a vector condition mask if needed.
9262 Register MaskElt
= MaskReg
;
9264 // The condition was potentially zero extended before, but we want a sign
9265 // extended boolean.
9266 if (MaskTy
!= LLT::scalar(1))
9267 MaskElt
= MIRBuilder
.buildSExtInReg(MaskTy
, MaskElt
, 1).getReg(0);
9269 // Continue the sign extension (or truncate) to match the data type.
9271 MIRBuilder
.buildSExtOrTrunc(DstTy
.getScalarType(), MaskElt
).getReg(0);
9273 if (DstTy
.isVector()) {
9274 // Generate a vector splat idiom.
9275 auto ShufSplat
= MIRBuilder
.buildShuffleSplat(DstTy
, MaskElt
);
9276 MaskReg
= ShufSplat
.getReg(0);
9281 } else if (!DstTy
.isVector()) {
9282 // Cannot handle the case that mask is a vector and dst is a scalar.
9283 return UnableToLegalize
;
9286 if (MaskTy
.getSizeInBits() != DstTy
.getSizeInBits()) {
9287 return UnableToLegalize
;
9290 auto NotMask
= MIRBuilder
.buildNot(MaskTy
, MaskReg
);
9291 auto NewOp1
= MIRBuilder
.buildAnd(MaskTy
, Op1Reg
, MaskReg
);
9292 auto NewOp2
= MIRBuilder
.buildAnd(MaskTy
, Op2Reg
, NotMask
);
9294 auto Or
= MIRBuilder
.buildOr(DstTy
, NewOp1
, NewOp2
);
9295 MIRBuilder
.buildIntToPtr(DstReg
, Or
);
9297 MIRBuilder
.buildOr(DstReg
, NewOp1
, NewOp2
);
9299 MI
.eraseFromParent();
9303 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerDIVREM(MachineInstr
&MI
) {
9304 // Split DIVREM into individual instructions.
9305 unsigned Opcode
= MI
.getOpcode();
9307 MIRBuilder
.buildInstr(
9308 Opcode
== TargetOpcode::G_SDIVREM
? TargetOpcode::G_SDIV
9309 : TargetOpcode::G_UDIV
,
9310 {MI
.getOperand(0).getReg()}, {MI
.getOperand(2), MI
.getOperand(3)});
9311 MIRBuilder
.buildInstr(
9312 Opcode
== TargetOpcode::G_SDIVREM
? TargetOpcode::G_SREM
9313 : TargetOpcode::G_UREM
,
9314 {MI
.getOperand(1).getReg()}, {MI
.getOperand(2), MI
.getOperand(3)});
9315 MI
.eraseFromParent();
9319 LegalizerHelper::LegalizeResult
9320 LegalizerHelper::lowerAbsToAddXor(MachineInstr
&MI
) {
9321 // Expand %res = G_ABS %a into:
9322 // %v1 = G_ASHR %a, scalar_size-1
9323 // %v2 = G_ADD %a, %v1
9324 // %res = G_XOR %v2, %v1
9325 LLT DstTy
= MRI
.getType(MI
.getOperand(0).getReg());
9326 Register OpReg
= MI
.getOperand(1).getReg();
9328 MIRBuilder
.buildConstant(DstTy
, DstTy
.getScalarSizeInBits() - 1);
9329 auto Shift
= MIRBuilder
.buildAShr(DstTy
, OpReg
, ShiftAmt
);
9330 auto Add
= MIRBuilder
.buildAdd(DstTy
, OpReg
, Shift
);
9331 MIRBuilder
.buildXor(MI
.getOperand(0).getReg(), Add
, Shift
);
9332 MI
.eraseFromParent();
9336 LegalizerHelper::LegalizeResult
9337 LegalizerHelper::lowerAbsToMaxNeg(MachineInstr
&MI
) {
9338 // Expand %res = G_ABS %a into:
9339 // %v1 = G_CONSTANT 0
9340 // %v2 = G_SUB %v1, %a
9341 // %res = G_SMAX %a, %v2
9342 Register SrcReg
= MI
.getOperand(1).getReg();
9343 LLT Ty
= MRI
.getType(SrcReg
);
9344 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0);
9345 auto Sub
= MIRBuilder
.buildSub(Ty
, Zero
, SrcReg
);
9346 MIRBuilder
.buildSMax(MI
.getOperand(0), SrcReg
, Sub
);
9347 MI
.eraseFromParent();
9351 LegalizerHelper::LegalizeResult
9352 LegalizerHelper::lowerAbsToCNeg(MachineInstr
&MI
) {
9353 Register SrcReg
= MI
.getOperand(1).getReg();
9354 Register DestReg
= MI
.getOperand(0).getReg();
9355 LLT Ty
= MRI
.getType(SrcReg
), IType
= LLT::scalar(1);
9356 auto Zero
= MIRBuilder
.buildConstant(Ty
, 0).getReg(0);
9357 auto Sub
= MIRBuilder
.buildSub(Ty
, Zero
, SrcReg
).getReg(0);
9358 auto ICmp
= MIRBuilder
.buildICmp(CmpInst::ICMP_SGT
, IType
, SrcReg
, Zero
);
9359 MIRBuilder
.buildSelect(DestReg
, ICmp
, SrcReg
, Sub
);
9360 MI
.eraseFromParent();
9364 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerFAbs(MachineInstr
&MI
) {
9365 Register SrcReg
= MI
.getOperand(1).getReg();
9366 Register DstReg
= MI
.getOperand(0).getReg();
9368 LLT Ty
= MRI
.getType(DstReg
);
9371 MIRBuilder
.buildAnd(
9373 MIRBuilder
.buildConstant(
9374 Ty
, APInt::getSignedMaxValue(Ty
.getScalarSizeInBits())));
9376 MI
.eraseFromParent();
9380 LegalizerHelper::LegalizeResult
9381 LegalizerHelper::lowerVectorReduction(MachineInstr
&MI
) {
9382 Register SrcReg
= MI
.getOperand(1).getReg();
9383 LLT SrcTy
= MRI
.getType(SrcReg
);
9384 LLT DstTy
= MRI
.getType(SrcReg
);
9386 // The source could be a scalar if the IR type was <1 x sN>.
9387 if (SrcTy
.isScalar()) {
9388 if (DstTy
.getSizeInBits() > SrcTy
.getSizeInBits())
9389 return UnableToLegalize
; // FIXME: handle extension.
9390 // This can be just a plain copy.
9391 Observer
.changingInstr(MI
);
9392 MI
.setDesc(MIRBuilder
.getTII().get(TargetOpcode::COPY
));
9393 Observer
.changedInstr(MI
);
9396 return UnableToLegalize
;
9399 LegalizerHelper::LegalizeResult
LegalizerHelper::lowerVAArg(MachineInstr
&MI
) {
9400 MachineFunction
&MF
= *MI
.getMF();
9401 const DataLayout
&DL
= MIRBuilder
.getDataLayout();
9402 LLVMContext
&Ctx
= MF
.getFunction().getContext();
9403 Register ListPtr
= MI
.getOperand(1).getReg();
9404 LLT PtrTy
= MRI
.getType(ListPtr
);
9406 // LstPtr is a pointer to the head of the list. Get the address
9407 // of the head of the list.
9408 Align PtrAlignment
= DL
.getABITypeAlign(getTypeForLLT(PtrTy
, Ctx
));
9409 MachineMemOperand
*PtrLoadMMO
= MF
.getMachineMemOperand(
9410 MachinePointerInfo(), MachineMemOperand::MOLoad
, PtrTy
, PtrAlignment
);
9411 auto VAList
= MIRBuilder
.buildLoad(PtrTy
, ListPtr
, *PtrLoadMMO
).getReg(0);
9413 const Align
A(MI
.getOperand(2).getImm());
9414 LLT PtrTyAsScalarTy
= LLT::scalar(PtrTy
.getSizeInBits());
9415 if (A
> TLI
.getMinStackArgumentAlignment()) {
9417 MIRBuilder
.buildConstant(PtrTyAsScalarTy
, A
.value() - 1).getReg(0);
9418 auto AddDst
= MIRBuilder
.buildPtrAdd(PtrTy
, VAList
, AlignAmt
);
9419 auto AndDst
= MIRBuilder
.buildMaskLowPtrBits(PtrTy
, AddDst
, Log2(A
));
9420 VAList
= AndDst
.getReg(0);
9423 // Increment the pointer, VAList, to the next vaarg
9424 // The list should be bumped by the size of element in the current head of
9426 Register Dst
= MI
.getOperand(0).getReg();
9427 LLT LLTTy
= MRI
.getType(Dst
);
9428 Type
*Ty
= getTypeForLLT(LLTTy
, Ctx
);
9430 MIRBuilder
.buildConstant(PtrTyAsScalarTy
, DL
.getTypeAllocSize(Ty
));
9431 auto Succ
= MIRBuilder
.buildPtrAdd(PtrTy
, VAList
, IncAmt
);
9433 // Store the increment VAList to the legalized pointer
9434 MachineMemOperand
*StoreMMO
= MF
.getMachineMemOperand(
9435 MachinePointerInfo(), MachineMemOperand::MOStore
, PtrTy
, PtrAlignment
);
9436 MIRBuilder
.buildStore(Succ
, ListPtr
, *StoreMMO
);
9437 // Load the actual argument out of the pointer VAList
9438 Align EltAlignment
= DL
.getABITypeAlign(Ty
);
9439 MachineMemOperand
*EltLoadMMO
= MF
.getMachineMemOperand(
9440 MachinePointerInfo(), MachineMemOperand::MOLoad
, LLTTy
, EltAlignment
);
9441 MIRBuilder
.buildLoad(Dst
, VAList
, *EltLoadMMO
);
9443 MI
.eraseFromParent();
9447 static bool shouldLowerMemFuncForSize(const MachineFunction
&MF
) {
9448 // On Darwin, -Os means optimize for size without hurting performance, so
9449 // only really optimize for size when -Oz (MinSize) is used.
9450 if (MF
.getTarget().getTargetTriple().isOSDarwin())
9451 return MF
.getFunction().hasMinSize();
9452 return MF
.getFunction().hasOptSize();
9455 // Returns a list of types to use for memory op lowering in MemOps. A partial
9456 // port of findOptimalMemOpLowering in TargetLowering.
9457 static bool findGISelOptimalMemOpLowering(std::vector
<LLT
> &MemOps
,
9458 unsigned Limit
, const MemOp
&Op
,
9459 unsigned DstAS
, unsigned SrcAS
,
9460 const AttributeList
&FuncAttributes
,
9461 const TargetLowering
&TLI
) {
9462 if (Op
.isMemcpyWithFixedDstAlign() && Op
.getSrcAlign() < Op
.getDstAlign())
9465 LLT Ty
= TLI
.getOptimalMemOpLLT(Op
, FuncAttributes
);
9468 // Use the largest scalar type whose alignment constraints are satisfied.
9469 // We only need to check DstAlign here as SrcAlign is always greater or
9470 // equal to DstAlign (or zero).
9471 Ty
= LLT::scalar(64);
9472 if (Op
.isFixedDstAlign())
9473 while (Op
.getDstAlign() < Ty
.getSizeInBytes() &&
9474 !TLI
.allowsMisalignedMemoryAccesses(Ty
, DstAS
, Op
.getDstAlign()))
9475 Ty
= LLT::scalar(Ty
.getSizeInBytes());
9476 assert(Ty
.getSizeInBits() > 0 && "Could not find valid type");
9477 // FIXME: check for the largest legal type we can load/store to.
9480 unsigned NumMemOps
= 0;
9481 uint64_t Size
= Op
.size();
9483 unsigned TySize
= Ty
.getSizeInBytes();
9484 while (TySize
> Size
) {
9485 // For now, only use non-vector load / store's for the left-over pieces.
9487 // FIXME: check for mem op safety and legality of the types. Not all of
9488 // SDAGisms map cleanly to GISel concepts.
9489 if (NewTy
.isVector())
9490 NewTy
= NewTy
.getSizeInBits() > 64 ? LLT::scalar(64) : LLT::scalar(32);
9491 NewTy
= LLT::scalar(llvm::bit_floor(NewTy
.getSizeInBits() - 1));
9492 unsigned NewTySize
= NewTy
.getSizeInBytes();
9493 assert(NewTySize
> 0 && "Could not find appropriate type");
9495 // If the new LLT cannot cover all of the remaining bits, then consider
9496 // issuing a (or a pair of) unaligned and overlapping load / store.
9498 // Need to get a VT equivalent for allowMisalignedMemoryAccesses().
9499 MVT VT
= getMVTForLLT(Ty
);
9500 if (NumMemOps
&& Op
.allowOverlap() && NewTySize
< Size
&&
9501 TLI
.allowsMisalignedMemoryAccesses(
9502 VT
, DstAS
, Op
.isFixedDstAlign() ? Op
.getDstAlign() : Align(1),
9503 MachineMemOperand::MONone
, &Fast
) &&
9512 if (++NumMemOps
> Limit
)
9515 MemOps
.push_back(Ty
);
9522 // Get a vectorized representation of the memset value operand, GISel edition.
9523 static Register
getMemsetValue(Register Val
, LLT Ty
, MachineIRBuilder
&MIB
) {
9524 MachineRegisterInfo
&MRI
= *MIB
.getMRI();
9525 unsigned NumBits
= Ty
.getScalarSizeInBits();
9526 auto ValVRegAndVal
= getIConstantVRegValWithLookThrough(Val
, MRI
);
9527 if (!Ty
.isVector() && ValVRegAndVal
) {
9528 APInt Scalar
= ValVRegAndVal
->Value
.trunc(8);
9529 APInt SplatVal
= APInt::getSplat(NumBits
, Scalar
);
9530 return MIB
.buildConstant(Ty
, SplatVal
).getReg(0);
9533 // Extend the byte value to the larger type, and then multiply by a magic
9534 // value 0x010101... in order to replicate it across every byte.
9535 // Unless it's zero, in which case just emit a larger G_CONSTANT 0.
9536 if (ValVRegAndVal
&& ValVRegAndVal
->Value
== 0) {
9537 return MIB
.buildConstant(Ty
, 0).getReg(0);
9540 LLT ExtType
= Ty
.getScalarType();
9541 auto ZExt
= MIB
.buildZExtOrTrunc(ExtType
, Val
);
9543 APInt Magic
= APInt::getSplat(NumBits
, APInt(8, 0x01));
9544 auto MagicMI
= MIB
.buildConstant(ExtType
, Magic
);
9545 Val
= MIB
.buildMul(ExtType
, ZExt
, MagicMI
).getReg(0);
9548 // For vector types create a G_BUILD_VECTOR.
9550 Val
= MIB
.buildSplatBuildVector(Ty
, Val
).getReg(0);
9555 LegalizerHelper::LegalizeResult
9556 LegalizerHelper::lowerMemset(MachineInstr
&MI
, Register Dst
, Register Val
,
9557 uint64_t KnownLen
, Align Alignment
,
9559 auto &MF
= *MI
.getParent()->getParent();
9560 const auto &TLI
= *MF
.getSubtarget().getTargetLowering();
9561 auto &DL
= MF
.getDataLayout();
9562 LLVMContext
&C
= MF
.getFunction().getContext();
9564 assert(KnownLen
!= 0 && "Have a zero length memset length!");
9566 bool DstAlignCanChange
= false;
9567 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
9568 bool OptSize
= shouldLowerMemFuncForSize(MF
);
9570 MachineInstr
*FIDef
= getOpcodeDef(TargetOpcode::G_FRAME_INDEX
, Dst
, MRI
);
9571 if (FIDef
&& !MFI
.isFixedObjectIndex(FIDef
->getOperand(1).getIndex()))
9572 DstAlignCanChange
= true;
9574 unsigned Limit
= TLI
.getMaxStoresPerMemset(OptSize
);
9575 std::vector
<LLT
> MemOps
;
9577 const auto &DstMMO
= **MI
.memoperands_begin();
9578 MachinePointerInfo DstPtrInfo
= DstMMO
.getPointerInfo();
9580 auto ValVRegAndVal
= getIConstantVRegValWithLookThrough(Val
, MRI
);
9581 bool IsZeroVal
= ValVRegAndVal
&& ValVRegAndVal
->Value
== 0;
9583 if (!findGISelOptimalMemOpLowering(MemOps
, Limit
,
9584 MemOp::Set(KnownLen
, DstAlignCanChange
,
9586 /*IsZeroMemset=*/IsZeroVal
,
9587 /*IsVolatile=*/IsVolatile
),
9588 DstPtrInfo
.getAddrSpace(), ~0u,
9589 MF
.getFunction().getAttributes(), TLI
))
9590 return UnableToLegalize
;
9592 if (DstAlignCanChange
) {
9593 // Get an estimate of the type from the LLT.
9594 Type
*IRTy
= getTypeForLLT(MemOps
[0], C
);
9595 Align NewAlign
= DL
.getABITypeAlign(IRTy
);
9596 if (NewAlign
> Alignment
) {
9597 Alignment
= NewAlign
;
9598 unsigned FI
= FIDef
->getOperand(1).getIndex();
9599 // Give the stack frame object a larger alignment if needed.
9600 if (MFI
.getObjectAlign(FI
) < Alignment
)
9601 MFI
.setObjectAlignment(FI
, Alignment
);
9605 MachineIRBuilder
MIB(MI
);
9606 // Find the largest store and generate the bit pattern for it.
9607 LLT LargestTy
= MemOps
[0];
9608 for (unsigned i
= 1; i
< MemOps
.size(); i
++)
9609 if (MemOps
[i
].getSizeInBits() > LargestTy
.getSizeInBits())
9610 LargestTy
= MemOps
[i
];
9612 // The memset stored value is always defined as an s8, so in order to make it
9613 // work with larger store types we need to repeat the bit pattern across the
9615 Register MemSetValue
= getMemsetValue(Val
, LargestTy
, MIB
);
9618 return UnableToLegalize
;
9620 // Generate the stores. For each store type in the list, we generate the
9621 // matching store of that type to the destination address.
9622 LLT PtrTy
= MRI
.getType(Dst
);
9623 unsigned DstOff
= 0;
9624 unsigned Size
= KnownLen
;
9625 for (unsigned I
= 0; I
< MemOps
.size(); I
++) {
9627 unsigned TySize
= Ty
.getSizeInBytes();
9628 if (TySize
> Size
) {
9629 // Issuing an unaligned load / store pair that overlaps with the previous
9630 // pair. Adjust the offset accordingly.
9631 assert(I
== MemOps
.size() - 1 && I
!= 0);
9632 DstOff
-= TySize
- Size
;
9635 // If this store is smaller than the largest store see whether we can get
9636 // the smaller value for free with a truncate.
9637 Register Value
= MemSetValue
;
9638 if (Ty
.getSizeInBits() < LargestTy
.getSizeInBits()) {
9639 MVT VT
= getMVTForLLT(Ty
);
9640 MVT LargestVT
= getMVTForLLT(LargestTy
);
9641 if (!LargestTy
.isVector() && !Ty
.isVector() &&
9642 TLI
.isTruncateFree(LargestVT
, VT
))
9643 Value
= MIB
.buildTrunc(Ty
, MemSetValue
).getReg(0);
9645 Value
= getMemsetValue(Val
, Ty
, MIB
);
9647 return UnableToLegalize
;
9650 auto *StoreMMO
= MF
.getMachineMemOperand(&DstMMO
, DstOff
, Ty
);
9655 MIB
.buildConstant(LLT::scalar(PtrTy
.getSizeInBits()), DstOff
);
9656 Ptr
= MIB
.buildPtrAdd(PtrTy
, Dst
, Offset
).getReg(0);
9659 MIB
.buildStore(Value
, Ptr
, *StoreMMO
);
9660 DstOff
+= Ty
.getSizeInBytes();
9664 MI
.eraseFromParent();
9668 LegalizerHelper::LegalizeResult
9669 LegalizerHelper::lowerMemcpyInline(MachineInstr
&MI
) {
9670 assert(MI
.getOpcode() == TargetOpcode::G_MEMCPY_INLINE
);
9672 auto [Dst
, Src
, Len
] = MI
.getFirst3Regs();
9674 const auto *MMOIt
= MI
.memoperands_begin();
9675 const MachineMemOperand
*MemOp
= *MMOIt
;
9676 bool IsVolatile
= MemOp
->isVolatile();
9678 // See if this is a constant length copy
9679 auto LenVRegAndVal
= getIConstantVRegValWithLookThrough(Len
, MRI
);
9680 // FIXME: support dynamically sized G_MEMCPY_INLINE
9681 assert(LenVRegAndVal
&&
9682 "inline memcpy with dynamic size is not yet supported");
9683 uint64_t KnownLen
= LenVRegAndVal
->Value
.getZExtValue();
9684 if (KnownLen
== 0) {
9685 MI
.eraseFromParent();
9689 const auto &DstMMO
= **MI
.memoperands_begin();
9690 const auto &SrcMMO
= **std::next(MI
.memoperands_begin());
9691 Align DstAlign
= DstMMO
.getBaseAlign();
9692 Align SrcAlign
= SrcMMO
.getBaseAlign();
9694 return lowerMemcpyInline(MI
, Dst
, Src
, KnownLen
, DstAlign
, SrcAlign
,
9698 LegalizerHelper::LegalizeResult
9699 LegalizerHelper::lowerMemcpyInline(MachineInstr
&MI
, Register Dst
, Register Src
,
9700 uint64_t KnownLen
, Align DstAlign
,
9701 Align SrcAlign
, bool IsVolatile
) {
9702 assert(MI
.getOpcode() == TargetOpcode::G_MEMCPY_INLINE
);
9703 return lowerMemcpy(MI
, Dst
, Src
, KnownLen
,
9704 std::numeric_limits
<uint64_t>::max(), DstAlign
, SrcAlign
,
9708 LegalizerHelper::LegalizeResult
9709 LegalizerHelper::lowerMemcpy(MachineInstr
&MI
, Register Dst
, Register Src
,
9710 uint64_t KnownLen
, uint64_t Limit
, Align DstAlign
,
9711 Align SrcAlign
, bool IsVolatile
) {
9712 auto &MF
= *MI
.getParent()->getParent();
9713 const auto &TLI
= *MF
.getSubtarget().getTargetLowering();
9714 auto &DL
= MF
.getDataLayout();
9715 LLVMContext
&C
= MF
.getFunction().getContext();
9717 assert(KnownLen
!= 0 && "Have a zero length memcpy length!");
9719 bool DstAlignCanChange
= false;
9720 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
9721 Align Alignment
= std::min(DstAlign
, SrcAlign
);
9723 MachineInstr
*FIDef
= getOpcodeDef(TargetOpcode::G_FRAME_INDEX
, Dst
, MRI
);
9724 if (FIDef
&& !MFI
.isFixedObjectIndex(FIDef
->getOperand(1).getIndex()))
9725 DstAlignCanChange
= true;
9727 // FIXME: infer better src pointer alignment like SelectionDAG does here.
9728 // FIXME: also use the equivalent of isMemSrcFromConstant and alwaysinlining
9729 // if the memcpy is in a tail call position.
9731 std::vector
<LLT
> MemOps
;
9733 const auto &DstMMO
= **MI
.memoperands_begin();
9734 const auto &SrcMMO
= **std::next(MI
.memoperands_begin());
9735 MachinePointerInfo DstPtrInfo
= DstMMO
.getPointerInfo();
9736 MachinePointerInfo SrcPtrInfo
= SrcMMO
.getPointerInfo();
9738 if (!findGISelOptimalMemOpLowering(
9740 MemOp::Copy(KnownLen
, DstAlignCanChange
, Alignment
, SrcAlign
,
9742 DstPtrInfo
.getAddrSpace(), SrcPtrInfo
.getAddrSpace(),
9743 MF
.getFunction().getAttributes(), TLI
))
9744 return UnableToLegalize
;
9746 if (DstAlignCanChange
) {
9747 // Get an estimate of the type from the LLT.
9748 Type
*IRTy
= getTypeForLLT(MemOps
[0], C
);
9749 Align NewAlign
= DL
.getABITypeAlign(IRTy
);
9751 // Don't promote to an alignment that would require dynamic stack
9753 const TargetRegisterInfo
*TRI
= MF
.getSubtarget().getRegisterInfo();
9754 if (!TRI
->hasStackRealignment(MF
))
9755 if (MaybeAlign StackAlign
= DL
.getStackAlignment())
9756 NewAlign
= std::min(NewAlign
, *StackAlign
);
9758 if (NewAlign
> Alignment
) {
9759 Alignment
= NewAlign
;
9760 unsigned FI
= FIDef
->getOperand(1).getIndex();
9761 // Give the stack frame object a larger alignment if needed.
9762 if (MFI
.getObjectAlign(FI
) < Alignment
)
9763 MFI
.setObjectAlignment(FI
, Alignment
);
9767 LLVM_DEBUG(dbgs() << "Inlining memcpy: " << MI
<< " into loads & stores\n");
9769 MachineIRBuilder
MIB(MI
);
9770 // Now we need to emit a pair of load and stores for each of the types we've
9771 // collected. I.e. for each type, generate a load from the source pointer of
9772 // that type width, and then generate a corresponding store to the dest buffer
9773 // of that value loaded. This can result in a sequence of loads and stores
9774 // mixed types, depending on what the target specifies as good types to use.
9775 unsigned CurrOffset
= 0;
9776 unsigned Size
= KnownLen
;
9777 for (auto CopyTy
: MemOps
) {
9778 // Issuing an unaligned load / store pair that overlaps with the previous
9779 // pair. Adjust the offset accordingly.
9780 if (CopyTy
.getSizeInBytes() > Size
)
9781 CurrOffset
-= CopyTy
.getSizeInBytes() - Size
;
9783 // Construct MMOs for the accesses.
9785 MF
.getMachineMemOperand(&SrcMMO
, CurrOffset
, CopyTy
.getSizeInBytes());
9787 MF
.getMachineMemOperand(&DstMMO
, CurrOffset
, CopyTy
.getSizeInBytes());
9790 Register LoadPtr
= Src
;
9792 if (CurrOffset
!= 0) {
9793 LLT SrcTy
= MRI
.getType(Src
);
9794 Offset
= MIB
.buildConstant(LLT::scalar(SrcTy
.getSizeInBits()), CurrOffset
)
9796 LoadPtr
= MIB
.buildPtrAdd(SrcTy
, Src
, Offset
).getReg(0);
9798 auto LdVal
= MIB
.buildLoad(CopyTy
, LoadPtr
, *LoadMMO
);
9800 // Create the store.
9801 Register StorePtr
= Dst
;
9802 if (CurrOffset
!= 0) {
9803 LLT DstTy
= MRI
.getType(Dst
);
9804 StorePtr
= MIB
.buildPtrAdd(DstTy
, Dst
, Offset
).getReg(0);
9806 MIB
.buildStore(LdVal
, StorePtr
, *StoreMMO
);
9807 CurrOffset
+= CopyTy
.getSizeInBytes();
9808 Size
-= CopyTy
.getSizeInBytes();
9811 MI
.eraseFromParent();
9815 LegalizerHelper::LegalizeResult
9816 LegalizerHelper::lowerMemmove(MachineInstr
&MI
, Register Dst
, Register Src
,
9817 uint64_t KnownLen
, Align DstAlign
, Align SrcAlign
,
9819 auto &MF
= *MI
.getParent()->getParent();
9820 const auto &TLI
= *MF
.getSubtarget().getTargetLowering();
9821 auto &DL
= MF
.getDataLayout();
9822 LLVMContext
&C
= MF
.getFunction().getContext();
9824 assert(KnownLen
!= 0 && "Have a zero length memmove length!");
9826 bool DstAlignCanChange
= false;
9827 MachineFrameInfo
&MFI
= MF
.getFrameInfo();
9828 bool OptSize
= shouldLowerMemFuncForSize(MF
);
9829 Align Alignment
= std::min(DstAlign
, SrcAlign
);
9831 MachineInstr
*FIDef
= getOpcodeDef(TargetOpcode::G_FRAME_INDEX
, Dst
, MRI
);
9832 if (FIDef
&& !MFI
.isFixedObjectIndex(FIDef
->getOperand(1).getIndex()))
9833 DstAlignCanChange
= true;
9835 unsigned Limit
= TLI
.getMaxStoresPerMemmove(OptSize
);
9836 std::vector
<LLT
> MemOps
;
9838 const auto &DstMMO
= **MI
.memoperands_begin();
9839 const auto &SrcMMO
= **std::next(MI
.memoperands_begin());
9840 MachinePointerInfo DstPtrInfo
= DstMMO
.getPointerInfo();
9841 MachinePointerInfo SrcPtrInfo
= SrcMMO
.getPointerInfo();
9843 // FIXME: SelectionDAG always passes false for 'AllowOverlap', apparently due
9844 // to a bug in it's findOptimalMemOpLowering implementation. For now do the
9846 if (!findGISelOptimalMemOpLowering(
9848 MemOp::Copy(KnownLen
, DstAlignCanChange
, Alignment
, SrcAlign
,
9849 /*IsVolatile*/ true),
9850 DstPtrInfo
.getAddrSpace(), SrcPtrInfo
.getAddrSpace(),
9851 MF
.getFunction().getAttributes(), TLI
))
9852 return UnableToLegalize
;
9854 if (DstAlignCanChange
) {
9855 // Get an estimate of the type from the LLT.
9856 Type
*IRTy
= getTypeForLLT(MemOps
[0], C
);
9857 Align NewAlign
= DL
.getABITypeAlign(IRTy
);
9859 // Don't promote to an alignment that would require dynamic stack
9861 const TargetRegisterInfo
*TRI
= MF
.getSubtarget().getRegisterInfo();
9862 if (!TRI
->hasStackRealignment(MF
))
9863 if (MaybeAlign StackAlign
= DL
.getStackAlignment())
9864 NewAlign
= std::min(NewAlign
, *StackAlign
);
9866 if (NewAlign
> Alignment
) {
9867 Alignment
= NewAlign
;
9868 unsigned FI
= FIDef
->getOperand(1).getIndex();
9869 // Give the stack frame object a larger alignment if needed.
9870 if (MFI
.getObjectAlign(FI
) < Alignment
)
9871 MFI
.setObjectAlignment(FI
, Alignment
);
9875 LLVM_DEBUG(dbgs() << "Inlining memmove: " << MI
<< " into loads & stores\n");
9877 MachineIRBuilder
MIB(MI
);
9878 // Memmove requires that we perform the loads first before issuing the stores.
9879 // Apart from that, this loop is pretty much doing the same thing as the
9880 // memcpy codegen function.
9881 unsigned CurrOffset
= 0;
9882 SmallVector
<Register
, 16> LoadVals
;
9883 for (auto CopyTy
: MemOps
) {
9884 // Construct MMO for the load.
9886 MF
.getMachineMemOperand(&SrcMMO
, CurrOffset
, CopyTy
.getSizeInBytes());
9889 Register LoadPtr
= Src
;
9890 if (CurrOffset
!= 0) {
9891 LLT SrcTy
= MRI
.getType(Src
);
9893 MIB
.buildConstant(LLT::scalar(SrcTy
.getSizeInBits()), CurrOffset
);
9894 LoadPtr
= MIB
.buildPtrAdd(SrcTy
, Src
, Offset
).getReg(0);
9896 LoadVals
.push_back(MIB
.buildLoad(CopyTy
, LoadPtr
, *LoadMMO
).getReg(0));
9897 CurrOffset
+= CopyTy
.getSizeInBytes();
9901 for (unsigned I
= 0; I
< MemOps
.size(); ++I
) {
9902 LLT CopyTy
= MemOps
[I
];
9903 // Now store the values loaded.
9905 MF
.getMachineMemOperand(&DstMMO
, CurrOffset
, CopyTy
.getSizeInBytes());
9907 Register StorePtr
= Dst
;
9908 if (CurrOffset
!= 0) {
9909 LLT DstTy
= MRI
.getType(Dst
);
9911 MIB
.buildConstant(LLT::scalar(DstTy
.getSizeInBits()), CurrOffset
);
9912 StorePtr
= MIB
.buildPtrAdd(DstTy
, Dst
, Offset
).getReg(0);
9914 MIB
.buildStore(LoadVals
[I
], StorePtr
, *StoreMMO
);
9915 CurrOffset
+= CopyTy
.getSizeInBytes();
9917 MI
.eraseFromParent();
9921 LegalizerHelper::LegalizeResult
9922 LegalizerHelper::lowerMemCpyFamily(MachineInstr
&MI
, unsigned MaxLen
) {
9923 const unsigned Opc
= MI
.getOpcode();
9924 // This combine is fairly complex so it's not written with a separate
9925 // matcher function.
9926 assert((Opc
== TargetOpcode::G_MEMCPY
|| Opc
== TargetOpcode::G_MEMMOVE
||
9927 Opc
== TargetOpcode::G_MEMSET
) &&
9928 "Expected memcpy like instruction");
9930 auto MMOIt
= MI
.memoperands_begin();
9931 const MachineMemOperand
*MemOp
= *MMOIt
;
9933 Align DstAlign
= MemOp
->getBaseAlign();
9935 auto [Dst
, Src
, Len
] = MI
.getFirst3Regs();
9937 if (Opc
!= TargetOpcode::G_MEMSET
) {
9938 assert(MMOIt
!= MI
.memoperands_end() && "Expected a second MMO on MI");
9940 SrcAlign
= MemOp
->getBaseAlign();
9943 // See if this is a constant length copy
9944 auto LenVRegAndVal
= getIConstantVRegValWithLookThrough(Len
, MRI
);
9946 return UnableToLegalize
;
9947 uint64_t KnownLen
= LenVRegAndVal
->Value
.getZExtValue();
9949 if (KnownLen
== 0) {
9950 MI
.eraseFromParent();
9954 bool IsVolatile
= MemOp
->isVolatile();
9955 if (Opc
== TargetOpcode::G_MEMCPY_INLINE
)
9956 return lowerMemcpyInline(MI
, Dst
, Src
, KnownLen
, DstAlign
, SrcAlign
,
9959 // Don't try to optimize volatile.
9961 return UnableToLegalize
;
9963 if (MaxLen
&& KnownLen
> MaxLen
)
9964 return UnableToLegalize
;
9966 if (Opc
== TargetOpcode::G_MEMCPY
) {
9967 auto &MF
= *MI
.getParent()->getParent();
9968 const auto &TLI
= *MF
.getSubtarget().getTargetLowering();
9969 bool OptSize
= shouldLowerMemFuncForSize(MF
);
9970 uint64_t Limit
= TLI
.getMaxStoresPerMemcpy(OptSize
);
9971 return lowerMemcpy(MI
, Dst
, Src
, KnownLen
, Limit
, DstAlign
, SrcAlign
,
9974 if (Opc
== TargetOpcode::G_MEMMOVE
)
9975 return lowerMemmove(MI
, Dst
, Src
, KnownLen
, DstAlign
, SrcAlign
, IsVolatile
);
9976 if (Opc
== TargetOpcode::G_MEMSET
)
9977 return lowerMemset(MI
, Dst
, Src
, KnownLen
, DstAlign
, IsVolatile
);
9978 return UnableToLegalize
;