1 | //===- llvm/CodeGen/GlobalISel/Utils.cpp -------------------------*- C++ -*-==// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// \file This file implements the utility functions used by the GlobalISel |
9 | /// pipeline. |
10 | //===----------------------------------------------------------------------===// |
11 | |
12 | #include "llvm/CodeGen/GlobalISel/Utils.h" |
13 | #include "llvm/ADT/APFloat.h" |
14 | #include "llvm/ADT/APInt.h" |
15 | #include "llvm/Analysis/ValueTracking.h" |
16 | #include "llvm/CodeGen/CodeGenCommonISel.h" |
17 | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" |
18 | #include "llvm/CodeGen/GlobalISel/GISelValueTracking.h" |
19 | #include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h" |
20 | #include "llvm/CodeGen/GlobalISel/LostDebugLocObserver.h" |
21 | #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" |
22 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
23 | #include "llvm/CodeGen/MachineInstr.h" |
24 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
25 | #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" |
26 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
27 | #include "llvm/CodeGen/MachineSizeOpts.h" |
28 | #include "llvm/CodeGen/RegisterBankInfo.h" |
29 | #include "llvm/CodeGen/StackProtector.h" |
30 | #include "llvm/CodeGen/TargetInstrInfo.h" |
31 | #include "llvm/CodeGen/TargetLowering.h" |
32 | #include "llvm/CodeGen/TargetOpcodes.h" |
33 | #include "llvm/CodeGen/TargetPassConfig.h" |
34 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
35 | #include "llvm/IR/Constants.h" |
36 | #include "llvm/Target/TargetMachine.h" |
37 | #include "llvm/Transforms/Utils/SizeOpts.h" |
38 | #include <numeric> |
39 | #include <optional> |
40 | |
41 | #define DEBUG_TYPE "globalisel-utils" |
42 | |
43 | using namespace llvm; |
44 | using namespace MIPatternMatch; |
45 | |
46 | Register llvm::constrainRegToClass(MachineRegisterInfo &MRI, |
47 | const TargetInstrInfo &TII, |
48 | const RegisterBankInfo &RBI, Register Reg, |
49 | const TargetRegisterClass &RegClass) { |
50 | if (!RBI.constrainGenericRegister(Reg, RC: RegClass, MRI)) |
51 | return MRI.createVirtualRegister(RegClass: &RegClass); |
52 | |
53 | return Reg; |
54 | } |
55 | |
56 | Register llvm::constrainOperandRegClass( |
57 | const MachineFunction &MF, const TargetRegisterInfo &TRI, |
58 | MachineRegisterInfo &MRI, const TargetInstrInfo &TII, |
59 | const RegisterBankInfo &RBI, MachineInstr &InsertPt, |
60 | const TargetRegisterClass &RegClass, MachineOperand &RegMO) { |
61 | Register Reg = RegMO.getReg(); |
62 | // Assume physical registers are properly constrained. |
63 | assert(Reg.isVirtual() && "PhysReg not implemented" ); |
64 | |
65 | // Save the old register class to check whether |
66 | // the change notifications will be required. |
67 | // TODO: A better approach would be to pass |
68 | // the observers to constrainRegToClass(). |
69 | auto *OldRegClass = MRI.getRegClassOrNull(Reg); |
70 | Register ConstrainedReg = constrainRegToClass(MRI, TII, RBI, Reg, RegClass); |
71 | // If we created a new virtual register because the class is not compatible |
72 | // then create a copy between the new and the old register. |
73 | if (ConstrainedReg != Reg) { |
74 | MachineBasicBlock::iterator InsertIt(&InsertPt); |
75 | MachineBasicBlock &MBB = *InsertPt.getParent(); |
76 | // FIXME: The copy needs to have the classes constrained for its operands. |
77 | // Use operand's regbank to get the class for old register (Reg). |
78 | if (RegMO.isUse()) { |
79 | BuildMI(BB&: MBB, I: InsertIt, MIMD: InsertPt.getDebugLoc(), |
80 | MCID: TII.get(Opcode: TargetOpcode::COPY), DestReg: ConstrainedReg) |
81 | .addReg(RegNo: Reg); |
82 | } else { |
83 | assert(RegMO.isDef() && "Must be a definition" ); |
84 | BuildMI(BB&: MBB, I: std::next(x: InsertIt), MIMD: InsertPt.getDebugLoc(), |
85 | MCID: TII.get(Opcode: TargetOpcode::COPY), DestReg: Reg) |
86 | .addReg(RegNo: ConstrainedReg); |
87 | } |
88 | if (GISelChangeObserver *Observer = MF.getObserver()) { |
89 | Observer->changingInstr(MI&: *RegMO.getParent()); |
90 | } |
91 | RegMO.setReg(ConstrainedReg); |
92 | if (GISelChangeObserver *Observer = MF.getObserver()) { |
93 | Observer->changedInstr(MI&: *RegMO.getParent()); |
94 | } |
95 | } else if (OldRegClass != MRI.getRegClassOrNull(Reg)) { |
96 | if (GISelChangeObserver *Observer = MF.getObserver()) { |
97 | if (!RegMO.isDef()) { |
98 | MachineInstr *RegDef = MRI.getVRegDef(Reg); |
99 | Observer->changedInstr(MI&: *RegDef); |
100 | } |
101 | Observer->changingAllUsesOfReg(MRI, Reg); |
102 | Observer->finishedChangingAllUsesOfReg(); |
103 | } |
104 | } |
105 | return ConstrainedReg; |
106 | } |
107 | |
108 | Register llvm::constrainOperandRegClass( |
109 | const MachineFunction &MF, const TargetRegisterInfo &TRI, |
110 | MachineRegisterInfo &MRI, const TargetInstrInfo &TII, |
111 | const RegisterBankInfo &RBI, MachineInstr &InsertPt, const MCInstrDesc &II, |
112 | MachineOperand &RegMO, unsigned OpIdx) { |
113 | Register Reg = RegMO.getReg(); |
114 | // Assume physical registers are properly constrained. |
115 | assert(Reg.isVirtual() && "PhysReg not implemented" ); |
116 | |
117 | const TargetRegisterClass *OpRC = TII.getRegClass(MCID: II, OpNum: OpIdx, TRI: &TRI, MF); |
118 | // Some of the target independent instructions, like COPY, may not impose any |
119 | // register class constraints on some of their operands: If it's a use, we can |
120 | // skip constraining as the instruction defining the register would constrain |
121 | // it. |
122 | |
123 | if (OpRC) { |
124 | // Obtain the RC from incoming regbank if it is a proper sub-class. Operands |
125 | // can have multiple regbanks for a superclass that combine different |
126 | // register types (E.g., AMDGPU's VGPR and AGPR). The regbank ambiguity |
127 | // resolved by targets during regbankselect should not be overridden. |
128 | if (const auto *SubRC = TRI.getCommonSubClass( |
129 | A: OpRC, B: TRI.getConstrainedRegClassForOperand(MO: RegMO, MRI))) |
130 | OpRC = SubRC; |
131 | |
132 | OpRC = TRI.getAllocatableClass(RC: OpRC); |
133 | } |
134 | |
135 | if (!OpRC) { |
136 | assert((!isTargetSpecificOpcode(II.getOpcode()) || RegMO.isUse()) && |
137 | "Register class constraint is required unless either the " |
138 | "instruction is target independent or the operand is a use" ); |
139 | // FIXME: Just bailing out like this here could be not enough, unless we |
140 | // expect the users of this function to do the right thing for PHIs and |
141 | // COPY: |
142 | // v1 = COPY v0 |
143 | // v2 = COPY v1 |
144 | // v1 here may end up not being constrained at all. Please notice that to |
145 | // reproduce the issue we likely need a destination pattern of a selection |
146 | // rule producing such extra copies, not just an input GMIR with them as |
147 | // every existing target using selectImpl handles copies before calling it |
148 | // and they never reach this function. |
149 | return Reg; |
150 | } |
151 | return constrainOperandRegClass(MF, TRI, MRI, TII, RBI, InsertPt, RegClass: *OpRC, |
152 | RegMO); |
153 | } |
154 | |
155 | bool llvm::constrainSelectedInstRegOperands(MachineInstr &I, |
156 | const TargetInstrInfo &TII, |
157 | const TargetRegisterInfo &TRI, |
158 | const RegisterBankInfo &RBI) { |
159 | assert(!isPreISelGenericOpcode(I.getOpcode()) && |
160 | "A selected instruction is expected" ); |
161 | MachineBasicBlock &MBB = *I.getParent(); |
162 | MachineFunction &MF = *MBB.getParent(); |
163 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
164 | |
165 | for (unsigned OpI = 0, OpE = I.getNumExplicitOperands(); OpI != OpE; ++OpI) { |
166 | MachineOperand &MO = I.getOperand(i: OpI); |
167 | |
168 | // There's nothing to be done on non-register operands. |
169 | if (!MO.isReg()) |
170 | continue; |
171 | |
172 | LLVM_DEBUG(dbgs() << "Converting operand: " << MO << '\n'); |
173 | assert(MO.isReg() && "Unsupported non-reg operand" ); |
174 | |
175 | Register Reg = MO.getReg(); |
176 | // Physical registers don't need to be constrained. |
177 | if (Reg.isPhysical()) |
178 | continue; |
179 | |
180 | // Register operands with a value of 0 (e.g. predicate operands) don't need |
181 | // to be constrained. |
182 | if (Reg == 0) |
183 | continue; |
184 | |
185 | // If the operand is a vreg, we should constrain its regclass, and only |
186 | // insert COPYs if that's impossible. |
187 | // constrainOperandRegClass does that for us. |
188 | constrainOperandRegClass(MF, TRI, MRI, TII, RBI, InsertPt&: I, II: I.getDesc(), RegMO&: MO, OpIdx: OpI); |
189 | |
190 | // Tie uses to defs as indicated in MCInstrDesc if this hasn't already been |
191 | // done. |
192 | if (MO.isUse()) { |
193 | int DefIdx = I.getDesc().getOperandConstraint(OpNum: OpI, Constraint: MCOI::TIED_TO); |
194 | if (DefIdx != -1 && !I.isRegTiedToUseOperand(DefOpIdx: DefIdx)) |
195 | I.tieOperands(DefIdx, UseIdx: OpI); |
196 | } |
197 | } |
198 | return true; |
199 | } |
200 | |
201 | bool llvm::canReplaceReg(Register DstReg, Register SrcReg, |
202 | MachineRegisterInfo &MRI) { |
203 | // Give up if either DstReg or SrcReg is a physical register. |
204 | if (DstReg.isPhysical() || SrcReg.isPhysical()) |
205 | return false; |
206 | // Give up if the types don't match. |
207 | if (MRI.getType(Reg: DstReg) != MRI.getType(Reg: SrcReg)) |
208 | return false; |
209 | // Replace if either DstReg has no constraints or the register |
210 | // constraints match. |
211 | const auto &DstRBC = MRI.getRegClassOrRegBank(Reg: DstReg); |
212 | if (!DstRBC || DstRBC == MRI.getRegClassOrRegBank(Reg: SrcReg)) |
213 | return true; |
214 | |
215 | // Otherwise match if the Src is already a regclass that is covered by the Dst |
216 | // RegBank. |
217 | return isa<const RegisterBank *>(Val: DstRBC) && MRI.getRegClassOrNull(Reg: SrcReg) && |
218 | cast<const RegisterBank *>(Val: DstRBC)->covers( |
219 | RC: *MRI.getRegClassOrNull(Reg: SrcReg)); |
220 | } |
221 | |
222 | bool llvm::isTriviallyDead(const MachineInstr &MI, |
223 | const MachineRegisterInfo &MRI) { |
224 | // Instructions without side-effects are dead iff they only define dead regs. |
225 | // This function is hot and this loop returns early in the common case, |
226 | // so only perform additional checks before this if absolutely necessary. |
227 | for (const auto &MO : MI.all_defs()) { |
228 | Register Reg = MO.getReg(); |
229 | if (Reg.isPhysical() || !MRI.use_nodbg_empty(RegNo: Reg)) |
230 | return false; |
231 | } |
232 | return MI.wouldBeTriviallyDead(); |
233 | } |
234 | |
235 | static void (DiagnosticSeverity Severity, |
236 | MachineFunction &MF, |
237 | const TargetPassConfig &TPC, |
238 | MachineOptimizationRemarkEmitter &MORE, |
239 | MachineOptimizationRemarkMissed &R) { |
240 | bool IsFatal = Severity == DS_Error && |
241 | TPC.isGlobalISelAbortEnabled(); |
242 | // Print the function name explicitly if we don't have a debug location (which |
243 | // makes the diagnostic less useful) or if we're going to emit a raw error. |
244 | if (!R.getLocation().isValid() || IsFatal) |
245 | R << (" (in function: " + MF.getName() + ")" ).str(); |
246 | |
247 | if (IsFatal) |
248 | reportFatalUsageError(reason: Twine(R.getMsg())); |
249 | else |
250 | MORE.emit(OptDiag&: R); |
251 | } |
252 | |
253 | void llvm::(MachineFunction &MF, const TargetPassConfig &TPC, |
254 | MachineOptimizationRemarkEmitter &MORE, |
255 | MachineOptimizationRemarkMissed &R) { |
256 | reportGISelDiagnostic(Severity: DS_Warning, MF, TPC, MORE, R); |
257 | } |
258 | |
259 | void llvm::(MachineFunction &MF, const TargetPassConfig &TPC, |
260 | MachineOptimizationRemarkEmitter &MORE, |
261 | MachineOptimizationRemarkMissed &R) { |
262 | MF.getProperties().setFailedISel(); |
263 | reportGISelDiagnostic(Severity: DS_Error, MF, TPC, MORE, R); |
264 | } |
265 | |
266 | void llvm::(MachineFunction &MF, const TargetPassConfig &TPC, |
267 | MachineOptimizationRemarkEmitter &MORE, |
268 | const char *PassName, StringRef Msg, |
269 | const MachineInstr &MI) { |
270 | MachineOptimizationRemarkMissed R(PassName, "GISelFailure: " , |
271 | MI.getDebugLoc(), MI.getParent()); |
272 | R << Msg; |
273 | // Printing MI is expensive; only do it if expensive remarks are enabled. |
274 | if (TPC.isGlobalISelAbortEnabled() || MORE.allowExtraAnalysis(PassName)) |
275 | R << ": " << ore::MNV("Inst" , MI); |
276 | reportGISelFailure(MF, TPC, MORE, R); |
277 | } |
278 | |
279 | unsigned llvm::getInverseGMinMaxOpcode(unsigned MinMaxOpc) { |
280 | switch (MinMaxOpc) { |
281 | case TargetOpcode::G_SMIN: |
282 | return TargetOpcode::G_SMAX; |
283 | case TargetOpcode::G_SMAX: |
284 | return TargetOpcode::G_SMIN; |
285 | case TargetOpcode::G_UMIN: |
286 | return TargetOpcode::G_UMAX; |
287 | case TargetOpcode::G_UMAX: |
288 | return TargetOpcode::G_UMIN; |
289 | default: |
290 | llvm_unreachable("unrecognized opcode" ); |
291 | } |
292 | } |
293 | |
294 | std::optional<APInt> llvm::getIConstantVRegVal(Register VReg, |
295 | const MachineRegisterInfo &MRI) { |
296 | std::optional<ValueAndVReg> ValAndVReg = getIConstantVRegValWithLookThrough( |
297 | VReg, MRI, /*LookThroughInstrs*/ false); |
298 | assert((!ValAndVReg || ValAndVReg->VReg == VReg) && |
299 | "Value found while looking through instrs" ); |
300 | if (!ValAndVReg) |
301 | return std::nullopt; |
302 | return ValAndVReg->Value; |
303 | } |
304 | |
305 | const APInt &llvm::getIConstantFromReg(Register Reg, |
306 | const MachineRegisterInfo &MRI) { |
307 | MachineInstr *Const = MRI.getVRegDef(Reg); |
308 | assert((Const && Const->getOpcode() == TargetOpcode::G_CONSTANT) && |
309 | "expected a G_CONSTANT on Reg" ); |
310 | return Const->getOperand(i: 1).getCImm()->getValue(); |
311 | } |
312 | |
313 | std::optional<int64_t> |
314 | llvm::getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI) { |
315 | std::optional<APInt> Val = getIConstantVRegVal(VReg, MRI); |
316 | if (Val && Val->getBitWidth() <= 64) |
317 | return Val->getSExtValue(); |
318 | return std::nullopt; |
319 | } |
320 | |
321 | namespace { |
322 | |
323 | // This function is used in many places, and as such, it has some |
324 | // micro-optimizations to try and make it as fast as it can be. |
325 | // |
326 | // - We use template arguments to avoid an indirect call caused by passing a |
327 | // function_ref/std::function |
328 | // - GetAPCstValue does not return std::optional<APInt> as that's expensive. |
329 | // Instead it returns true/false and places the result in a pre-constructed |
330 | // APInt. |
331 | // |
332 | // Please change this function carefully and benchmark your changes. |
333 | template <bool (*IsConstantOpcode)(const MachineInstr *), |
334 | bool (*GetAPCstValue)(const MachineInstr *MI, APInt &)> |
335 | std::optional<ValueAndVReg> |
336 | getConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, |
337 | bool LookThroughInstrs = true, |
338 | bool LookThroughAnyExt = false) { |
339 | SmallVector<std::pair<unsigned, unsigned>, 4> SeenOpcodes; |
340 | MachineInstr *MI; |
341 | |
342 | while ((MI = MRI.getVRegDef(Reg: VReg)) && !IsConstantOpcode(MI) && |
343 | LookThroughInstrs) { |
344 | switch (MI->getOpcode()) { |
345 | case TargetOpcode::G_ANYEXT: |
346 | if (!LookThroughAnyExt) |
347 | return std::nullopt; |
348 | [[fallthrough]]; |
349 | case TargetOpcode::G_TRUNC: |
350 | case TargetOpcode::G_SEXT: |
351 | case TargetOpcode::G_ZEXT: |
352 | SeenOpcodes.push_back(Elt: std::make_pair( |
353 | x: MI->getOpcode(), |
354 | y: MRI.getType(Reg: MI->getOperand(i: 0).getReg()).getSizeInBits())); |
355 | VReg = MI->getOperand(i: 1).getReg(); |
356 | break; |
357 | case TargetOpcode::COPY: |
358 | VReg = MI->getOperand(i: 1).getReg(); |
359 | if (VReg.isPhysical()) |
360 | return std::nullopt; |
361 | break; |
362 | case TargetOpcode::G_INTTOPTR: |
363 | VReg = MI->getOperand(i: 1).getReg(); |
364 | break; |
365 | default: |
366 | return std::nullopt; |
367 | } |
368 | } |
369 | if (!MI || !IsConstantOpcode(MI)) |
370 | return std::nullopt; |
371 | |
372 | APInt Val; |
373 | if (!GetAPCstValue(MI, Val)) |
374 | return std::nullopt; |
375 | for (auto &Pair : reverse(C&: SeenOpcodes)) { |
376 | switch (Pair.first) { |
377 | case TargetOpcode::G_TRUNC: |
378 | Val = Val.trunc(width: Pair.second); |
379 | break; |
380 | case TargetOpcode::G_ANYEXT: |
381 | case TargetOpcode::G_SEXT: |
382 | Val = Val.sext(width: Pair.second); |
383 | break; |
384 | case TargetOpcode::G_ZEXT: |
385 | Val = Val.zext(width: Pair.second); |
386 | break; |
387 | } |
388 | } |
389 | |
390 | return ValueAndVReg{.Value: std::move(Val), .VReg: VReg}; |
391 | } |
392 | |
393 | bool isIConstant(const MachineInstr *MI) { |
394 | if (!MI) |
395 | return false; |
396 | return MI->getOpcode() == TargetOpcode::G_CONSTANT; |
397 | } |
398 | |
399 | bool isFConstant(const MachineInstr *MI) { |
400 | if (!MI) |
401 | return false; |
402 | return MI->getOpcode() == TargetOpcode::G_FCONSTANT; |
403 | } |
404 | |
405 | bool isAnyConstant(const MachineInstr *MI) { |
406 | if (!MI) |
407 | return false; |
408 | unsigned Opc = MI->getOpcode(); |
409 | return Opc == TargetOpcode::G_CONSTANT || Opc == TargetOpcode::G_FCONSTANT; |
410 | } |
411 | |
412 | bool getCImmAsAPInt(const MachineInstr *MI, APInt &Result) { |
413 | const MachineOperand &CstVal = MI->getOperand(i: 1); |
414 | if (!CstVal.isCImm()) |
415 | return false; |
416 | Result = CstVal.getCImm()->getValue(); |
417 | return true; |
418 | } |
419 | |
420 | bool getCImmOrFPImmAsAPInt(const MachineInstr *MI, APInt &Result) { |
421 | const MachineOperand &CstVal = MI->getOperand(i: 1); |
422 | if (CstVal.isCImm()) |
423 | Result = CstVal.getCImm()->getValue(); |
424 | else if (CstVal.isFPImm()) |
425 | Result = CstVal.getFPImm()->getValueAPF().bitcastToAPInt(); |
426 | else |
427 | return false; |
428 | return true; |
429 | } |
430 | |
431 | } // end anonymous namespace |
432 | |
433 | std::optional<ValueAndVReg> llvm::getIConstantVRegValWithLookThrough( |
434 | Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) { |
435 | return getConstantVRegValWithLookThrough<isIConstant, getCImmAsAPInt>( |
436 | VReg, MRI, LookThroughInstrs); |
437 | } |
438 | |
439 | std::optional<ValueAndVReg> llvm::getAnyConstantVRegValWithLookThrough( |
440 | Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs, |
441 | bool LookThroughAnyExt) { |
442 | return getConstantVRegValWithLookThrough<isAnyConstant, |
443 | getCImmOrFPImmAsAPInt>( |
444 | VReg, MRI, LookThroughInstrs, LookThroughAnyExt); |
445 | } |
446 | |
447 | std::optional<FPValueAndVReg> llvm::getFConstantVRegValWithLookThrough( |
448 | Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs) { |
449 | auto Reg = |
450 | getConstantVRegValWithLookThrough<isFConstant, getCImmOrFPImmAsAPInt>( |
451 | VReg, MRI, LookThroughInstrs); |
452 | if (!Reg) |
453 | return std::nullopt; |
454 | return FPValueAndVReg{.Value: getConstantFPVRegVal(VReg: Reg->VReg, MRI)->getValueAPF(), |
455 | .VReg: Reg->VReg}; |
456 | } |
457 | |
458 | const ConstantFP * |
459 | llvm::getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI) { |
460 | MachineInstr *MI = MRI.getVRegDef(Reg: VReg); |
461 | if (TargetOpcode::G_FCONSTANT != MI->getOpcode()) |
462 | return nullptr; |
463 | return MI->getOperand(i: 1).getFPImm(); |
464 | } |
465 | |
466 | std::optional<DefinitionAndSourceRegister> |
467 | llvm::getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI) { |
468 | Register DefSrcReg = Reg; |
469 | auto *DefMI = MRI.getVRegDef(Reg); |
470 | auto DstTy = MRI.getType(Reg: DefMI->getOperand(i: 0).getReg()); |
471 | if (!DstTy.isValid()) |
472 | return std::nullopt; |
473 | unsigned Opc = DefMI->getOpcode(); |
474 | while (Opc == TargetOpcode::COPY || isPreISelGenericOptimizationHint(Opcode: Opc)) { |
475 | Register SrcReg = DefMI->getOperand(i: 1).getReg(); |
476 | auto SrcTy = MRI.getType(Reg: SrcReg); |
477 | if (!SrcTy.isValid()) |
478 | break; |
479 | DefMI = MRI.getVRegDef(Reg: SrcReg); |
480 | DefSrcReg = SrcReg; |
481 | Opc = DefMI->getOpcode(); |
482 | } |
483 | return DefinitionAndSourceRegister{.MI: DefMI, .Reg: DefSrcReg}; |
484 | } |
485 | |
486 | MachineInstr *llvm::getDefIgnoringCopies(Register Reg, |
487 | const MachineRegisterInfo &MRI) { |
488 | std::optional<DefinitionAndSourceRegister> DefSrcReg = |
489 | getDefSrcRegIgnoringCopies(Reg, MRI); |
490 | return DefSrcReg ? DefSrcReg->MI : nullptr; |
491 | } |
492 | |
493 | Register llvm::getSrcRegIgnoringCopies(Register Reg, |
494 | const MachineRegisterInfo &MRI) { |
495 | std::optional<DefinitionAndSourceRegister> DefSrcReg = |
496 | getDefSrcRegIgnoringCopies(Reg, MRI); |
497 | return DefSrcReg ? DefSrcReg->Reg : Register(); |
498 | } |
499 | |
500 | void llvm::(Register Reg, LLT Ty, int NumParts, |
501 | SmallVectorImpl<Register> &VRegs, |
502 | MachineIRBuilder &MIRBuilder, |
503 | MachineRegisterInfo &MRI) { |
504 | for (int i = 0; i < NumParts; ++i) |
505 | VRegs.push_back(Elt: MRI.createGenericVirtualRegister(Ty)); |
506 | MIRBuilder.buildUnmerge(Res: VRegs, Op: Reg); |
507 | } |
508 | |
509 | bool llvm::(Register Reg, LLT RegTy, LLT MainTy, LLT &LeftoverTy, |
510 | SmallVectorImpl<Register> &VRegs, |
511 | SmallVectorImpl<Register> &LeftoverRegs, |
512 | MachineIRBuilder &MIRBuilder, |
513 | MachineRegisterInfo &MRI) { |
514 | assert(!LeftoverTy.isValid() && "this is an out argument" ); |
515 | |
516 | unsigned RegSize = RegTy.getSizeInBits(); |
517 | unsigned MainSize = MainTy.getSizeInBits(); |
518 | unsigned NumParts = RegSize / MainSize; |
519 | unsigned LeftoverSize = RegSize - NumParts * MainSize; |
520 | |
521 | // Use an unmerge when possible. |
522 | if (LeftoverSize == 0) { |
523 | for (unsigned I = 0; I < NumParts; ++I) |
524 | VRegs.push_back(Elt: MRI.createGenericVirtualRegister(Ty: MainTy)); |
525 | MIRBuilder.buildUnmerge(Res: VRegs, Op: Reg); |
526 | return true; |
527 | } |
528 | |
529 | // Try to use unmerge for irregular vector split where possible |
530 | // For example when splitting a <6 x i32> into <4 x i32> with <2 x i32> |
531 | // leftover, it becomes: |
532 | // <2 x i32> %2, <2 x i32>%3, <2 x i32> %4 = G_UNMERGE_VALUE <6 x i32> %1 |
533 | // <4 x i32> %5 = G_CONCAT_VECTOR <2 x i32> %2, <2 x i32> %3 |
534 | if (RegTy.isVector() && MainTy.isVector()) { |
535 | unsigned RegNumElts = RegTy.getNumElements(); |
536 | unsigned MainNumElts = MainTy.getNumElements(); |
537 | unsigned LeftoverNumElts = RegNumElts % MainNumElts; |
538 | // If can unmerge to LeftoverTy, do it |
539 | if (MainNumElts % LeftoverNumElts == 0 && |
540 | RegNumElts % LeftoverNumElts == 0 && |
541 | RegTy.getScalarSizeInBits() == MainTy.getScalarSizeInBits() && |
542 | LeftoverNumElts > 1) { |
543 | LeftoverTy = LLT::fixed_vector(NumElements: LeftoverNumElts, ScalarTy: RegTy.getElementType()); |
544 | |
545 | // Unmerge the SrcReg to LeftoverTy vectors |
546 | SmallVector<Register, 4> UnmergeValues; |
547 | extractParts(Reg, Ty: LeftoverTy, NumParts: RegNumElts / LeftoverNumElts, VRegs&: UnmergeValues, |
548 | MIRBuilder, MRI); |
549 | |
550 | // Find how many LeftoverTy makes one MainTy |
551 | unsigned LeftoverPerMain = MainNumElts / LeftoverNumElts; |
552 | unsigned NumOfLeftoverVal = |
553 | ((RegNumElts % MainNumElts) / LeftoverNumElts); |
554 | |
555 | // Create as many MainTy as possible using unmerged value |
556 | SmallVector<Register, 4> MergeValues; |
557 | for (unsigned I = 0; I < UnmergeValues.size() - NumOfLeftoverVal; I++) { |
558 | MergeValues.push_back(Elt: UnmergeValues[I]); |
559 | if (MergeValues.size() == LeftoverPerMain) { |
560 | VRegs.push_back( |
561 | Elt: MIRBuilder.buildMergeLikeInstr(Res: MainTy, Ops: MergeValues).getReg(Idx: 0)); |
562 | MergeValues.clear(); |
563 | } |
564 | } |
565 | // Populate LeftoverRegs with the leftovers |
566 | for (unsigned I = UnmergeValues.size() - NumOfLeftoverVal; |
567 | I < UnmergeValues.size(); I++) { |
568 | LeftoverRegs.push_back(Elt: UnmergeValues[I]); |
569 | } |
570 | return true; |
571 | } |
572 | } |
573 | // Perform irregular split. Leftover is last element of RegPieces. |
574 | if (MainTy.isVector()) { |
575 | SmallVector<Register, 8> RegPieces; |
576 | extractVectorParts(Reg, NumElts: MainTy.getNumElements(), VRegs&: RegPieces, MIRBuilder, |
577 | MRI); |
578 | for (unsigned i = 0; i < RegPieces.size() - 1; ++i) |
579 | VRegs.push_back(Elt: RegPieces[i]); |
580 | LeftoverRegs.push_back(Elt: RegPieces[RegPieces.size() - 1]); |
581 | LeftoverTy = MRI.getType(Reg: LeftoverRegs[0]); |
582 | return true; |
583 | } |
584 | |
585 | LeftoverTy = LLT::scalar(SizeInBits: LeftoverSize); |
586 | // For irregular sizes, extract the individual parts. |
587 | for (unsigned I = 0; I != NumParts; ++I) { |
588 | Register NewReg = MRI.createGenericVirtualRegister(Ty: MainTy); |
589 | VRegs.push_back(Elt: NewReg); |
590 | MIRBuilder.buildExtract(Res: NewReg, Src: Reg, Index: MainSize * I); |
591 | } |
592 | |
593 | for (unsigned Offset = MainSize * NumParts; Offset < RegSize; |
594 | Offset += LeftoverSize) { |
595 | Register NewReg = MRI.createGenericVirtualRegister(Ty: LeftoverTy); |
596 | LeftoverRegs.push_back(Elt: NewReg); |
597 | MIRBuilder.buildExtract(Res: NewReg, Src: Reg, Index: Offset); |
598 | } |
599 | |
600 | return true; |
601 | } |
602 | |
603 | void llvm::(Register Reg, unsigned NumElts, |
604 | SmallVectorImpl<Register> &VRegs, |
605 | MachineIRBuilder &MIRBuilder, |
606 | MachineRegisterInfo &MRI) { |
607 | LLT RegTy = MRI.getType(Reg); |
608 | assert(RegTy.isVector() && "Expected a vector type" ); |
609 | |
610 | LLT EltTy = RegTy.getElementType(); |
611 | LLT NarrowTy = (NumElts == 1) ? EltTy : LLT::fixed_vector(NumElements: NumElts, ScalarTy: EltTy); |
612 | unsigned RegNumElts = RegTy.getNumElements(); |
613 | unsigned LeftoverNumElts = RegNumElts % NumElts; |
614 | unsigned NumNarrowTyPieces = RegNumElts / NumElts; |
615 | |
616 | // Perfect split without leftover |
617 | if (LeftoverNumElts == 0) |
618 | return extractParts(Reg, Ty: NarrowTy, NumParts: NumNarrowTyPieces, VRegs, MIRBuilder, |
619 | MRI); |
620 | |
621 | // Irregular split. Provide direct access to all elements for artifact |
622 | // combiner using unmerge to elements. Then build vectors with NumElts |
623 | // elements. Remaining element(s) will be (used to build vector) Leftover. |
624 | SmallVector<Register, 8> Elts; |
625 | extractParts(Reg, Ty: EltTy, NumParts: RegNumElts, VRegs&: Elts, MIRBuilder, MRI); |
626 | |
627 | unsigned Offset = 0; |
628 | // Requested sub-vectors of NarrowTy. |
629 | for (unsigned i = 0; i < NumNarrowTyPieces; ++i, Offset += NumElts) { |
630 | ArrayRef<Register> Pieces(&Elts[Offset], NumElts); |
631 | VRegs.push_back(Elt: MIRBuilder.buildMergeLikeInstr(Res: NarrowTy, Ops: Pieces).getReg(Idx: 0)); |
632 | } |
633 | |
634 | // Leftover element(s). |
635 | if (LeftoverNumElts == 1) { |
636 | VRegs.push_back(Elt: Elts[Offset]); |
637 | } else { |
638 | LLT LeftoverTy = LLT::fixed_vector(NumElements: LeftoverNumElts, ScalarTy: EltTy); |
639 | ArrayRef<Register> Pieces(&Elts[Offset], LeftoverNumElts); |
640 | VRegs.push_back( |
641 | Elt: MIRBuilder.buildMergeLikeInstr(Res: LeftoverTy, Ops: Pieces).getReg(Idx: 0)); |
642 | } |
643 | } |
644 | |
645 | MachineInstr *llvm::getOpcodeDef(unsigned Opcode, Register Reg, |
646 | const MachineRegisterInfo &MRI) { |
647 | MachineInstr *DefMI = getDefIgnoringCopies(Reg, MRI); |
648 | return DefMI && DefMI->getOpcode() == Opcode ? DefMI : nullptr; |
649 | } |
650 | |
651 | APFloat llvm::getAPFloatFromSize(double Val, unsigned Size) { |
652 | if (Size == 32) |
653 | return APFloat(float(Val)); |
654 | if (Size == 64) |
655 | return APFloat(Val); |
656 | if (Size != 16) |
657 | llvm_unreachable("Unsupported FPConstant size" ); |
658 | bool Ignored; |
659 | APFloat APF(Val); |
660 | APF.convert(ToSemantics: APFloat::IEEEhalf(), RM: APFloat::rmNearestTiesToEven, losesInfo: &Ignored); |
661 | return APF; |
662 | } |
663 | |
664 | std::optional<APInt> llvm::ConstantFoldBinOp(unsigned Opcode, |
665 | const Register Op1, |
666 | const Register Op2, |
667 | const MachineRegisterInfo &MRI) { |
668 | auto MaybeOp2Cst = getAnyConstantVRegValWithLookThrough(VReg: Op2, MRI, LookThroughInstrs: false); |
669 | if (!MaybeOp2Cst) |
670 | return std::nullopt; |
671 | |
672 | auto MaybeOp1Cst = getAnyConstantVRegValWithLookThrough(VReg: Op1, MRI, LookThroughInstrs: false); |
673 | if (!MaybeOp1Cst) |
674 | return std::nullopt; |
675 | |
676 | const APInt &C1 = MaybeOp1Cst->Value; |
677 | const APInt &C2 = MaybeOp2Cst->Value; |
678 | switch (Opcode) { |
679 | default: |
680 | break; |
681 | case TargetOpcode::G_ADD: |
682 | return C1 + C2; |
683 | case TargetOpcode::G_PTR_ADD: |
684 | // Types can be of different width here. |
685 | // Result needs to be the same width as C1, so trunc or sext C2. |
686 | return C1 + C2.sextOrTrunc(width: C1.getBitWidth()); |
687 | case TargetOpcode::G_AND: |
688 | return C1 & C2; |
689 | case TargetOpcode::G_ASHR: |
690 | return C1.ashr(ShiftAmt: C2); |
691 | case TargetOpcode::G_LSHR: |
692 | return C1.lshr(ShiftAmt: C2); |
693 | case TargetOpcode::G_MUL: |
694 | return C1 * C2; |
695 | case TargetOpcode::G_OR: |
696 | return C1 | C2; |
697 | case TargetOpcode::G_SHL: |
698 | return C1 << C2; |
699 | case TargetOpcode::G_SUB: |
700 | return C1 - C2; |
701 | case TargetOpcode::G_XOR: |
702 | return C1 ^ C2; |
703 | case TargetOpcode::G_UDIV: |
704 | if (!C2.getBoolValue()) |
705 | break; |
706 | return C1.udiv(RHS: C2); |
707 | case TargetOpcode::G_SDIV: |
708 | if (!C2.getBoolValue()) |
709 | break; |
710 | return C1.sdiv(RHS: C2); |
711 | case TargetOpcode::G_UREM: |
712 | if (!C2.getBoolValue()) |
713 | break; |
714 | return C1.urem(RHS: C2); |
715 | case TargetOpcode::G_SREM: |
716 | if (!C2.getBoolValue()) |
717 | break; |
718 | return C1.srem(RHS: C2); |
719 | case TargetOpcode::G_SMIN: |
720 | return APIntOps::smin(A: C1, B: C2); |
721 | case TargetOpcode::G_SMAX: |
722 | return APIntOps::smax(A: C1, B: C2); |
723 | case TargetOpcode::G_UMIN: |
724 | return APIntOps::umin(A: C1, B: C2); |
725 | case TargetOpcode::G_UMAX: |
726 | return APIntOps::umax(A: C1, B: C2); |
727 | } |
728 | |
729 | return std::nullopt; |
730 | } |
731 | |
732 | std::optional<APFloat> |
733 | llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1, |
734 | const Register Op2, const MachineRegisterInfo &MRI) { |
735 | const ConstantFP *Op2Cst = getConstantFPVRegVal(VReg: Op2, MRI); |
736 | if (!Op2Cst) |
737 | return std::nullopt; |
738 | |
739 | const ConstantFP *Op1Cst = getConstantFPVRegVal(VReg: Op1, MRI); |
740 | if (!Op1Cst) |
741 | return std::nullopt; |
742 | |
743 | APFloat C1 = Op1Cst->getValueAPF(); |
744 | const APFloat &C2 = Op2Cst->getValueAPF(); |
745 | switch (Opcode) { |
746 | case TargetOpcode::G_FADD: |
747 | C1.add(RHS: C2, RM: APFloat::rmNearestTiesToEven); |
748 | return C1; |
749 | case TargetOpcode::G_FSUB: |
750 | C1.subtract(RHS: C2, RM: APFloat::rmNearestTiesToEven); |
751 | return C1; |
752 | case TargetOpcode::G_FMUL: |
753 | C1.multiply(RHS: C2, RM: APFloat::rmNearestTiesToEven); |
754 | return C1; |
755 | case TargetOpcode::G_FDIV: |
756 | C1.divide(RHS: C2, RM: APFloat::rmNearestTiesToEven); |
757 | return C1; |
758 | case TargetOpcode::G_FREM: |
759 | C1.mod(RHS: C2); |
760 | return C1; |
761 | case TargetOpcode::G_FCOPYSIGN: |
762 | C1.copySign(RHS: C2); |
763 | return C1; |
764 | case TargetOpcode::G_FMINNUM: |
765 | return minnum(A: C1, B: C2); |
766 | case TargetOpcode::G_FMAXNUM: |
767 | return maxnum(A: C1, B: C2); |
768 | case TargetOpcode::G_FMINIMUM: |
769 | return minimum(A: C1, B: C2); |
770 | case TargetOpcode::G_FMAXIMUM: |
771 | return maximum(A: C1, B: C2); |
772 | case TargetOpcode::G_FMINNUM_IEEE: |
773 | case TargetOpcode::G_FMAXNUM_IEEE: |
774 | // FIXME: These operations were unfortunately named. fminnum/fmaxnum do not |
775 | // follow the IEEE behavior for signaling nans and follow libm's fmin/fmax, |
776 | // and currently there isn't a nice wrapper in APFloat for the version with |
777 | // correct snan handling. |
778 | break; |
779 | default: |
780 | break; |
781 | } |
782 | |
783 | return std::nullopt; |
784 | } |
785 | |
786 | SmallVector<APInt> |
787 | llvm::ConstantFoldVectorBinop(unsigned Opcode, const Register Op1, |
788 | const Register Op2, |
789 | const MachineRegisterInfo &MRI) { |
790 | auto *SrcVec2 = getOpcodeDef<GBuildVector>(Reg: Op2, MRI); |
791 | if (!SrcVec2) |
792 | return SmallVector<APInt>(); |
793 | |
794 | auto *SrcVec1 = getOpcodeDef<GBuildVector>(Reg: Op1, MRI); |
795 | if (!SrcVec1) |
796 | return SmallVector<APInt>(); |
797 | |
798 | SmallVector<APInt> FoldedElements; |
799 | for (unsigned Idx = 0, E = SrcVec1->getNumSources(); Idx < E; ++Idx) { |
800 | auto MaybeCst = ConstantFoldBinOp(Opcode, Op1: SrcVec1->getSourceReg(I: Idx), |
801 | Op2: SrcVec2->getSourceReg(I: Idx), MRI); |
802 | if (!MaybeCst) |
803 | return SmallVector<APInt>(); |
804 | FoldedElements.push_back(Elt: *MaybeCst); |
805 | } |
806 | return FoldedElements; |
807 | } |
808 | |
809 | bool llvm::isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI, |
810 | bool SNaN) { |
811 | const MachineInstr *DefMI = MRI.getVRegDef(Reg: Val); |
812 | if (!DefMI) |
813 | return false; |
814 | |
815 | const TargetMachine& TM = DefMI->getMF()->getTarget(); |
816 | if (DefMI->getFlag(Flag: MachineInstr::FmNoNans) || TM.Options.NoNaNsFPMath) |
817 | return true; |
818 | |
819 | // If the value is a constant, we can obviously see if it is a NaN or not. |
820 | if (const ConstantFP *FPVal = getConstantFPVRegVal(VReg: Val, MRI)) { |
821 | return !FPVal->getValueAPF().isNaN() || |
822 | (SNaN && !FPVal->getValueAPF().isSignaling()); |
823 | } |
824 | |
825 | if (DefMI->getOpcode() == TargetOpcode::G_BUILD_VECTOR) { |
826 | for (const auto &Op : DefMI->uses()) |
827 | if (!isKnownNeverNaN(Val: Op.getReg(), MRI, SNaN)) |
828 | return false; |
829 | return true; |
830 | } |
831 | |
832 | switch (DefMI->getOpcode()) { |
833 | default: |
834 | break; |
835 | case TargetOpcode::G_FADD: |
836 | case TargetOpcode::G_FSUB: |
837 | case TargetOpcode::G_FMUL: |
838 | case TargetOpcode::G_FDIV: |
839 | case TargetOpcode::G_FREM: |
840 | case TargetOpcode::G_FSIN: |
841 | case TargetOpcode::G_FCOS: |
842 | case TargetOpcode::G_FTAN: |
843 | case TargetOpcode::G_FACOS: |
844 | case TargetOpcode::G_FASIN: |
845 | case TargetOpcode::G_FATAN: |
846 | case TargetOpcode::G_FATAN2: |
847 | case TargetOpcode::G_FCOSH: |
848 | case TargetOpcode::G_FSINH: |
849 | case TargetOpcode::G_FTANH: |
850 | case TargetOpcode::G_FMA: |
851 | case TargetOpcode::G_FMAD: |
852 | if (SNaN) |
853 | return true; |
854 | |
855 | // TODO: Need isKnownNeverInfinity |
856 | return false; |
857 | case TargetOpcode::G_FMINNUM_IEEE: |
858 | case TargetOpcode::G_FMAXNUM_IEEE: { |
859 | if (SNaN) |
860 | return true; |
861 | // This can return a NaN if either operand is an sNaN, or if both operands |
862 | // are NaN. |
863 | return (isKnownNeverNaN(Val: DefMI->getOperand(i: 1).getReg(), MRI) && |
864 | isKnownNeverSNaN(Val: DefMI->getOperand(i: 2).getReg(), MRI)) || |
865 | (isKnownNeverSNaN(Val: DefMI->getOperand(i: 1).getReg(), MRI) && |
866 | isKnownNeverNaN(Val: DefMI->getOperand(i: 2).getReg(), MRI)); |
867 | } |
868 | case TargetOpcode::G_FMINNUM: |
869 | case TargetOpcode::G_FMAXNUM: { |
870 | // Only one needs to be known not-nan, since it will be returned if the |
871 | // other ends up being one. |
872 | return isKnownNeverNaN(Val: DefMI->getOperand(i: 1).getReg(), MRI, SNaN) || |
873 | isKnownNeverNaN(Val: DefMI->getOperand(i: 2).getReg(), MRI, SNaN); |
874 | } |
875 | } |
876 | |
877 | if (SNaN) { |
878 | // FP operations quiet. For now, just handle the ones inserted during |
879 | // legalization. |
880 | switch (DefMI->getOpcode()) { |
881 | case TargetOpcode::G_FPEXT: |
882 | case TargetOpcode::G_FPTRUNC: |
883 | case TargetOpcode::G_FCANONICALIZE: |
884 | return true; |
885 | default: |
886 | return false; |
887 | } |
888 | } |
889 | |
890 | return false; |
891 | } |
892 | |
893 | Align llvm::inferAlignFromPtrInfo(MachineFunction &MF, |
894 | const MachinePointerInfo &MPO) { |
895 | auto PSV = dyn_cast_if_present<const PseudoSourceValue *>(Val: MPO.V); |
896 | if (auto FSPV = dyn_cast_or_null<FixedStackPseudoSourceValue>(Val: PSV)) { |
897 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
898 | return commonAlignment(A: MFI.getObjectAlign(ObjectIdx: FSPV->getFrameIndex()), |
899 | Offset: MPO.Offset); |
900 | } |
901 | |
902 | if (const Value *V = dyn_cast_if_present<const Value *>(Val: MPO.V)) { |
903 | const Module *M = MF.getFunction().getParent(); |
904 | return V->getPointerAlignment(DL: M->getDataLayout()); |
905 | } |
906 | |
907 | return Align(1); |
908 | } |
909 | |
910 | Register llvm::getFunctionLiveInPhysReg(MachineFunction &MF, |
911 | const TargetInstrInfo &TII, |
912 | MCRegister PhysReg, |
913 | const TargetRegisterClass &RC, |
914 | const DebugLoc &DL, LLT RegTy) { |
915 | MachineBasicBlock &EntryMBB = MF.front(); |
916 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
917 | Register LiveIn = MRI.getLiveInVirtReg(PReg: PhysReg); |
918 | if (LiveIn) { |
919 | MachineInstr *Def = MRI.getVRegDef(Reg: LiveIn); |
920 | if (Def) { |
921 | // FIXME: Should the verifier check this is in the entry block? |
922 | assert(Def->getParent() == &EntryMBB && "live-in copy not in entry block" ); |
923 | return LiveIn; |
924 | } |
925 | |
926 | // It's possible the incoming argument register and copy was added during |
927 | // lowering, but later deleted due to being/becoming dead. If this happens, |
928 | // re-insert the copy. |
929 | } else { |
930 | // The live in register was not present, so add it. |
931 | LiveIn = MF.addLiveIn(PReg: PhysReg, RC: &RC); |
932 | if (RegTy.isValid()) |
933 | MRI.setType(VReg: LiveIn, Ty: RegTy); |
934 | } |
935 | |
936 | BuildMI(BB&: EntryMBB, I: EntryMBB.begin(), MIMD: DL, MCID: TII.get(Opcode: TargetOpcode::COPY), DestReg: LiveIn) |
937 | .addReg(RegNo: PhysReg); |
938 | if (!EntryMBB.isLiveIn(Reg: PhysReg)) |
939 | EntryMBB.addLiveIn(PhysReg); |
940 | return LiveIn; |
941 | } |
942 | |
943 | std::optional<APInt> llvm::ConstantFoldExtOp(unsigned Opcode, |
944 | const Register Op1, uint64_t Imm, |
945 | const MachineRegisterInfo &MRI) { |
946 | auto MaybeOp1Cst = getIConstantVRegVal(VReg: Op1, MRI); |
947 | if (MaybeOp1Cst) { |
948 | switch (Opcode) { |
949 | default: |
950 | break; |
951 | case TargetOpcode::G_SEXT_INREG: { |
952 | LLT Ty = MRI.getType(Reg: Op1); |
953 | return MaybeOp1Cst->trunc(width: Imm).sext(width: Ty.getScalarSizeInBits()); |
954 | } |
955 | } |
956 | } |
957 | return std::nullopt; |
958 | } |
959 | |
960 | std::optional<APInt> llvm::ConstantFoldCastOp(unsigned Opcode, LLT DstTy, |
961 | const Register Op0, |
962 | const MachineRegisterInfo &MRI) { |
963 | std::optional<APInt> Val = getIConstantVRegVal(VReg: Op0, MRI); |
964 | if (!Val) |
965 | return Val; |
966 | |
967 | const unsigned DstSize = DstTy.getScalarSizeInBits(); |
968 | |
969 | switch (Opcode) { |
970 | case TargetOpcode::G_SEXT: |
971 | return Val->sext(width: DstSize); |
972 | case TargetOpcode::G_ZEXT: |
973 | case TargetOpcode::G_ANYEXT: |
974 | // TODO: DAG considers target preference when constant folding any_extend. |
975 | return Val->zext(width: DstSize); |
976 | default: |
977 | break; |
978 | } |
979 | |
980 | llvm_unreachable("unexpected cast opcode to constant fold" ); |
981 | } |
982 | |
983 | std::optional<APFloat> |
984 | llvm::ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy, Register Src, |
985 | const MachineRegisterInfo &MRI) { |
986 | assert(Opcode == TargetOpcode::G_SITOFP || Opcode == TargetOpcode::G_UITOFP); |
987 | if (auto MaybeSrcVal = getIConstantVRegVal(VReg: Src, MRI)) { |
988 | APFloat DstVal(getFltSemanticForLLT(Ty: DstTy)); |
989 | DstVal.convertFromAPInt(Input: *MaybeSrcVal, IsSigned: Opcode == TargetOpcode::G_SITOFP, |
990 | RM: APFloat::rmNearestTiesToEven); |
991 | return DstVal; |
992 | } |
993 | return std::nullopt; |
994 | } |
995 | |
996 | std::optional<SmallVector<unsigned>> |
997 | llvm::ConstantFoldCountZeros(Register Src, const MachineRegisterInfo &MRI, |
998 | std::function<unsigned(APInt)> CB) { |
999 | LLT Ty = MRI.getType(Reg: Src); |
1000 | SmallVector<unsigned> FoldedCTLZs; |
1001 | auto tryFoldScalar = [&](Register R) -> std::optional<unsigned> { |
1002 | auto MaybeCst = getIConstantVRegVal(VReg: R, MRI); |
1003 | if (!MaybeCst) |
1004 | return std::nullopt; |
1005 | return CB(*MaybeCst); |
1006 | }; |
1007 | if (Ty.isVector()) { |
1008 | // Try to constant fold each element. |
1009 | auto *BV = getOpcodeDef<GBuildVector>(Reg: Src, MRI); |
1010 | if (!BV) |
1011 | return std::nullopt; |
1012 | for (unsigned SrcIdx = 0; SrcIdx < BV->getNumSources(); ++SrcIdx) { |
1013 | if (auto MaybeFold = tryFoldScalar(BV->getSourceReg(I: SrcIdx))) { |
1014 | FoldedCTLZs.emplace_back(Args&: *MaybeFold); |
1015 | continue; |
1016 | } |
1017 | return std::nullopt; |
1018 | } |
1019 | return FoldedCTLZs; |
1020 | } |
1021 | if (auto MaybeCst = tryFoldScalar(Src)) { |
1022 | FoldedCTLZs.emplace_back(Args&: *MaybeCst); |
1023 | return FoldedCTLZs; |
1024 | } |
1025 | return std::nullopt; |
1026 | } |
1027 | |
1028 | std::optional<SmallVector<APInt>> |
1029 | llvm::ConstantFoldICmp(unsigned Pred, const Register Op1, const Register Op2, |
1030 | unsigned DstScalarSizeInBits, unsigned ExtOp, |
1031 | const MachineRegisterInfo &MRI) { |
1032 | assert(ExtOp == TargetOpcode::G_SEXT || ExtOp == TargetOpcode::G_ZEXT || |
1033 | ExtOp == TargetOpcode::G_ANYEXT); |
1034 | |
1035 | const LLT Ty = MRI.getType(Reg: Op1); |
1036 | |
1037 | auto GetICmpResultCst = [&](bool IsTrue) { |
1038 | if (IsTrue) |
1039 | return ExtOp == TargetOpcode::G_SEXT |
1040 | ? APInt::getAllOnes(numBits: DstScalarSizeInBits) |
1041 | : APInt::getOneBitSet(numBits: DstScalarSizeInBits, BitNo: 0); |
1042 | return APInt::getZero(numBits: DstScalarSizeInBits); |
1043 | }; |
1044 | |
1045 | auto TryFoldScalar = [&](Register LHS, Register RHS) -> std::optional<APInt> { |
1046 | auto RHSCst = getIConstantVRegVal(VReg: RHS, MRI); |
1047 | if (!RHSCst) |
1048 | return std::nullopt; |
1049 | auto LHSCst = getIConstantVRegVal(VReg: LHS, MRI); |
1050 | if (!LHSCst) |
1051 | return std::nullopt; |
1052 | |
1053 | switch (Pred) { |
1054 | case CmpInst::Predicate::ICMP_EQ: |
1055 | return GetICmpResultCst(LHSCst->eq(RHS: *RHSCst)); |
1056 | case CmpInst::Predicate::ICMP_NE: |
1057 | return GetICmpResultCst(LHSCst->ne(RHS: *RHSCst)); |
1058 | case CmpInst::Predicate::ICMP_UGT: |
1059 | return GetICmpResultCst(LHSCst->ugt(RHS: *RHSCst)); |
1060 | case CmpInst::Predicate::ICMP_UGE: |
1061 | return GetICmpResultCst(LHSCst->uge(RHS: *RHSCst)); |
1062 | case CmpInst::Predicate::ICMP_ULT: |
1063 | return GetICmpResultCst(LHSCst->ult(RHS: *RHSCst)); |
1064 | case CmpInst::Predicate::ICMP_ULE: |
1065 | return GetICmpResultCst(LHSCst->ule(RHS: *RHSCst)); |
1066 | case CmpInst::Predicate::ICMP_SGT: |
1067 | return GetICmpResultCst(LHSCst->sgt(RHS: *RHSCst)); |
1068 | case CmpInst::Predicate::ICMP_SGE: |
1069 | return GetICmpResultCst(LHSCst->sge(RHS: *RHSCst)); |
1070 | case CmpInst::Predicate::ICMP_SLT: |
1071 | return GetICmpResultCst(LHSCst->slt(RHS: *RHSCst)); |
1072 | case CmpInst::Predicate::ICMP_SLE: |
1073 | return GetICmpResultCst(LHSCst->sle(RHS: *RHSCst)); |
1074 | default: |
1075 | return std::nullopt; |
1076 | } |
1077 | }; |
1078 | |
1079 | SmallVector<APInt> FoldedICmps; |
1080 | |
1081 | if (Ty.isVector()) { |
1082 | // Try to constant fold each element. |
1083 | auto *BV1 = getOpcodeDef<GBuildVector>(Reg: Op1, MRI); |
1084 | auto *BV2 = getOpcodeDef<GBuildVector>(Reg: Op2, MRI); |
1085 | if (!BV1 || !BV2) |
1086 | return std::nullopt; |
1087 | assert(BV1->getNumSources() == BV2->getNumSources() && "Invalid vectors" ); |
1088 | for (unsigned I = 0; I < BV1->getNumSources(); ++I) { |
1089 | if (auto MaybeFold = |
1090 | TryFoldScalar(BV1->getSourceReg(I), BV2->getSourceReg(I))) { |
1091 | FoldedICmps.emplace_back(Args&: *MaybeFold); |
1092 | continue; |
1093 | } |
1094 | return std::nullopt; |
1095 | } |
1096 | return FoldedICmps; |
1097 | } |
1098 | |
1099 | if (auto MaybeCst = TryFoldScalar(Op1, Op2)) { |
1100 | FoldedICmps.emplace_back(Args&: *MaybeCst); |
1101 | return FoldedICmps; |
1102 | } |
1103 | |
1104 | return std::nullopt; |
1105 | } |
1106 | |
1107 | bool llvm::isKnownToBeAPowerOfTwo(Register Reg, const MachineRegisterInfo &MRI, |
1108 | GISelValueTracking *VT) { |
1109 | std::optional<DefinitionAndSourceRegister> DefSrcReg = |
1110 | getDefSrcRegIgnoringCopies(Reg, MRI); |
1111 | if (!DefSrcReg) |
1112 | return false; |
1113 | |
1114 | const MachineInstr &MI = *DefSrcReg->MI; |
1115 | const LLT Ty = MRI.getType(Reg); |
1116 | |
1117 | switch (MI.getOpcode()) { |
1118 | case TargetOpcode::G_CONSTANT: { |
1119 | unsigned BitWidth = Ty.getScalarSizeInBits(); |
1120 | const ConstantInt *CI = MI.getOperand(i: 1).getCImm(); |
1121 | return CI->getValue().zextOrTrunc(width: BitWidth).isPowerOf2(); |
1122 | } |
1123 | case TargetOpcode::G_SHL: { |
1124 | // A left-shift of a constant one will have exactly one bit set because |
1125 | // shifting the bit off the end is undefined. |
1126 | |
1127 | // TODO: Constant splat |
1128 | if (auto ConstLHS = getIConstantVRegVal(VReg: MI.getOperand(i: 1).getReg(), MRI)) { |
1129 | if (*ConstLHS == 1) |
1130 | return true; |
1131 | } |
1132 | |
1133 | break; |
1134 | } |
1135 | case TargetOpcode::G_LSHR: { |
1136 | if (auto ConstLHS = getIConstantVRegVal(VReg: MI.getOperand(i: 1).getReg(), MRI)) { |
1137 | if (ConstLHS->isSignMask()) |
1138 | return true; |
1139 | } |
1140 | |
1141 | break; |
1142 | } |
1143 | case TargetOpcode::G_BUILD_VECTOR: { |
1144 | // TODO: Probably should have a recursion depth guard since you could have |
1145 | // bitcasted vector elements. |
1146 | for (const MachineOperand &MO : llvm::drop_begin(RangeOrContainer: MI.operands())) |
1147 | if (!isKnownToBeAPowerOfTwo(Reg: MO.getReg(), MRI, VT)) |
1148 | return false; |
1149 | |
1150 | return true; |
1151 | } |
1152 | case TargetOpcode::G_BUILD_VECTOR_TRUNC: { |
1153 | // Only handle constants since we would need to know if number of leading |
1154 | // zeros is greater than the truncation amount. |
1155 | const unsigned BitWidth = Ty.getScalarSizeInBits(); |
1156 | for (const MachineOperand &MO : llvm::drop_begin(RangeOrContainer: MI.operands())) { |
1157 | auto Const = getIConstantVRegVal(VReg: MO.getReg(), MRI); |
1158 | if (!Const || !Const->zextOrTrunc(width: BitWidth).isPowerOf2()) |
1159 | return false; |
1160 | } |
1161 | |
1162 | return true; |
1163 | } |
1164 | default: |
1165 | break; |
1166 | } |
1167 | |
1168 | if (!VT) |
1169 | return false; |
1170 | |
1171 | // More could be done here, though the above checks are enough |
1172 | // to handle some common cases. |
1173 | |
1174 | // Fall back to computeKnownBits to catch other known cases. |
1175 | KnownBits Known = VT->getKnownBits(R: Reg); |
1176 | return (Known.countMaxPopulation() == 1) && (Known.countMinPopulation() == 1); |
1177 | } |
1178 | |
1179 | void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) { |
1180 | AU.addPreserved<StackProtector>(); |
1181 | } |
1182 | |
1183 | LLT llvm::getLCMType(LLT OrigTy, LLT TargetTy) { |
1184 | if (OrigTy.getSizeInBits() == TargetTy.getSizeInBits()) |
1185 | return OrigTy; |
1186 | |
1187 | if (OrigTy.isVector() && TargetTy.isVector()) { |
1188 | LLT OrigElt = OrigTy.getElementType(); |
1189 | LLT TargetElt = TargetTy.getElementType(); |
1190 | |
1191 | // TODO: The docstring for this function says the intention is to use this |
1192 | // function to build MERGE/UNMERGE instructions. It won't be the case that |
1193 | // we generate a MERGE/UNMERGE between fixed and scalable vector types. We |
1194 | // could implement getLCMType between the two in the future if there was a |
1195 | // need, but it is not worth it now as this function should not be used in |
1196 | // that way. |
1197 | assert(((OrigTy.isScalableVector() && !TargetTy.isFixedVector()) || |
1198 | (OrigTy.isFixedVector() && !TargetTy.isScalableVector())) && |
1199 | "getLCMType not implemented between fixed and scalable vectors." ); |
1200 | |
1201 | if (OrigElt.getSizeInBits() == TargetElt.getSizeInBits()) { |
1202 | int GCDMinElts = std::gcd(m: OrigTy.getElementCount().getKnownMinValue(), |
1203 | n: TargetTy.getElementCount().getKnownMinValue()); |
1204 | // Prefer the original element type. |
1205 | ElementCount Mul = OrigTy.getElementCount().multiplyCoefficientBy( |
1206 | RHS: TargetTy.getElementCount().getKnownMinValue()); |
1207 | return LLT::vector(EC: Mul.divideCoefficientBy(RHS: GCDMinElts), |
1208 | ScalarTy: OrigTy.getElementType()); |
1209 | } |
1210 | unsigned LCM = std::lcm(m: OrigTy.getSizeInBits().getKnownMinValue(), |
1211 | n: TargetTy.getSizeInBits().getKnownMinValue()); |
1212 | return LLT::vector( |
1213 | EC: ElementCount::get(MinVal: LCM / OrigElt.getSizeInBits(), Scalable: OrigTy.isScalable()), |
1214 | ScalarTy: OrigElt); |
1215 | } |
1216 | |
1217 | // One type is scalar, one type is vector |
1218 | if (OrigTy.isVector() || TargetTy.isVector()) { |
1219 | LLT VecTy = OrigTy.isVector() ? OrigTy : TargetTy; |
1220 | LLT ScalarTy = OrigTy.isVector() ? TargetTy : OrigTy; |
1221 | LLT EltTy = VecTy.getElementType(); |
1222 | LLT OrigEltTy = OrigTy.isVector() ? OrigTy.getElementType() : OrigTy; |
1223 | |
1224 | // Prefer scalar type from OrigTy. |
1225 | if (EltTy.getSizeInBits() == ScalarTy.getSizeInBits()) |
1226 | return LLT::vector(EC: VecTy.getElementCount(), ScalarTy: OrigEltTy); |
1227 | |
1228 | // Different size scalars. Create vector with the same total size. |
1229 | // LCM will take fixed/scalable from VecTy. |
1230 | unsigned LCM = std::lcm(m: EltTy.getSizeInBits().getFixedValue() * |
1231 | VecTy.getElementCount().getKnownMinValue(), |
1232 | n: ScalarTy.getSizeInBits().getFixedValue()); |
1233 | // Prefer type from OrigTy |
1234 | return LLT::vector(EC: ElementCount::get(MinVal: LCM / OrigEltTy.getSizeInBits(), |
1235 | Scalable: VecTy.getElementCount().isScalable()), |
1236 | ScalarTy: OrigEltTy); |
1237 | } |
1238 | |
1239 | // At this point, both types are scalars of different size |
1240 | unsigned LCM = std::lcm(m: OrigTy.getSizeInBits().getFixedValue(), |
1241 | n: TargetTy.getSizeInBits().getFixedValue()); |
1242 | // Preserve pointer types. |
1243 | if (LCM == OrigTy.getSizeInBits()) |
1244 | return OrigTy; |
1245 | if (LCM == TargetTy.getSizeInBits()) |
1246 | return TargetTy; |
1247 | return LLT::scalar(SizeInBits: LCM); |
1248 | } |
1249 | |
1250 | LLT llvm::getCoverTy(LLT OrigTy, LLT TargetTy) { |
1251 | |
1252 | if ((OrigTy.isScalableVector() && TargetTy.isFixedVector()) || |
1253 | (OrigTy.isFixedVector() && TargetTy.isScalableVector())) |
1254 | llvm_unreachable( |
1255 | "getCoverTy not implemented between fixed and scalable vectors." ); |
1256 | |
1257 | if (!OrigTy.isVector() || !TargetTy.isVector() || OrigTy == TargetTy || |
1258 | (OrigTy.getScalarSizeInBits() != TargetTy.getScalarSizeInBits())) |
1259 | return getLCMType(OrigTy, TargetTy); |
1260 | |
1261 | unsigned OrigTyNumElts = OrigTy.getElementCount().getKnownMinValue(); |
1262 | unsigned TargetTyNumElts = TargetTy.getElementCount().getKnownMinValue(); |
1263 | if (OrigTyNumElts % TargetTyNumElts == 0) |
1264 | return OrigTy; |
1265 | |
1266 | unsigned NumElts = alignTo(Value: OrigTyNumElts, Align: TargetTyNumElts); |
1267 | return LLT::scalarOrVector(EC: ElementCount::getFixed(MinVal: NumElts), |
1268 | ScalarTy: OrigTy.getElementType()); |
1269 | } |
1270 | |
1271 | LLT llvm::getGCDType(LLT OrigTy, LLT TargetTy) { |
1272 | if (OrigTy.getSizeInBits() == TargetTy.getSizeInBits()) |
1273 | return OrigTy; |
1274 | |
1275 | if (OrigTy.isVector() && TargetTy.isVector()) { |
1276 | LLT OrigElt = OrigTy.getElementType(); |
1277 | |
1278 | // TODO: The docstring for this function says the intention is to use this |
1279 | // function to build MERGE/UNMERGE instructions. It won't be the case that |
1280 | // we generate a MERGE/UNMERGE between fixed and scalable vector types. We |
1281 | // could implement getGCDType between the two in the future if there was a |
1282 | // need, but it is not worth it now as this function should not be used in |
1283 | // that way. |
1284 | assert(((OrigTy.isScalableVector() && !TargetTy.isFixedVector()) || |
1285 | (OrigTy.isFixedVector() && !TargetTy.isScalableVector())) && |
1286 | "getGCDType not implemented between fixed and scalable vectors." ); |
1287 | |
1288 | unsigned GCD = std::gcd(m: OrigTy.getSizeInBits().getKnownMinValue(), |
1289 | n: TargetTy.getSizeInBits().getKnownMinValue()); |
1290 | if (GCD == OrigElt.getSizeInBits()) |
1291 | return LLT::scalarOrVector(EC: ElementCount::get(MinVal: 1, Scalable: OrigTy.isScalable()), |
1292 | ScalarTy: OrigElt); |
1293 | |
1294 | // Cannot produce original element type, but both have vscale in common. |
1295 | if (GCD < OrigElt.getSizeInBits()) |
1296 | return LLT::scalarOrVector(EC: ElementCount::get(MinVal: 1, Scalable: OrigTy.isScalable()), |
1297 | ScalarSize: GCD); |
1298 | |
1299 | return LLT::vector( |
1300 | EC: ElementCount::get(MinVal: GCD / OrigElt.getSizeInBits().getFixedValue(), |
1301 | Scalable: OrigTy.isScalable()), |
1302 | ScalarTy: OrigElt); |
1303 | } |
1304 | |
1305 | // If one type is vector and the element size matches the scalar size, then |
1306 | // the gcd is the scalar type. |
1307 | if (OrigTy.isVector() && |
1308 | OrigTy.getElementType().getSizeInBits() == TargetTy.getSizeInBits()) |
1309 | return OrigTy.getElementType(); |
1310 | if (TargetTy.isVector() && |
1311 | TargetTy.getElementType().getSizeInBits() == OrigTy.getSizeInBits()) |
1312 | return OrigTy; |
1313 | |
1314 | // At this point, both types are either scalars of different type or one is a |
1315 | // vector and one is a scalar. If both types are scalars, the GCD type is the |
1316 | // GCD between the two scalar sizes. If one is vector and one is scalar, then |
1317 | // the GCD type is the GCD between the scalar and the vector element size. |
1318 | LLT OrigScalar = OrigTy.getScalarType(); |
1319 | LLT TargetScalar = TargetTy.getScalarType(); |
1320 | unsigned GCD = std::gcd(m: OrigScalar.getSizeInBits().getFixedValue(), |
1321 | n: TargetScalar.getSizeInBits().getFixedValue()); |
1322 | return LLT::scalar(SizeInBits: GCD); |
1323 | } |
1324 | |
1325 | std::optional<int> llvm::getSplatIndex(MachineInstr &MI) { |
1326 | assert(MI.getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR && |
1327 | "Only G_SHUFFLE_VECTOR can have a splat index!" ); |
1328 | ArrayRef<int> Mask = MI.getOperand(i: 3).getShuffleMask(); |
1329 | auto FirstDefinedIdx = find_if(Range&: Mask, P: [](int Elt) { return Elt >= 0; }); |
1330 | |
1331 | // If all elements are undefined, this shuffle can be considered a splat. |
1332 | // Return 0 for better potential for callers to simplify. |
1333 | if (FirstDefinedIdx == Mask.end()) |
1334 | return 0; |
1335 | |
1336 | // Make sure all remaining elements are either undef or the same |
1337 | // as the first non-undef value. |
1338 | int SplatValue = *FirstDefinedIdx; |
1339 | if (any_of(Range: make_range(x: std::next(x: FirstDefinedIdx), y: Mask.end()), |
1340 | P: [&SplatValue](int Elt) { return Elt >= 0 && Elt != SplatValue; })) |
1341 | return std::nullopt; |
1342 | |
1343 | return SplatValue; |
1344 | } |
1345 | |
1346 | static bool isBuildVectorOp(unsigned Opcode) { |
1347 | return Opcode == TargetOpcode::G_BUILD_VECTOR || |
1348 | Opcode == TargetOpcode::G_BUILD_VECTOR_TRUNC; |
1349 | } |
1350 | |
1351 | namespace { |
1352 | |
1353 | std::optional<ValueAndVReg> getAnyConstantSplat(Register VReg, |
1354 | const MachineRegisterInfo &MRI, |
1355 | bool AllowUndef) { |
1356 | MachineInstr *MI = getDefIgnoringCopies(Reg: VReg, MRI); |
1357 | if (!MI) |
1358 | return std::nullopt; |
1359 | |
1360 | bool isConcatVectorsOp = MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS; |
1361 | if (!isBuildVectorOp(Opcode: MI->getOpcode()) && !isConcatVectorsOp) |
1362 | return std::nullopt; |
1363 | |
1364 | std::optional<ValueAndVReg> SplatValAndReg; |
1365 | for (MachineOperand &Op : MI->uses()) { |
1366 | Register Element = Op.getReg(); |
1367 | // If we have a G_CONCAT_VECTOR, we recursively look into the |
1368 | // vectors that we're concatenating to see if they're splats. |
1369 | auto ElementValAndReg = |
1370 | isConcatVectorsOp |
1371 | ? getAnyConstantSplat(VReg: Element, MRI, AllowUndef) |
1372 | : getAnyConstantVRegValWithLookThrough(VReg: Element, MRI, LookThroughInstrs: true, LookThroughAnyExt: true); |
1373 | |
1374 | // If AllowUndef, treat undef as value that will result in a constant splat. |
1375 | if (!ElementValAndReg) { |
1376 | if (AllowUndef && isa<GImplicitDef>(Val: MRI.getVRegDef(Reg: Element))) |
1377 | continue; |
1378 | return std::nullopt; |
1379 | } |
1380 | |
1381 | // Record splat value |
1382 | if (!SplatValAndReg) |
1383 | SplatValAndReg = ElementValAndReg; |
1384 | |
1385 | // Different constant than the one already recorded, not a constant splat. |
1386 | if (SplatValAndReg->Value != ElementValAndReg->Value) |
1387 | return std::nullopt; |
1388 | } |
1389 | |
1390 | return SplatValAndReg; |
1391 | } |
1392 | |
1393 | } // end anonymous namespace |
1394 | |
1395 | bool llvm::isBuildVectorConstantSplat(const Register Reg, |
1396 | const MachineRegisterInfo &MRI, |
1397 | int64_t SplatValue, bool AllowUndef) { |
1398 | if (auto SplatValAndReg = getAnyConstantSplat(VReg: Reg, MRI, AllowUndef)) |
1399 | return SplatValAndReg->Value.getSExtValue() == SplatValue; |
1400 | |
1401 | return false; |
1402 | } |
1403 | |
1404 | bool llvm::isBuildVectorConstantSplat(const MachineInstr &MI, |
1405 | const MachineRegisterInfo &MRI, |
1406 | int64_t SplatValue, bool AllowUndef) { |
1407 | return isBuildVectorConstantSplat(Reg: MI.getOperand(i: 0).getReg(), MRI, SplatValue, |
1408 | AllowUndef); |
1409 | } |
1410 | |
1411 | std::optional<APInt> |
1412 | llvm::getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI) { |
1413 | if (auto SplatValAndReg = |
1414 | getAnyConstantSplat(VReg: Reg, MRI, /* AllowUndef */ false)) { |
1415 | if (std::optional<ValueAndVReg> ValAndVReg = |
1416 | getIConstantVRegValWithLookThrough(VReg: SplatValAndReg->VReg, MRI)) |
1417 | return ValAndVReg->Value; |
1418 | } |
1419 | |
1420 | return std::nullopt; |
1421 | } |
1422 | |
1423 | std::optional<APInt> |
1424 | llvm::getIConstantSplatVal(const MachineInstr &MI, |
1425 | const MachineRegisterInfo &MRI) { |
1426 | return getIConstantSplatVal(Reg: MI.getOperand(i: 0).getReg(), MRI); |
1427 | } |
1428 | |
1429 | std::optional<int64_t> |
1430 | llvm::getIConstantSplatSExtVal(const Register Reg, |
1431 | const MachineRegisterInfo &MRI) { |
1432 | if (auto SplatValAndReg = |
1433 | getAnyConstantSplat(VReg: Reg, MRI, /* AllowUndef */ false)) |
1434 | return getIConstantVRegSExtVal(VReg: SplatValAndReg->VReg, MRI); |
1435 | return std::nullopt; |
1436 | } |
1437 | |
1438 | std::optional<int64_t> |
1439 | llvm::getIConstantSplatSExtVal(const MachineInstr &MI, |
1440 | const MachineRegisterInfo &MRI) { |
1441 | return getIConstantSplatSExtVal(Reg: MI.getOperand(i: 0).getReg(), MRI); |
1442 | } |
1443 | |
1444 | std::optional<FPValueAndVReg> |
1445 | llvm::getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, |
1446 | bool AllowUndef) { |
1447 | if (auto SplatValAndReg = getAnyConstantSplat(VReg, MRI, AllowUndef)) |
1448 | return getFConstantVRegValWithLookThrough(VReg: SplatValAndReg->VReg, MRI); |
1449 | return std::nullopt; |
1450 | } |
1451 | |
1452 | bool llvm::isBuildVectorAllZeros(const MachineInstr &MI, |
1453 | const MachineRegisterInfo &MRI, |
1454 | bool AllowUndef) { |
1455 | return isBuildVectorConstantSplat(MI, MRI, SplatValue: 0, AllowUndef); |
1456 | } |
1457 | |
1458 | bool llvm::isBuildVectorAllOnes(const MachineInstr &MI, |
1459 | const MachineRegisterInfo &MRI, |
1460 | bool AllowUndef) { |
1461 | return isBuildVectorConstantSplat(MI, MRI, SplatValue: -1, AllowUndef); |
1462 | } |
1463 | |
1464 | std::optional<RegOrConstant> |
1465 | llvm::getVectorSplat(const MachineInstr &MI, const MachineRegisterInfo &MRI) { |
1466 | unsigned Opc = MI.getOpcode(); |
1467 | if (!isBuildVectorOp(Opcode: Opc)) |
1468 | return std::nullopt; |
1469 | if (auto Splat = getIConstantSplatSExtVal(MI, MRI)) |
1470 | return RegOrConstant(*Splat); |
1471 | auto Reg = MI.getOperand(i: 1).getReg(); |
1472 | if (any_of(Range: drop_begin(RangeOrContainer: MI.operands(), N: 2), |
1473 | P: [&Reg](const MachineOperand &Op) { return Op.getReg() != Reg; })) |
1474 | return std::nullopt; |
1475 | return RegOrConstant(Reg); |
1476 | } |
1477 | |
1478 | static bool isConstantScalar(const MachineInstr &MI, |
1479 | const MachineRegisterInfo &MRI, |
1480 | bool AllowFP = true, |
1481 | bool AllowOpaqueConstants = true) { |
1482 | switch (MI.getOpcode()) { |
1483 | case TargetOpcode::G_CONSTANT: |
1484 | case TargetOpcode::G_IMPLICIT_DEF: |
1485 | return true; |
1486 | case TargetOpcode::G_FCONSTANT: |
1487 | return AllowFP; |
1488 | case TargetOpcode::G_GLOBAL_VALUE: |
1489 | case TargetOpcode::G_FRAME_INDEX: |
1490 | case TargetOpcode::G_BLOCK_ADDR: |
1491 | case TargetOpcode::G_JUMP_TABLE: |
1492 | return AllowOpaqueConstants; |
1493 | default: |
1494 | return false; |
1495 | } |
1496 | } |
1497 | |
1498 | bool llvm::isConstantOrConstantVector(MachineInstr &MI, |
1499 | const MachineRegisterInfo &MRI) { |
1500 | Register Def = MI.getOperand(i: 0).getReg(); |
1501 | if (auto C = getIConstantVRegValWithLookThrough(VReg: Def, MRI)) |
1502 | return true; |
1503 | GBuildVector *BV = dyn_cast<GBuildVector>(Val: &MI); |
1504 | if (!BV) |
1505 | return false; |
1506 | for (unsigned SrcIdx = 0; SrcIdx < BV->getNumSources(); ++SrcIdx) { |
1507 | if (getIConstantVRegValWithLookThrough(VReg: BV->getSourceReg(I: SrcIdx), MRI) || |
1508 | getOpcodeDef<GImplicitDef>(Reg: BV->getSourceReg(I: SrcIdx), MRI)) |
1509 | continue; |
1510 | return false; |
1511 | } |
1512 | return true; |
1513 | } |
1514 | |
1515 | bool llvm::isConstantOrConstantVector(const MachineInstr &MI, |
1516 | const MachineRegisterInfo &MRI, |
1517 | bool AllowFP, bool AllowOpaqueConstants) { |
1518 | if (isConstantScalar(MI, MRI, AllowFP, AllowOpaqueConstants)) |
1519 | return true; |
1520 | |
1521 | if (!isBuildVectorOp(Opcode: MI.getOpcode())) |
1522 | return false; |
1523 | |
1524 | const unsigned NumOps = MI.getNumOperands(); |
1525 | for (unsigned I = 1; I != NumOps; ++I) { |
1526 | const MachineInstr *ElementDef = MRI.getVRegDef(Reg: MI.getOperand(i: I).getReg()); |
1527 | if (!isConstantScalar(MI: *ElementDef, MRI, AllowFP, AllowOpaqueConstants)) |
1528 | return false; |
1529 | } |
1530 | |
1531 | return true; |
1532 | } |
1533 | |
1534 | std::optional<APInt> |
1535 | llvm::isConstantOrConstantSplatVector(MachineInstr &MI, |
1536 | const MachineRegisterInfo &MRI) { |
1537 | Register Def = MI.getOperand(i: 0).getReg(); |
1538 | if (auto C = getIConstantVRegValWithLookThrough(VReg: Def, MRI)) |
1539 | return C->Value; |
1540 | auto MaybeCst = getIConstantSplatSExtVal(MI, MRI); |
1541 | if (!MaybeCst) |
1542 | return std::nullopt; |
1543 | const unsigned ScalarSize = MRI.getType(Reg: Def).getScalarSizeInBits(); |
1544 | return APInt(ScalarSize, *MaybeCst, true); |
1545 | } |
1546 | |
1547 | std::optional<APFloat> |
1548 | llvm::isConstantOrConstantSplatVectorFP(MachineInstr &MI, |
1549 | const MachineRegisterInfo &MRI) { |
1550 | Register Def = MI.getOperand(i: 0).getReg(); |
1551 | if (auto FpConst = getFConstantVRegValWithLookThrough(VReg: Def, MRI)) |
1552 | return FpConst->Value; |
1553 | auto MaybeCstFP = getFConstantSplat(VReg: Def, MRI, /*allowUndef=*/AllowUndef: false); |
1554 | if (!MaybeCstFP) |
1555 | return std::nullopt; |
1556 | return MaybeCstFP->Value; |
1557 | } |
1558 | |
1559 | bool llvm::isNullOrNullSplat(const MachineInstr &MI, |
1560 | const MachineRegisterInfo &MRI, bool AllowUndefs) { |
1561 | switch (MI.getOpcode()) { |
1562 | case TargetOpcode::G_IMPLICIT_DEF: |
1563 | return AllowUndefs; |
1564 | case TargetOpcode::G_CONSTANT: |
1565 | return MI.getOperand(i: 1).getCImm()->isNullValue(); |
1566 | case TargetOpcode::G_FCONSTANT: { |
1567 | const ConstantFP *FPImm = MI.getOperand(i: 1).getFPImm(); |
1568 | return FPImm->isZero() && !FPImm->isNegative(); |
1569 | } |
1570 | default: |
1571 | if (!AllowUndefs) // TODO: isBuildVectorAllZeros assumes undef is OK already |
1572 | return false; |
1573 | return isBuildVectorAllZeros(MI, MRI); |
1574 | } |
1575 | } |
1576 | |
1577 | bool llvm::isAllOnesOrAllOnesSplat(const MachineInstr &MI, |
1578 | const MachineRegisterInfo &MRI, |
1579 | bool AllowUndefs) { |
1580 | switch (MI.getOpcode()) { |
1581 | case TargetOpcode::G_IMPLICIT_DEF: |
1582 | return AllowUndefs; |
1583 | case TargetOpcode::G_CONSTANT: |
1584 | return MI.getOperand(i: 1).getCImm()->isAllOnesValue(); |
1585 | default: |
1586 | if (!AllowUndefs) // TODO: isBuildVectorAllOnes assumes undef is OK already |
1587 | return false; |
1588 | return isBuildVectorAllOnes(MI, MRI); |
1589 | } |
1590 | } |
1591 | |
1592 | bool llvm::matchUnaryPredicate( |
1593 | const MachineRegisterInfo &MRI, Register Reg, |
1594 | std::function<bool(const Constant *ConstVal)> Match, bool AllowUndefs) { |
1595 | |
1596 | const MachineInstr *Def = getDefIgnoringCopies(Reg, MRI); |
1597 | if (AllowUndefs && Def->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) |
1598 | return Match(nullptr); |
1599 | |
1600 | // TODO: Also handle fconstant |
1601 | if (Def->getOpcode() == TargetOpcode::G_CONSTANT) |
1602 | return Match(Def->getOperand(i: 1).getCImm()); |
1603 | |
1604 | if (Def->getOpcode() != TargetOpcode::G_BUILD_VECTOR) |
1605 | return false; |
1606 | |
1607 | for (unsigned I = 1, E = Def->getNumOperands(); I != E; ++I) { |
1608 | Register SrcElt = Def->getOperand(i: I).getReg(); |
1609 | const MachineInstr *SrcDef = getDefIgnoringCopies(Reg: SrcElt, MRI); |
1610 | if (AllowUndefs && SrcDef->getOpcode() == TargetOpcode::G_IMPLICIT_DEF) { |
1611 | if (!Match(nullptr)) |
1612 | return false; |
1613 | continue; |
1614 | } |
1615 | |
1616 | if (SrcDef->getOpcode() != TargetOpcode::G_CONSTANT || |
1617 | !Match(SrcDef->getOperand(i: 1).getCImm())) |
1618 | return false; |
1619 | } |
1620 | |
1621 | return true; |
1622 | } |
1623 | |
1624 | bool llvm::isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector, |
1625 | bool IsFP) { |
1626 | switch (TLI.getBooleanContents(isVec: IsVector, isFloat: IsFP)) { |
1627 | case TargetLowering::UndefinedBooleanContent: |
1628 | return Val & 0x1; |
1629 | case TargetLowering::ZeroOrOneBooleanContent: |
1630 | return Val == 1; |
1631 | case TargetLowering::ZeroOrNegativeOneBooleanContent: |
1632 | return Val == -1; |
1633 | } |
1634 | llvm_unreachable("Invalid boolean contents" ); |
1635 | } |
1636 | |
1637 | bool llvm::isConstFalseVal(const TargetLowering &TLI, int64_t Val, |
1638 | bool IsVector, bool IsFP) { |
1639 | switch (TLI.getBooleanContents(isVec: IsVector, isFloat: IsFP)) { |
1640 | case TargetLowering::UndefinedBooleanContent: |
1641 | return ~Val & 0x1; |
1642 | case TargetLowering::ZeroOrOneBooleanContent: |
1643 | case TargetLowering::ZeroOrNegativeOneBooleanContent: |
1644 | return Val == 0; |
1645 | } |
1646 | llvm_unreachable("Invalid boolean contents" ); |
1647 | } |
1648 | |
1649 | int64_t llvm::getICmpTrueVal(const TargetLowering &TLI, bool IsVector, |
1650 | bool IsFP) { |
1651 | switch (TLI.getBooleanContents(isVec: IsVector, isFloat: IsFP)) { |
1652 | case TargetLowering::UndefinedBooleanContent: |
1653 | case TargetLowering::ZeroOrOneBooleanContent: |
1654 | return 1; |
1655 | case TargetLowering::ZeroOrNegativeOneBooleanContent: |
1656 | return -1; |
1657 | } |
1658 | llvm_unreachable("Invalid boolean contents" ); |
1659 | } |
1660 | |
1661 | void llvm::saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI, |
1662 | LostDebugLocObserver *LocObserver, |
1663 | SmallInstListTy &DeadInstChain) { |
1664 | for (MachineOperand &Op : MI.uses()) { |
1665 | if (Op.isReg() && Op.getReg().isVirtual()) |
1666 | DeadInstChain.insert(I: MRI.getVRegDef(Reg: Op.getReg())); |
1667 | } |
1668 | LLVM_DEBUG(dbgs() << MI << "Is dead; erasing.\n" ); |
1669 | DeadInstChain.remove(I: &MI); |
1670 | MI.eraseFromParent(); |
1671 | if (LocObserver) |
1672 | LocObserver->checkpoint(CheckDebugLocs: false); |
1673 | } |
1674 | |
1675 | void llvm::eraseInstrs(ArrayRef<MachineInstr *> DeadInstrs, |
1676 | MachineRegisterInfo &MRI, |
1677 | LostDebugLocObserver *LocObserver) { |
1678 | SmallInstListTy DeadInstChain; |
1679 | for (MachineInstr *MI : DeadInstrs) |
1680 | saveUsesAndErase(MI&: *MI, MRI, LocObserver, DeadInstChain); |
1681 | |
1682 | while (!DeadInstChain.empty()) { |
1683 | MachineInstr *Inst = DeadInstChain.pop_back_val(); |
1684 | if (!isTriviallyDead(MI: *Inst, MRI)) |
1685 | continue; |
1686 | saveUsesAndErase(MI&: *Inst, MRI, LocObserver, DeadInstChain); |
1687 | } |
1688 | } |
1689 | |
1690 | void llvm::eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI, |
1691 | LostDebugLocObserver *LocObserver) { |
1692 | return eraseInstrs(DeadInstrs: {&MI}, MRI, LocObserver); |
1693 | } |
1694 | |
1695 | void llvm::salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI) { |
1696 | for (auto &Def : MI.defs()) { |
1697 | assert(Def.isReg() && "Must be a reg" ); |
1698 | |
1699 | SmallVector<MachineOperand *, 16> DbgUsers; |
1700 | for (auto &MOUse : MRI.use_operands(Reg: Def.getReg())) { |
1701 | MachineInstr *DbgValue = MOUse.getParent(); |
1702 | // Ignore partially formed DBG_VALUEs. |
1703 | if (DbgValue->isNonListDebugValue() && DbgValue->getNumOperands() == 4) { |
1704 | DbgUsers.push_back(Elt: &MOUse); |
1705 | } |
1706 | } |
1707 | |
1708 | if (!DbgUsers.empty()) { |
1709 | salvageDebugInfoForDbgValue(MRI, MI, DbgUsers); |
1710 | } |
1711 | } |
1712 | } |
1713 | |
1714 | bool llvm::isPreISelGenericFloatingPointOpcode(unsigned Opc) { |
1715 | switch (Opc) { |
1716 | case TargetOpcode::G_FABS: |
1717 | case TargetOpcode::G_FADD: |
1718 | case TargetOpcode::G_FCANONICALIZE: |
1719 | case TargetOpcode::G_FCEIL: |
1720 | case TargetOpcode::G_FCONSTANT: |
1721 | case TargetOpcode::G_FCOPYSIGN: |
1722 | case TargetOpcode::G_FCOS: |
1723 | case TargetOpcode::G_FDIV: |
1724 | case TargetOpcode::G_FEXP2: |
1725 | case TargetOpcode::G_FEXP: |
1726 | case TargetOpcode::G_FFLOOR: |
1727 | case TargetOpcode::G_FLOG10: |
1728 | case TargetOpcode::G_FLOG2: |
1729 | case TargetOpcode::G_FLOG: |
1730 | case TargetOpcode::G_FMA: |
1731 | case TargetOpcode::G_FMAD: |
1732 | case TargetOpcode::G_FMAXIMUM: |
1733 | case TargetOpcode::G_FMAXNUM: |
1734 | case TargetOpcode::G_FMAXNUM_IEEE: |
1735 | case TargetOpcode::G_FMINIMUM: |
1736 | case TargetOpcode::G_FMINNUM: |
1737 | case TargetOpcode::G_FMINNUM_IEEE: |
1738 | case TargetOpcode::G_FMUL: |
1739 | case TargetOpcode::G_FNEARBYINT: |
1740 | case TargetOpcode::G_FNEG: |
1741 | case TargetOpcode::G_FPEXT: |
1742 | case TargetOpcode::G_FPOW: |
1743 | case TargetOpcode::G_FPTRUNC: |
1744 | case TargetOpcode::G_FREM: |
1745 | case TargetOpcode::G_FRINT: |
1746 | case TargetOpcode::G_FSIN: |
1747 | case TargetOpcode::G_FTAN: |
1748 | case TargetOpcode::G_FACOS: |
1749 | case TargetOpcode::G_FASIN: |
1750 | case TargetOpcode::G_FATAN: |
1751 | case TargetOpcode::G_FATAN2: |
1752 | case TargetOpcode::G_FCOSH: |
1753 | case TargetOpcode::G_FSINH: |
1754 | case TargetOpcode::G_FTANH: |
1755 | case TargetOpcode::G_FSQRT: |
1756 | case TargetOpcode::G_FSUB: |
1757 | case TargetOpcode::G_INTRINSIC_ROUND: |
1758 | case TargetOpcode::G_INTRINSIC_ROUNDEVEN: |
1759 | case TargetOpcode::G_INTRINSIC_TRUNC: |
1760 | return true; |
1761 | default: |
1762 | return false; |
1763 | } |
1764 | } |
1765 | |
1766 | /// Shifts return poison if shiftwidth is larger than the bitwidth. |
1767 | static bool shiftAmountKnownInRange(Register ShiftAmount, |
1768 | const MachineRegisterInfo &MRI) { |
1769 | LLT Ty = MRI.getType(Reg: ShiftAmount); |
1770 | |
1771 | if (Ty.isScalableVector()) |
1772 | return false; // Can't tell, just return false to be safe |
1773 | |
1774 | if (Ty.isScalar()) { |
1775 | std::optional<ValueAndVReg> Val = |
1776 | getIConstantVRegValWithLookThrough(VReg: ShiftAmount, MRI); |
1777 | if (!Val) |
1778 | return false; |
1779 | return Val->Value.ult(RHS: Ty.getScalarSizeInBits()); |
1780 | } |
1781 | |
1782 | GBuildVector *BV = getOpcodeDef<GBuildVector>(Reg: ShiftAmount, MRI); |
1783 | if (!BV) |
1784 | return false; |
1785 | |
1786 | unsigned Sources = BV->getNumSources(); |
1787 | for (unsigned I = 0; I < Sources; ++I) { |
1788 | std::optional<ValueAndVReg> Val = |
1789 | getIConstantVRegValWithLookThrough(VReg: BV->getSourceReg(I), MRI); |
1790 | if (!Val) |
1791 | return false; |
1792 | if (!Val->Value.ult(RHS: Ty.getScalarSizeInBits())) |
1793 | return false; |
1794 | } |
1795 | |
1796 | return true; |
1797 | } |
1798 | |
1799 | namespace { |
1800 | enum class UndefPoisonKind { |
1801 | PoisonOnly = (1 << 0), |
1802 | UndefOnly = (1 << 1), |
1803 | UndefOrPoison = PoisonOnly | UndefOnly, |
1804 | }; |
1805 | } |
1806 | |
1807 | static bool includesPoison(UndefPoisonKind Kind) { |
1808 | return (unsigned(Kind) & unsigned(UndefPoisonKind::PoisonOnly)) != 0; |
1809 | } |
1810 | |
1811 | static bool includesUndef(UndefPoisonKind Kind) { |
1812 | return (unsigned(Kind) & unsigned(UndefPoisonKind::UndefOnly)) != 0; |
1813 | } |
1814 | |
1815 | static bool canCreateUndefOrPoison(Register Reg, const MachineRegisterInfo &MRI, |
1816 | bool ConsiderFlagsAndMetadata, |
1817 | UndefPoisonKind Kind) { |
1818 | MachineInstr *RegDef = MRI.getVRegDef(Reg); |
1819 | |
1820 | if (ConsiderFlagsAndMetadata && includesPoison(Kind)) |
1821 | if (auto *GMI = dyn_cast<GenericMachineInstr>(Val: RegDef)) |
1822 | if (GMI->hasPoisonGeneratingFlags()) |
1823 | return true; |
1824 | |
1825 | // Check whether opcode is a poison/undef-generating operation. |
1826 | switch (RegDef->getOpcode()) { |
1827 | case TargetOpcode::G_BUILD_VECTOR: |
1828 | case TargetOpcode::G_CONSTANT_FOLD_BARRIER: |
1829 | return false; |
1830 | case TargetOpcode::G_SHL: |
1831 | case TargetOpcode::G_ASHR: |
1832 | case TargetOpcode::G_LSHR: |
1833 | return includesPoison(Kind) && |
1834 | !shiftAmountKnownInRange(ShiftAmount: RegDef->getOperand(i: 2).getReg(), MRI); |
1835 | case TargetOpcode::G_FPTOSI: |
1836 | case TargetOpcode::G_FPTOUI: |
1837 | // fptosi/ui yields poison if the resulting value does not fit in the |
1838 | // destination type. |
1839 | return true; |
1840 | case TargetOpcode::G_CTLZ: |
1841 | case TargetOpcode::G_CTTZ: |
1842 | case TargetOpcode::G_ABS: |
1843 | case TargetOpcode::G_CTPOP: |
1844 | case TargetOpcode::G_BSWAP: |
1845 | case TargetOpcode::G_BITREVERSE: |
1846 | case TargetOpcode::G_FSHL: |
1847 | case TargetOpcode::G_FSHR: |
1848 | case TargetOpcode::G_SMAX: |
1849 | case TargetOpcode::G_SMIN: |
1850 | case TargetOpcode::G_UMAX: |
1851 | case TargetOpcode::G_UMIN: |
1852 | case TargetOpcode::G_PTRMASK: |
1853 | case TargetOpcode::G_SADDO: |
1854 | case TargetOpcode::G_SSUBO: |
1855 | case TargetOpcode::G_UADDO: |
1856 | case TargetOpcode::G_USUBO: |
1857 | case TargetOpcode::G_SMULO: |
1858 | case TargetOpcode::G_UMULO: |
1859 | case TargetOpcode::G_SADDSAT: |
1860 | case TargetOpcode::G_UADDSAT: |
1861 | case TargetOpcode::G_SSUBSAT: |
1862 | case TargetOpcode::G_USUBSAT: |
1863 | return false; |
1864 | case TargetOpcode::G_SSHLSAT: |
1865 | case TargetOpcode::G_USHLSAT: |
1866 | return includesPoison(Kind) && |
1867 | !shiftAmountKnownInRange(ShiftAmount: RegDef->getOperand(i: 2).getReg(), MRI); |
1868 | case TargetOpcode::G_INSERT_VECTOR_ELT: { |
1869 | GInsertVectorElement *Insert = cast<GInsertVectorElement>(Val: RegDef); |
1870 | if (includesPoison(Kind)) { |
1871 | std::optional<ValueAndVReg> Index = |
1872 | getIConstantVRegValWithLookThrough(VReg: Insert->getIndexReg(), MRI); |
1873 | if (!Index) |
1874 | return true; |
1875 | LLT VecTy = MRI.getType(Reg: Insert->getVectorReg()); |
1876 | return Index->Value.uge(RHS: VecTy.getElementCount().getKnownMinValue()); |
1877 | } |
1878 | return false; |
1879 | } |
1880 | case TargetOpcode::G_EXTRACT_VECTOR_ELT: { |
1881 | GExtractVectorElement * = cast<GExtractVectorElement>(Val: RegDef); |
1882 | if (includesPoison(Kind)) { |
1883 | std::optional<ValueAndVReg> Index = |
1884 | getIConstantVRegValWithLookThrough(VReg: Extract->getIndexReg(), MRI); |
1885 | if (!Index) |
1886 | return true; |
1887 | LLT VecTy = MRI.getType(Reg: Extract->getVectorReg()); |
1888 | return Index->Value.uge(RHS: VecTy.getElementCount().getKnownMinValue()); |
1889 | } |
1890 | return false; |
1891 | } |
1892 | case TargetOpcode::G_SHUFFLE_VECTOR: { |
1893 | GShuffleVector *Shuffle = cast<GShuffleVector>(Val: RegDef); |
1894 | ArrayRef<int> Mask = Shuffle->getMask(); |
1895 | return includesPoison(Kind) && is_contained(Range&: Mask, Element: -1); |
1896 | } |
1897 | case TargetOpcode::G_FNEG: |
1898 | case TargetOpcode::G_PHI: |
1899 | case TargetOpcode::G_SELECT: |
1900 | case TargetOpcode::G_UREM: |
1901 | case TargetOpcode::G_SREM: |
1902 | case TargetOpcode::G_FREEZE: |
1903 | case TargetOpcode::G_ICMP: |
1904 | case TargetOpcode::G_FCMP: |
1905 | case TargetOpcode::G_FADD: |
1906 | case TargetOpcode::G_FSUB: |
1907 | case TargetOpcode::G_FMUL: |
1908 | case TargetOpcode::G_FDIV: |
1909 | case TargetOpcode::G_FREM: |
1910 | case TargetOpcode::G_PTR_ADD: |
1911 | return false; |
1912 | default: |
1913 | return !isa<GCastOp>(Val: RegDef) && !isa<GBinOp>(Val: RegDef); |
1914 | } |
1915 | } |
1916 | |
1917 | static bool isGuaranteedNotToBeUndefOrPoison(Register Reg, |
1918 | const MachineRegisterInfo &MRI, |
1919 | unsigned Depth, |
1920 | UndefPoisonKind Kind) { |
1921 | if (Depth >= MaxAnalysisRecursionDepth) |
1922 | return false; |
1923 | |
1924 | MachineInstr *RegDef = MRI.getVRegDef(Reg); |
1925 | |
1926 | switch (RegDef->getOpcode()) { |
1927 | case TargetOpcode::G_FREEZE: |
1928 | return true; |
1929 | case TargetOpcode::G_IMPLICIT_DEF: |
1930 | return !includesUndef(Kind); |
1931 | case TargetOpcode::G_CONSTANT: |
1932 | case TargetOpcode::G_FCONSTANT: |
1933 | return true; |
1934 | case TargetOpcode::G_BUILD_VECTOR: { |
1935 | GBuildVector *BV = cast<GBuildVector>(Val: RegDef); |
1936 | unsigned NumSources = BV->getNumSources(); |
1937 | for (unsigned I = 0; I < NumSources; ++I) |
1938 | if (!::isGuaranteedNotToBeUndefOrPoison(Reg: BV->getSourceReg(I), MRI, |
1939 | Depth: Depth + 1, Kind)) |
1940 | return false; |
1941 | return true; |
1942 | } |
1943 | case TargetOpcode::G_PHI: { |
1944 | GPhi *Phi = cast<GPhi>(Val: RegDef); |
1945 | unsigned NumIncoming = Phi->getNumIncomingValues(); |
1946 | for (unsigned I = 0; I < NumIncoming; ++I) |
1947 | if (!::isGuaranteedNotToBeUndefOrPoison(Reg: Phi->getIncomingValue(I), MRI, |
1948 | Depth: Depth + 1, Kind)) |
1949 | return false; |
1950 | return true; |
1951 | } |
1952 | default: { |
1953 | auto MOCheck = [&](const MachineOperand &MO) { |
1954 | if (!MO.isReg()) |
1955 | return true; |
1956 | return ::isGuaranteedNotToBeUndefOrPoison(Reg: MO.getReg(), MRI, Depth: Depth + 1, |
1957 | Kind); |
1958 | }; |
1959 | return !::canCreateUndefOrPoison(Reg, MRI, |
1960 | /*ConsiderFlagsAndMetadata=*/true, Kind) && |
1961 | all_of(Range: RegDef->uses(), P: MOCheck); |
1962 | } |
1963 | } |
1964 | } |
1965 | |
1966 | bool llvm::canCreateUndefOrPoison(Register Reg, const MachineRegisterInfo &MRI, |
1967 | bool ConsiderFlagsAndMetadata) { |
1968 | return ::canCreateUndefOrPoison(Reg, MRI, ConsiderFlagsAndMetadata, |
1969 | Kind: UndefPoisonKind::UndefOrPoison); |
1970 | } |
1971 | |
1972 | bool canCreatePoison(Register Reg, const MachineRegisterInfo &MRI, |
1973 | bool ConsiderFlagsAndMetadata = true) { |
1974 | return ::canCreateUndefOrPoison(Reg, MRI, ConsiderFlagsAndMetadata, |
1975 | Kind: UndefPoisonKind::PoisonOnly); |
1976 | } |
1977 | |
1978 | bool llvm::isGuaranteedNotToBeUndefOrPoison(Register Reg, |
1979 | const MachineRegisterInfo &MRI, |
1980 | unsigned Depth) { |
1981 | return ::isGuaranteedNotToBeUndefOrPoison(Reg, MRI, Depth, |
1982 | Kind: UndefPoisonKind::UndefOrPoison); |
1983 | } |
1984 | |
1985 | bool llvm::isGuaranteedNotToBePoison(Register Reg, |
1986 | const MachineRegisterInfo &MRI, |
1987 | unsigned Depth) { |
1988 | return ::isGuaranteedNotToBeUndefOrPoison(Reg, MRI, Depth, |
1989 | Kind: UndefPoisonKind::PoisonOnly); |
1990 | } |
1991 | |
1992 | bool llvm::isGuaranteedNotToBeUndef(Register Reg, |
1993 | const MachineRegisterInfo &MRI, |
1994 | unsigned Depth) { |
1995 | return ::isGuaranteedNotToBeUndefOrPoison(Reg, MRI, Depth, |
1996 | Kind: UndefPoisonKind::UndefOnly); |
1997 | } |
1998 | |
1999 | Type *llvm::getTypeForLLT(LLT Ty, LLVMContext &C) { |
2000 | if (Ty.isVector()) |
2001 | return VectorType::get(ElementType: IntegerType::get(C, NumBits: Ty.getScalarSizeInBits()), |
2002 | EC: Ty.getElementCount()); |
2003 | return IntegerType::get(C, NumBits: Ty.getSizeInBits()); |
2004 | } |
2005 | |
2006 | bool llvm::isAssertMI(const MachineInstr &MI) { |
2007 | switch (MI.getOpcode()) { |
2008 | default: |
2009 | return false; |
2010 | case TargetOpcode::G_ASSERT_ALIGN: |
2011 | case TargetOpcode::G_ASSERT_SEXT: |
2012 | case TargetOpcode::G_ASSERT_ZEXT: |
2013 | return true; |
2014 | } |
2015 | } |
2016 | |
2017 | APInt llvm::GIConstant::getScalarValue() const { |
2018 | assert(Kind == GIConstantKind::Scalar && "Expected scalar constant" ); |
2019 | |
2020 | return Value; |
2021 | } |
2022 | |
2023 | std::optional<GIConstant> |
2024 | llvm::GIConstant::getConstant(Register Const, const MachineRegisterInfo &MRI) { |
2025 | MachineInstr *Constant = getDefIgnoringCopies(Reg: Const, MRI); |
2026 | |
2027 | if (GSplatVector *Splat = dyn_cast<GSplatVector>(Val: Constant)) { |
2028 | std::optional<ValueAndVReg> MayBeConstant = |
2029 | getIConstantVRegValWithLookThrough(VReg: Splat->getScalarReg(), MRI); |
2030 | if (!MayBeConstant) |
2031 | return std::nullopt; |
2032 | return GIConstant(MayBeConstant->Value, GIConstantKind::ScalableVector); |
2033 | } |
2034 | |
2035 | if (GBuildVector *Build = dyn_cast<GBuildVector>(Val: Constant)) { |
2036 | SmallVector<APInt> Values; |
2037 | unsigned NumSources = Build->getNumSources(); |
2038 | for (unsigned I = 0; I < NumSources; ++I) { |
2039 | Register SrcReg = Build->getSourceReg(I); |
2040 | std::optional<ValueAndVReg> MayBeConstant = |
2041 | getIConstantVRegValWithLookThrough(VReg: SrcReg, MRI); |
2042 | if (!MayBeConstant) |
2043 | return std::nullopt; |
2044 | Values.push_back(Elt: MayBeConstant->Value); |
2045 | } |
2046 | return GIConstant(Values); |
2047 | } |
2048 | |
2049 | std::optional<ValueAndVReg> MayBeConstant = |
2050 | getIConstantVRegValWithLookThrough(VReg: Const, MRI); |
2051 | if (!MayBeConstant) |
2052 | return std::nullopt; |
2053 | |
2054 | return GIConstant(MayBeConstant->Value, GIConstantKind::Scalar); |
2055 | } |
2056 | |
2057 | APFloat llvm::GFConstant::getScalarValue() const { |
2058 | assert(Kind == GFConstantKind::Scalar && "Expected scalar constant" ); |
2059 | |
2060 | return Values[0]; |
2061 | } |
2062 | |
2063 | std::optional<GFConstant> |
2064 | llvm::GFConstant::getConstant(Register Const, const MachineRegisterInfo &MRI) { |
2065 | MachineInstr *Constant = getDefIgnoringCopies(Reg: Const, MRI); |
2066 | |
2067 | if (GSplatVector *Splat = dyn_cast<GSplatVector>(Val: Constant)) { |
2068 | std::optional<FPValueAndVReg> MayBeConstant = |
2069 | getFConstantVRegValWithLookThrough(VReg: Splat->getScalarReg(), MRI); |
2070 | if (!MayBeConstant) |
2071 | return std::nullopt; |
2072 | return GFConstant(MayBeConstant->Value, GFConstantKind::ScalableVector); |
2073 | } |
2074 | |
2075 | if (GBuildVector *Build = dyn_cast<GBuildVector>(Val: Constant)) { |
2076 | SmallVector<APFloat> Values; |
2077 | unsigned NumSources = Build->getNumSources(); |
2078 | for (unsigned I = 0; I < NumSources; ++I) { |
2079 | Register SrcReg = Build->getSourceReg(I); |
2080 | std::optional<FPValueAndVReg> MayBeConstant = |
2081 | getFConstantVRegValWithLookThrough(VReg: SrcReg, MRI); |
2082 | if (!MayBeConstant) |
2083 | return std::nullopt; |
2084 | Values.push_back(Elt: MayBeConstant->Value); |
2085 | } |
2086 | return GFConstant(Values); |
2087 | } |
2088 | |
2089 | std::optional<FPValueAndVReg> MayBeConstant = |
2090 | getFConstantVRegValWithLookThrough(VReg: Const, MRI); |
2091 | if (!MayBeConstant) |
2092 | return std::nullopt; |
2093 | |
2094 | return GFConstant(MayBeConstant->Value, GFConstantKind::Scalar); |
2095 | } |
2096 | |