LLVM 22.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"
18#include "llvm/IR/Constants.h"
19#include "llvm/IR/IntrinsicsAMDGPU.h"
20
21using namespace llvm;
22using namespace AMDGPU;
23using namespace MIPatternMatch;
24
25std::pair<Register, unsigned>
27 GISelValueTracking *ValueTracking,
28 bool CheckNUW) {
30 if (Def->getOpcode() == TargetOpcode::G_CONSTANT) {
31 unsigned Offset;
32 const MachineOperand &Op = Def->getOperand(1);
33 if (Op.isImm())
34 Offset = Op.getImm();
35 else
36 Offset = Op.getCImm()->getZExtValue();
37
38 return std::pair(Register(), Offset);
39 }
40
41 int64_t Offset;
42 if (Def->getOpcode() == TargetOpcode::G_ADD) {
43 // A 32-bit (address + offset) should not cause unsigned 32-bit integer
44 // wraparound, because s_load instructions perform the addition in 64 bits.
45 if (CheckNUW && !Def->getFlag(MachineInstr::NoUWrap)) {
46 assert(MRI.getType(Reg).getScalarSizeInBits() == 32);
47 return std::pair(Reg, 0);
48 }
49 // TODO: Handle G_OR used for add case
50 if (mi_match(Def->getOperand(2).getReg(), MRI, m_ICst(Offset)))
51 return std::pair(Def->getOperand(1).getReg(), Offset);
52
53 // FIXME: matcher should ignore copies
54 if (mi_match(Def->getOperand(2).getReg(), MRI, m_Copy(m_ICst(Offset))))
55 return std::pair(Def->getOperand(1).getReg(), Offset);
56 }
57
59 if (ValueTracking && mi_match(Reg, MRI, m_GOr(m_Reg(Base), m_ICst(Offset))) &&
60 ValueTracking->maskedValueIsZero(Base,
61 APInt(32, Offset, /*isSigned=*/true)))
62 return std::pair(Base, Offset);
63
64 // Handle G_PTRTOINT (G_PTR_ADD base, const) case
65 if (Def->getOpcode() == TargetOpcode::G_PTRTOINT) {
67 if (mi_match(Def->getOperand(1).getReg(), MRI,
69 // If Base was int converted to pointer, simply return int and offset.
70 if (Base->getOpcode() == TargetOpcode::G_INTTOPTR)
71 return std::pair(Base->getOperand(1).getReg(), Offset);
72
73 // Register returned here will be of pointer type.
74 return std::pair(Base->getOperand(0).getReg(), Offset);
75 }
76 }
77
78 return std::pair(Reg, 0);
79}
80
82 : MRI(MF.getRegInfo()) {
83 initLaneMaskIntrinsics(MF);
84}
85
87 return S32S64LaneMask.contains(Reg);
88}
89
90void IntrinsicLaneMaskAnalyzer::initLaneMaskIntrinsics(MachineFunction &MF) {
91 for (auto &MBB : MF) {
92 for (auto &MI : MBB) {
93 GIntrinsic *GI = dyn_cast<GIntrinsic>(&MI);
94 if (GI && GI->is(Intrinsic::amdgcn_if_break)) {
95 S32S64LaneMask.insert(MI.getOperand(3).getReg());
96 S32S64LaneMask.insert(MI.getOperand(0).getReg());
97 }
98
99 if (MI.getOpcode() == AMDGPU::SI_IF ||
100 MI.getOpcode() == AMDGPU::SI_ELSE) {
101 S32S64LaneMask.insert(MI.getOperand(0).getReg());
102 }
103 }
104 }
105}
106
108 if (Ty.isVector()) {
109 LLT ElTy = Ty.getElementType();
110 if (ElTy.getSizeInBits() == 16)
111 return LLT::fixed_vector(2, ElTy);
112 // S32, S64 or pointer
113 return ElTy;
114 }
115
116 // Large scalars and 64-bit pointers
117 return LLT::scalar(32);
118}
119
120template <typename ReadLaneFnTy>
122 const RegisterBankInfo &, ReadLaneFnTy);
123
124template <typename ReadLaneFnTy>
125static void
127 LLT UnmergeTy, Register VgprSrc, const RegisterBankInfo &RBI,
128 ReadLaneFnTy BuildRL) {
129 const RegisterBank *VgprRB = &RBI.getRegBank(AMDGPU::VGPRRegBankID);
130 auto Unmerge = B.buildUnmerge({VgprRB, UnmergeTy}, VgprSrc);
131 for (unsigned i = 0; i < Unmerge->getNumOperands() - 1; ++i) {
132 SgprDstParts.push_back(buildReadLane(B, Unmerge.getReg(i), RBI, BuildRL));
133 }
134}
135
136template <typename ReadLaneFnTy>
138 const RegisterBankInfo &RBI,
139 ReadLaneFnTy BuildRL) {
140 LLT Ty = B.getMRI()->getType(VgprSrc);
141 const RegisterBank *SgprRB = &RBI.getRegBank(AMDGPU::SGPRRegBankID);
142 if (Ty.getSizeInBits() == 32) {
143 Register SgprDst = B.getMRI()->createVirtualRegister({SgprRB, Ty});
144 return BuildRL(B, SgprDst, VgprSrc).getReg(0);
145 }
146
147 SmallVector<Register, 8> SgprDstParts;
148 unmergeReadAnyLane(B, SgprDstParts, getReadAnyLaneSplitTy(Ty), VgprSrc, RBI,
149 BuildRL);
150
151 return B.buildMergeLikeInstr({SgprRB, Ty}, SgprDstParts).getReg(0);
152}
153
154template <typename ReadLaneFnTy>
156 Register VgprSrc, const RegisterBankInfo &RBI,
157 ReadLaneFnTy BuildReadLane) {
158 LLT Ty = B.getMRI()->getType(VgprSrc);
159 if (Ty.getSizeInBits() == 32) {
160 BuildReadLane(B, SgprDst, VgprSrc);
161 return;
162 }
163
164 SmallVector<Register, 8> SgprDstParts;
165 unmergeReadAnyLane(B, SgprDstParts, getReadAnyLaneSplitTy(Ty), VgprSrc, RBI,
166 BuildReadLane);
167
168 B.buildMergeLikeInstr(SgprDst, SgprDstParts).getReg(0);
169}
170
172 Register VgprSrc, const RegisterBankInfo &RBI) {
173 return buildReadLane(
174 B, SgprDst, VgprSrc, RBI,
175 [](MachineIRBuilder &B, Register SgprDst, Register VgprSrc) {
176 return B.buildInstr(AMDGPU::G_AMDGPU_READANYLANE, {SgprDst}, {VgprSrc});
177 });
178}
179
181 Register VgprSrc, const RegisterBankInfo &RBI) {
182 return buildReadLane(
183 B, SgprDst, VgprSrc, RBI,
184 [](MachineIRBuilder &B, Register SgprDst, Register VgprSrc) {
185 return B.buildIntrinsic(Intrinsic::amdgcn_readfirstlane, SgprDst)
186 .addReg(VgprSrc);
187 });
188}
unsigned const MachineRegisterInfo * MRI
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.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
Implement a low-level type suitable for MachineInstr level instruction selection.
Contains matchers for matching SSA Machine Instructions.
This file declares the MachineIRBuilder class.
static unsigned getReg(const MCDisassembler *D, unsigned RC, unsigned RegNo)
Class for arbitrary precision integers.
Definition: APInt.h:78
This class represents an Operation in the Expression.
bool maskedValueIsZero(Register Val, const APInt &Mask)
Represents a call to an intrinsic.
bool is(Intrinsic::ID ID) const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelType.h:43
constexpr bool isVector() const
Definition: LowLevelType.h:149
constexpr TypeSize getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
Definition: LowLevelType.h:191
constexpr LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
Definition: LowLevelType.h:278
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
Definition: LowLevelType.h:101
Helper class to build MachineInstr.
Representation of each machine instruction.
Definition: MachineInstr.h:72
MachineOperand class - Representation of each machine instruction operand.
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.
Definition: RegisterBank.h:29
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
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)
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.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
LLVM_ABI MachineInstr * getDefIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI)
Find the def instruction for Reg, folding away any trivial copies.
Definition: Utils.cpp:492