Skip to content

Commit 805dfb1

Browse files
YuriPlyakhinigcbot
authored andcommitted
Add Abstract Load/Store instruction classes
Add ALoadInst and AStoreInst to abstract away the differences between Load and PredicatedLoad and between Store and PredicatedStore. Update PredicatedLoadIntrinsic and PredicatedStoreIntrinsic to be more aligned with LoadInst and StoreInst interfaces
1 parent 48e187d commit 805dfb1

File tree

5 files changed

+497
-8
lines changed

5 files changed

+497
-8
lines changed

IGC/Compiler/CISACodeGen/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ set(IGC_BUILD__SRC__CISACodeGen_Common
6060
"${CMAKE_CURRENT_SOURCE_DIR}/MatchCommonKernelPatterns.cpp"
6161
"${CMAKE_CURRENT_SOURCE_DIR}/MemOpt.cpp"
6262
"${CMAKE_CURRENT_SOURCE_DIR}/MemOpt2.cpp"
63+
"${CMAKE_CURRENT_SOURCE_DIR}/MemOptUtils.cpp"
6364
"${CMAKE_CURRENT_SOURCE_DIR}/MergeUniformStores.cpp"
6465
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLOptions.cpp"
6566
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLKernelCodeGen.cpp"
@@ -169,6 +170,7 @@ set(IGC_BUILD__HDR__CISACodeGen_Common
169170
"${CMAKE_CURRENT_SOURCE_DIR}/MatchCommonKernelPatterns.hpp"
170171
"${CMAKE_CURRENT_SOURCE_DIR}/MemOpt.h"
171172
"${CMAKE_CURRENT_SOURCE_DIR}/MemOpt2.h"
173+
"${CMAKE_CURRENT_SOURCE_DIR}/MemOptUtils.h"
172174
"${CMAKE_CURRENT_SOURCE_DIR}/MergeUniformStores.hpp"
173175
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLOptions.hpp"
174176
"${CMAKE_CURRENT_SOURCE_DIR}/OpenCLKernelCodeGen.hpp"
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
/*========================== begin_copyright_notice ============================
2+
3+
Copyright (C) 2025 Intel Corporation
4+
5+
SPDX-License-Identifier: MIT
6+
7+
============================= end_copyright_notice ===========================*/
8+
9+
#include "common/LLVMWarningsPush.hpp"
10+
#include <llvm/IR/NoFolder.h>
11+
#include "llvm/IR/Type.h"
12+
#include <llvmWrapper/IR/DerivedTypes.h>
13+
#include "common/LLVMWarningsPop.hpp"
14+
15+
#include "MemOptUtils.h"
16+
17+
using namespace llvm;
18+
19+
namespace IGC {
20+
std::optional<ALoadInst> ALoadInst::get(Value *value)
21+
{
22+
if (isa<LoadInst>(value) || isa<PredicatedLoadIntrinsic>(value))
23+
return ALoadInst{cast<Instruction>(value)};
24+
return std::nullopt;
25+
}
26+
27+
Type *ALoadInst::getType() const
28+
{
29+
if (isa<LoadInst>(m_inst))
30+
return cast<LoadInst>(m_inst)->getType();
31+
32+
if (isa<PredicatedLoadIntrinsic>(m_inst))
33+
return cast<PredicatedLoadIntrinsic>(m_inst)->getType();
34+
35+
llvm_unreachable("Unknown load instruction");
36+
}
37+
Value *ALoadInst::getPointerOperand() const
38+
{
39+
if (isa<LoadInst>(m_inst))
40+
return cast<LoadInst>(m_inst)->getPointerOperand();
41+
42+
if (isa<PredicatedLoadIntrinsic>(m_inst))
43+
return cast<PredicatedLoadIntrinsic>(m_inst)->getPointerOperand();
44+
45+
llvm_unreachable("Unknown load instruction");
46+
}
47+
Type *ALoadInst::getPointerOperandType() const
48+
{
49+
if (isa<LoadInst>(m_inst))
50+
return cast<LoadInst>(m_inst)->getPointerOperandType();
51+
52+
if (isa<PredicatedLoadIntrinsic>(m_inst))
53+
return cast<PredicatedLoadIntrinsic>(m_inst)->getPointerOperandType();
54+
55+
llvm_unreachable("Unknown load instruction");
56+
}
57+
unsigned ALoadInst::getPointerAddressSpace() const
58+
{
59+
if (isa<LoadInst>(m_inst))
60+
return cast<LoadInst>(m_inst)->getPointerAddressSpace();
61+
62+
if (isa<PredicatedLoadIntrinsic>(m_inst))
63+
return cast<PredicatedLoadIntrinsic>(m_inst)->getPointerAddressSpace();
64+
65+
llvm_unreachable("Unknown load instruction");
66+
}
67+
bool ALoadInst::isVolatile() const
68+
{
69+
if (isa<LoadInst>(m_inst))
70+
return cast<LoadInst>(m_inst)->isVolatile();
71+
72+
if (isa<PredicatedLoadIntrinsic>(m_inst))
73+
return cast<PredicatedLoadIntrinsic>(m_inst)->isVolatile();
74+
75+
llvm_unreachable("Unknown load instruction");
76+
}
77+
void ALoadInst::setVolatile(bool isVolatile)
78+
{
79+
if (isa<LoadInst>(m_inst))
80+
cast<LoadInst>(m_inst)->setVolatile(isVolatile);
81+
82+
if (isa<PredicatedLoadIntrinsic>(m_inst))
83+
cast<PredicatedLoadIntrinsic>(m_inst)->setVolatile(isVolatile);
84+
85+
llvm_unreachable("Unknown load instruction");
86+
}
87+
bool ALoadInst::isSimple() const
88+
{
89+
if (isa<LoadInst>(m_inst))
90+
return cast<LoadInst>(m_inst)->isSimple();
91+
92+
if (isa<PredicatedLoadIntrinsic>(m_inst))
93+
return cast<PredicatedLoadIntrinsic>(m_inst)->isSimple();
94+
95+
llvm_unreachable("Unknown load instruction");
96+
}
97+
98+
alignment_t ALoadInst::getAlignmentValue() const
99+
{
100+
if (isa<LoadInst>(m_inst))
101+
return IGCLLVM::getAlignmentValue(cast<LoadInst>(m_inst));
102+
103+
if (isa<PredicatedLoadIntrinsic>(m_inst))
104+
return cast<PredicatedLoadIntrinsic>(m_inst)->getAlignment();
105+
106+
llvm_unreachable("Unknown load instruction");
107+
}
108+
109+
bool ALoadInst::isPredicated() const
110+
{
111+
return isa<PredicatedLoadIntrinsic>(m_inst);
112+
}
113+
114+
Value *ALoadInst::getPredicate() const
115+
{
116+
if (isa<PredicatedLoadIntrinsic>(m_inst))
117+
return cast<PredicatedLoadIntrinsic>(m_inst)->getPredicate();
118+
119+
return nullptr;
120+
}
121+
122+
PredicatedLoadIntrinsic *ALoadInst::getPredicatedLoadIntrinsic() const
123+
{
124+
if (isa<PredicatedLoadIntrinsic>(m_inst))
125+
return cast<PredicatedLoadIntrinsic>(m_inst);
126+
127+
return nullptr;
128+
}
129+
130+
template <typename T>
131+
Instruction *ALoadInst::CreateLoad(IGCIRBuilder<T> &IRB, Type *Ty, Value *Ptr, Value *MergeValue)
132+
{
133+
if (isa<LoadInst>(m_inst))
134+
return IRB.CreateLoad(Ty, Ptr);
135+
136+
if (isa<PredicatedLoadIntrinsic>(m_inst))
137+
{
138+
IGC_ASSERT(MergeValue);
139+
PredicatedLoadIntrinsic *PLI = cast<PredicatedLoadIntrinsic>(m_inst);
140+
Module *M = IRB.GetInsertBlock()->getParent()->getParent();
141+
auto *F = GenISAIntrinsic::getDeclaration(M,
142+
GenISAIntrinsic::GenISA_PredicatedLoad,
143+
{Ty, Ptr->getType(), Ty});
144+
const DataLayout &DL = M->getDataLayout();
145+
146+
Value *alignValue = ConstantInt::get(Type::getInt64Ty(IRB.getContext()),
147+
DL.getABITypeAlign(Ty).value());
148+
return IRB.CreateCall4(F, Ptr, alignValue, PLI->getPredicate(), MergeValue);
149+
}
150+
151+
llvm_unreachable("Unknown load instruction");
152+
}
153+
154+
template Instruction *ALoadInst::CreateLoad(IGCIRBuilder<> &IRB, Type *Ty, Value *Ptr, Value *MergeValue);
155+
template Instruction *ALoadInst::CreateLoad(IGCIRBuilder<NoFolder> &IRB, Type *Ty, Value *Ptr, Value *MergeValue);
156+
157+
template <typename T>
158+
Instruction *ALoadInst::CreateAlignedLoad(IGCIRBuilder<T> &IRB, Type *Ty, Value *Ptr, Value* MergeValue, bool isVolatile)
159+
{
160+
if (isa<LoadInst>(m_inst))
161+
{
162+
LoadInst *LI = cast<LoadInst>(m_inst);
163+
return IRB.CreateAlignedLoad(Ty, Ptr, IGCLLVM::getAlign(*LI), isVolatile);
164+
}
165+
166+
if (isa<PredicatedLoadIntrinsic>(m_inst))
167+
{
168+
IGC_ASSERT_MESSAGE(!isVolatile, "PredicatedLoadIntrinsic should not be volatile");
169+
IGC_ASSERT(MergeValue);
170+
PredicatedLoadIntrinsic *PLI = cast<PredicatedLoadIntrinsic>(m_inst);
171+
auto *F = GenISAIntrinsic::getDeclaration(IRB.GetInsertBlock()->getParent()->getParent(),
172+
GenISAIntrinsic::GenISA_PredicatedLoad,
173+
{Ty, Ptr->getType(), Ty});
174+
return IRB.CreateCall4(F, Ptr, PLI->getAlignmentValue(), PLI->getPredicate(), MergeValue);
175+
}
176+
177+
llvm_unreachable("Unknown load instruction");
178+
}
179+
180+
template Instruction *ALoadInst::CreateAlignedLoad(IGCIRBuilder<> &IRB, Type *Ty, Value *Ptr, Value *MergeValue, bool isVolatile);
181+
template Instruction *ALoadInst::CreateAlignedLoad(IGCIRBuilder<NoFolder> &IRB, Type *Ty, Value *Ptr, Value *MergeValue, bool isVolatile);
182+
183+
Value *AStoreInst::getPointerOperand() const
184+
{
185+
if (isa<StoreInst>(m_inst))
186+
return cast<StoreInst>(m_inst)->getPointerOperand();
187+
188+
if (isa<PredicatedStoreIntrinsic>(m_inst))
189+
return cast<PredicatedStoreIntrinsic>(m_inst)->getPointerOperand();
190+
191+
llvm_unreachable("Unknown store instruction");
192+
}
193+
Type *AStoreInst::getPointerOperandType() const
194+
{
195+
if (isa<StoreInst>(m_inst))
196+
return cast<StoreInst>(m_inst)->getPointerOperandType();
197+
198+
if (isa<PredicatedStoreIntrinsic>(m_inst))
199+
return cast<PredicatedStoreIntrinsic>(m_inst)->getPointerOperandType();
200+
201+
llvm_unreachable("Unknown store instruction");
202+
}
203+
unsigned AStoreInst::getPointerAddressSpace() const
204+
{
205+
if (isa<StoreInst>(m_inst))
206+
return cast<StoreInst>(m_inst)->getPointerAddressSpace();
207+
208+
if (isa<PredicatedStoreIntrinsic>(m_inst))
209+
return cast<PredicatedStoreIntrinsic>(m_inst)->getPointerAddressSpace();
210+
211+
llvm_unreachable("Unknown store instruction");
212+
}
213+
Value *AStoreInst::getValueOperand() const
214+
{
215+
if (isa<StoreInst>(m_inst))
216+
return cast<StoreInst>(m_inst)->getValueOperand();
217+
218+
if (isa<PredicatedStoreIntrinsic>(m_inst))
219+
return cast<PredicatedStoreIntrinsic>(m_inst)->getValueOperand();
220+
221+
llvm_unreachable("Unknown store instruction");
222+
}
223+
bool AStoreInst::isVolatile() const
224+
{
225+
if (isa<StoreInst>(m_inst))
226+
return cast<StoreInst>(m_inst)->isVolatile();
227+
228+
if (isa<PredicatedStoreIntrinsic>(m_inst))
229+
return cast<PredicatedStoreIntrinsic>(m_inst)->isVolatile();
230+
231+
llvm_unreachable("Unknown store instruction");
232+
}
233+
void AStoreInst::setVolatile(bool isVolatile)
234+
{
235+
if (isa<StoreInst>(m_inst))
236+
cast<StoreInst>(m_inst)->setVolatile(isVolatile);
237+
238+
if (isa<PredicatedStoreIntrinsic>(m_inst))
239+
cast<PredicatedStoreIntrinsic>(m_inst)->setVolatile(isVolatile);
240+
241+
llvm_unreachable("Unknown store instruction");
242+
}
243+
bool AStoreInst::isSimple() const
244+
{
245+
if (isa<StoreInst>(m_inst))
246+
return cast<StoreInst>(m_inst)->isSimple();
247+
248+
if (isa<PredicatedStoreIntrinsic>(m_inst))
249+
return cast<PredicatedStoreIntrinsic>(m_inst)->isSimple();
250+
251+
llvm_unreachable("Unknown store instruction");
252+
}
253+
254+
alignment_t AStoreInst::getAlignmentValue() const
255+
{
256+
if (isa<StoreInst>(m_inst))
257+
return IGCLLVM::getAlignmentValue(cast<StoreInst>(m_inst));
258+
259+
if (isa<PredicatedStoreIntrinsic>(m_inst))
260+
return cast<PredicatedStoreIntrinsic>(m_inst)->getAlignment();
261+
262+
llvm_unreachable("Unknown store instruction");
263+
}
264+
265+
bool AStoreInst::isPredicated() const
266+
{
267+
return isa<PredicatedStoreIntrinsic>(m_inst);
268+
}
269+
270+
Value *AStoreInst::getPredicate() const
271+
{
272+
if (isa<PredicatedStoreIntrinsic>(m_inst))
273+
return cast<PredicatedStoreIntrinsic>(m_inst)->getPredicate();
274+
275+
return nullptr;
276+
}
277+
278+
std::optional<AStoreInst> AStoreInst::get(Value *value)
279+
{
280+
if (isa<StoreInst>(value) || isa<PredicatedStoreIntrinsic>(value))
281+
{
282+
return AStoreInst{cast<Instruction>(value)};
283+
}
284+
return std::nullopt;
285+
}
286+
template <typename T>
287+
Instruction *AStoreInst::CreateAlignedStore(IGCIRBuilder<T> &IRB, Value *Val, Value *Ptr, bool isVolatile)
288+
{
289+
if (isa<StoreInst>(m_inst))
290+
{
291+
StoreInst *SI = cast<StoreInst>(m_inst);
292+
return IRB.CreateAlignedStore(Val, Ptr, IGCLLVM::getAlign(*SI), isVolatile);
293+
}
294+
295+
if (isa<PredicatedStoreIntrinsic>(m_inst))
296+
{
297+
IGC_ASSERT_MESSAGE(!isVolatile, "PredicatedStoreIntrinsic should not be volatile");
298+
PredicatedStoreIntrinsic *PSI = cast<PredicatedStoreIntrinsic>(m_inst);
299+
auto *F = GenISAIntrinsic::getDeclaration(IRB.GetInsertBlock()->getParent()->getParent(),
300+
GenISAIntrinsic::GenISA_PredicatedStore,
301+
{Ptr->getType(), Val->getType()});
302+
return IRB.CreateCall4(F, Ptr, Val, PSI->getAlignmentValue(), PSI->getPredicate());
303+
}
304+
305+
llvm_unreachable("Unknown store instruction");
306+
}
307+
308+
template Instruction *AStoreInst::CreateAlignedStore(IGCIRBuilder<> &IRB, Value *Val, Value *Ptr, bool isVolatile);
309+
template Instruction *AStoreInst::CreateAlignedStore(IGCIRBuilder<NoFolder> &IRB, Value *Val, Value *Ptr, bool isVolatile);
310+
311+
// other utility functions, that should take into account abstract interface
312+
MemoryLocation getLocation(Instruction *I, TargetLibraryInfo *TLI)
313+
{
314+
if (LoadInst *LI = dyn_cast<LoadInst>(I))
315+
return MemoryLocation::get(LI);
316+
317+
if (StoreInst *SI = dyn_cast<StoreInst>(I))
318+
return MemoryLocation::get(SI);
319+
320+
if (isa<LdRawIntrinsic>(I) || isa<StoreRawIntrinsic>(I) ||
321+
isa<PredicatedLoadIntrinsic>(I) || isa<PredicatedStoreIntrinsic>(I))
322+
return MemoryLocation::getForArgument(cast<CallInst>(I), 0, TLI);
323+
324+
if (GenIntrinsicInst *GInst = dyn_cast<GenIntrinsicInst>(I))
325+
if (GInst->getIntrinsicID() == GenISAIntrinsic::GenISA_simdBlockRead)
326+
return MemoryLocation::getForArgument(cast<CallInst>(I), 0, TLI);
327+
328+
// TODO: Do coarse-grained thing so far. Need better checking for
329+
// non load or store instructions which may read/write memory.
330+
return MemoryLocation();
331+
}
332+
333+
// Symbolic difference of two address values
334+
// return value:
335+
// true if A1 - A0 = constant in bytes, and return that constant as BO.
336+
// false if A1 - A0 != constant. BO will be undefined.
337+
// BO: byte offset
338+
bool getDiffIfConstant(Value *A0, Value *A1, int64_t &ConstBO, SymbolicEvaluation &symEval)
339+
{
340+
// Using a simple integer symbolic expression (polynomial) as SCEV
341+
// does not work well for this.
342+
SymExpr *S0 = symEval.getSymExpr(A0);
343+
SymExpr *S1 = symEval.getSymExpr(A1);
344+
return symEval.isOffByConstant(S0, S1, ConstBO);
345+
}
346+
347+
// If I0 and I1 are load/store insts, compare their address operands and return
348+
// the constant difference if it is; return false otherwise.
349+
bool getAddressDiffIfConstant(Instruction *I0, Instruction *I1, int64_t &BO, SymbolicEvaluation &symEval)
350+
{
351+
if (isa<LoadInst>(I0) && isa<LoadInst>(I1) ||
352+
isa<PredicatedLoadIntrinsic>(I0) && isa<PredicatedLoadIntrinsic>(I1))
353+
{
354+
auto LI0 = ALoadInst::get(I0);
355+
auto LI1 = ALoadInst::get(I1);
356+
return getDiffIfConstant(LI0->getPointerOperand(), LI1->getPointerOperand(), BO, symEval);
357+
}
358+
if (isa<StoreInst>(I0) && isa<StoreInst>(I1) ||
359+
isa<PredicatedStoreIntrinsic>(I0) && isa<PredicatedStoreIntrinsic>(I1))
360+
{
361+
auto SI0 = AStoreInst::get(I0);
362+
auto SI1 = AStoreInst::get(I1);
363+
return getDiffIfConstant(SI0->getPointerOperand(), SI1->getPointerOperand(), BO, symEval);
364+
}
365+
return false;
366+
}
367+
} // namespace IGC

0 commit comments

Comments
 (0)