LLVM 24.0.0git
AMDGPUGlobalISelUtils.cpp
Go to the documentation of this file.
1//===- AMDGPUGlobalISelUtils.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
12#include "llvm/ADT/DenseSet.h"
19#include "llvm/IR/Constants.h"
20#include "llvm/IR/IntrinsicsAMDGPU.h"
21
22using namespace llvm;
23using namespace AMDGPU;
24using namespace MIPatternMatch;
25
27 const MachineRegisterInfo &MRI) {
28 Register ScaleReg = MI.getOperand(5).getReg();
29 MachineInstr *ScaleDef = getDefIgnoringCopies(ScaleReg, MRI);
30 if (ScaleDef && ScaleDef->getOpcode() == AMDGPU::G_AMDGPU_COPY_VCC_SCC)
31 ScaleReg = ScaleDef->getOperand(1).getReg();
32 auto Scale = getIConstantVRegValWithLookThrough(ScaleReg, MRI);
33 if (!Scale || !Scale->Value.isZero())
34 return false;
35
36 const fltSemantics &Semantics =
37 getFltSemanticForLLT(MRI.getType(MI.getOperand(0).getReg()));
38 return MI.getMF()->getDenormalMode(Semantics).Input == DenormalMode::IEEE;
39}
40
41std::pair<Register, unsigned>
43 GISelValueTracking *ValueTracking,
44 bool CheckNUW) {
46 if (Def->getOpcode() == TargetOpcode::G_CONSTANT) {
47 unsigned Offset;
48 const MachineOperand &Op = Def->getOperand(1);
49 if (Op.isImm())
50 Offset = Op.getImm();
51 else
52 Offset = Op.getCImm()->getZExtValue();
53
54 return std::pair(Register(), Offset);
55 }
56
57 int64_t Offset;
58 if (Def->getOpcode() == TargetOpcode::G_ADD) {
59 // A 32-bit (address + offset) should not cause unsigned 32-bit integer
60 // wraparound, because s_load instructions perform the addition in 64 bits.
61 if (CheckNUW && !Def->getFlag(MachineInstr::NoUWrap)) {
62 assert(MRI.getType(Reg).getScalarSizeInBits() == 32);
63 return std::pair(Reg, 0);
64 }
65 // TODO: Handle G_OR used for add case
66 if (mi_match(Def->getOperand(2).getReg(), MRI, m_ICst(Offset)))
67 return std::pair(Def->getOperand(1).getReg(), Offset);
68
69 // FIXME: matcher should ignore copies
70 if (mi_match(Def->getOperand(2).getReg(), MRI, m_Copy(m_ICst(Offset))))
71 return std::pair(Def->getOperand(1).getReg(), Offset);
72 }
73
75 if (mi_match(Reg, MRI, m_GOr(m_Reg(Base), m_ICst(Offset))) &&
76 (Def->getFlag(MachineInstr::Disjoint) ||
77 (ValueTracking && ValueTracking->maskedValueIsZero(
78 Base, APInt(32, Offset, /*isSigned=*/true)))))
79 return std::pair(Base, Offset);
80
81 // Handle G_PTRTOINT (G_PTR_ADD base, const) case
82 if (Def->getOpcode() == TargetOpcode::G_PTRTOINT) {
84 Register PtrAdd = Def->getOperand(1).getReg();
85 uint32_t Flags;
86 if (mi_match(PtrAdd, MRI,
88 // Same check as for G_ADD; nuw comes from getelementptr inbounds.
89 if (CheckNUW && !(Flags & MachineInstr::NoUWrap)) {
90 assert(MRI.getType(Reg).getScalarSizeInBits() == 32);
91 return std::pair(Reg, 0);
92 }
93 // If Base was int converted to pointer, simply return int and offset.
94 if (Base->getOpcode() == TargetOpcode::G_INTTOPTR)
95 return std::pair(Base->getOperand(1).getReg(), Offset);
96
97 // Register returned here will be of pointer type.
98 return std::pair(Base->getOperand(0).getReg(), Offset);
99 }
100 }
101
102 return std::pair(Reg, 0);
103}
104
106 : MRI(MF.getRegInfo()) {
107 initLaneMaskIntrinsics(MF);
108}
109
111 return S32S64LaneMask.contains(Reg);
112}
113
114void IntrinsicLaneMaskAnalyzer::initLaneMaskIntrinsics(MachineFunction &MF) {
115 for (auto &MBB : MF) {
116 for (auto &MI : MBB) {
118 if (GI && GI->is(Intrinsic::amdgcn_if_break)) {
119 S32S64LaneMask.insert(MI.getOperand(3).getReg());
120 S32S64LaneMask.insert(MI.getOperand(0).getReg());
121 }
122
123 if (MI.getOpcode() == AMDGPU::SI_IF ||
124 MI.getOpcode() == AMDGPU::SI_ELSE) {
125 S32S64LaneMask.insert(MI.getOperand(0).getReg());
126 }
127 }
128 }
129}
130
132 if (Ty.isVector()) {
133 LLT ElTy = Ty.getElementType();
134 if (ElTy.getSizeInBits() == 16)
135 return LLT::fixed_vector(2, ElTy);
136 // S32, S64 or pointer
137 return ElTy;
138 }
139
140 // Large scalars and 64-bit pointers
141 return LLT::integer(32);
142}
143
144template <typename ReadLaneFnTy>
145static Register buildReadLane(MachineIRBuilder &, Register,
146 const RegisterBankInfo &, ReadLaneFnTy);
147
148template <typename ReadLaneFnTy>
149static void
151 LLT UnmergeTy, Register VgprSrc, const RegisterBankInfo &RBI,
152 ReadLaneFnTy BuildRL) {
153 const RegisterBank *VgprRB = &RBI.getRegBank(AMDGPU::VGPRRegBankID);
154 auto Unmerge = B.buildUnmerge({VgprRB, UnmergeTy}, VgprSrc);
155 for (unsigned i = 0; i < Unmerge->getNumOperands() - 1; ++i) {
156 SgprDstParts.push_back(buildReadLane(B, Unmerge.getReg(i), RBI, BuildRL));
157 }
158}
159
160template <typename ReadLaneFnTy>
162 const RegisterBankInfo &RBI,
163 ReadLaneFnTy BuildRL) {
164 LLT Ty = B.getMRI()->getType(VgprSrc);
165 const RegisterBank *SgprRB = &RBI.getRegBank(AMDGPU::SGPRRegBankID);
166 if (Ty.getSizeInBits() == 32) {
167 Register SgprDst = B.getMRI()->createVirtualRegister({SgprRB, Ty});
168 return BuildRL(B, SgprDst, VgprSrc).getReg(0);
169 }
170
171 SmallVector<Register, 8> SgprDstParts;
172 unmergeReadAnyLane(B, SgprDstParts, getReadAnyLaneSplitTy(Ty), VgprSrc, RBI,
173 BuildRL);
174
175 return B.buildMergeLikeInstr({SgprRB, Ty}, SgprDstParts).getReg(0);
176}
177
178template <typename ReadLaneFnTy>
180 Register VgprSrc, const RegisterBankInfo &RBI,
181 ReadLaneFnTy BuildReadLane) {
182 LLT Ty = B.getMRI()->getType(VgprSrc);
183 if (Ty.getSizeInBits() == 32) {
184 BuildReadLane(B, SgprDst, VgprSrc);
185 return;
186 }
187
188 SmallVector<Register, 8> SgprDstParts;
189 unmergeReadAnyLane(B, SgprDstParts, getReadAnyLaneSplitTy(Ty), VgprSrc, RBI,
190 BuildReadLane);
191
192 B.buildMergeLikeInstr(SgprDst, SgprDstParts).getReg(0);
193}
194
196 Register VgprSrc, const RegisterBankInfo &RBI) {
197 return buildReadLane(
198 B, SgprDst, VgprSrc, RBI,
199 [](MachineIRBuilder &B, Register SgprDst, Register VgprSrc) {
200 return B.buildInstr(AMDGPU::G_AMDGPU_READANYLANE, {SgprDst}, {VgprSrc});
201 });
202}
203
205 Register VgprSrc, const RegisterBankInfo &RBI) {
206 return buildReadLane(
207 B, SgprDst, VgprSrc, RBI,
208 [](MachineIRBuilder &B, Register SgprDst, Register VgprSrc) {
209 return B.buildIntrinsic(Intrinsic::amdgcn_readfirstlane, SgprDst)
210 .addReg(VgprSrc);
211 });
212}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static LLT getReadAnyLaneSplitTy(LLT Ty)
static Register buildReadLane(MachineIRBuilder &, Register, const RegisterBankInfo &, ReadLaneFnTy)
static void unmergeReadAnyLane(MachineIRBuilder &B, SmallVectorImpl< Register > &SgprDstParts, LLT UnmergeTy, Register VgprSrc, const RegisterBankInfo &RBI, ReadLaneFnTy BuildRL)
Provides AMDGPU specific target descriptions.
This file declares the targeting of the RegisterBankInfo class for AMDGPU.
MachineBasicBlock & MBB
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
This file defines the DenseSet and SmallDenseSet classes.
Provides analysis for querying information about KnownBits during GISel passes.
IRTranslator LLVM IR MI
Implement a low-level type suitable for MachineInstr level instruction selection.
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
Promote Memory to Register
Definition Mem2Reg.cpp:110
static MCRegister getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
MachineRegisterInfo & MRI
Class for arbitrary precision integers.
Definition APInt.h:78
bool maskedValueIsZero(Register Val, const APInt &Mask)
Represents a call to an intrinsic.
bool is(Intrinsic::ID ID) const
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
static LLT integer(unsigned SizeInBits)
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Helper class to build MachineInstr.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Holds all the information related to register banks.
const RegisterBank & getRegBank(unsigned ID)
Get the register bank identified by ID.
This class implements the register bank concept.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
bool isUnscaledIEEEDivFmas(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Return whether div.fmas can use ordinary FMA without changing denormals.
std::pair< Register, unsigned > getBaseWithConstantOffset(MachineRegisterInfo &MRI, Register Reg, GISelValueTracking *ValueTracking=nullptr, bool CheckNUW=false)
Returns base register and constant offset.
void buildReadAnyLane(MachineIRBuilder &B, Register SgprDst, Register VgprSrc, const RegisterBankInfo &RBI)
void buildReadFirstLane(MachineIRBuilder &B, Register SgprDst, Register VgprSrc, const RegisterBankInfo &RBI)
operand_type_match m_Reg()
UnaryOp_match< SrcTy, TargetOpcode::COPY > m_Copy(SrcTy &&Src)
MIFlagsRef m_MIFlags(uint32_t &Flags)
ConstantMatch< APInt > m_ICst(APInt &Cst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition Utils.cpp:520
DWARFExpression::Operation Op
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:440
@ IEEE
IEEE-754 denormal numbers preserved.