Skip to content

Commit 0001483

Browse files
pszymichigcbot
authored andcommitted
Revert: Trivially eliminate TrivialLocalMemoryOpsElimination pass
This reverts commit 6a215e5.
1 parent b488aab commit 0001483

File tree

8 files changed

+527
-0
lines changed

8 files changed

+527
-0
lines changed

IGC/Compiler/CustomSafeOptPass.cpp

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,179 @@ void CustomSafeOptPass::visitExtractElementInst(ExtractElementInst& I)
24512451
dp4WithIdentityMatrix(I);
24522452
}
24532453

2454+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2455+
// This pass removes dead local memory loads and stores. If we remove all such loads and stores, we also
2456+
// remove all local memory fences together with barriers that follow.
2457+
//
2458+
IGC_INITIALIZE_PASS_BEGIN(TrivialLocalMemoryOpsElimination, "TrivialLocalMemoryOpsElimination", "TrivialLocalMemoryOpsElimination", false, false)
2459+
IGC_INITIALIZE_PASS_END(TrivialLocalMemoryOpsElimination, "TrivialLocalMemoryOpsElimination", "TrivialLocalMemoryOpsElimination", false, false)
2460+
2461+
char TrivialLocalMemoryOpsElimination::ID = 0;
2462+
2463+
TrivialLocalMemoryOpsElimination::TrivialLocalMemoryOpsElimination() : FunctionPass(ID)
2464+
{
2465+
initializeTrivialLocalMemoryOpsEliminationPass(*PassRegistry::getPassRegistry());
2466+
}
2467+
2468+
bool TrivialLocalMemoryOpsElimination::runOnFunction(Function& F)
2469+
{
2470+
bool change = false;
2471+
2472+
IGCMD::MetaDataUtils* pMdUtil = getAnalysis<MetaDataUtilsWrapper>().getMetaDataUtils();
2473+
if (!isEntryFunc(pMdUtil, &F))
2474+
{
2475+
// Skip if it is non-entry function. For example, a subroutine
2476+
// foo ( local int* p) { ...... store v, p; ......}
2477+
// in which no localMemoptimization will be performed.
2478+
return change;
2479+
}
2480+
2481+
visit(F);
2482+
if (!abortPass && (m_LocalLoadsToRemove.empty() ^ m_LocalStoresToRemove.empty()))
2483+
{
2484+
for (StoreInst* Inst : m_LocalStoresToRemove)
2485+
{
2486+
Inst->eraseFromParent();
2487+
change = true;
2488+
}
2489+
2490+
for (LoadInst* Inst : m_LocalLoadsToRemove)
2491+
{
2492+
if (Inst->use_empty())
2493+
{
2494+
Inst->eraseFromParent();
2495+
change = true;
2496+
}
2497+
}
2498+
2499+
for (CallInst* Inst : m_LocalFencesBariersToRemove)
2500+
{
2501+
Inst->eraseFromParent();
2502+
change = true;
2503+
}
2504+
}
2505+
m_LocalStoresToRemove.clear();
2506+
m_LocalLoadsToRemove.clear();
2507+
m_LocalFencesBariersToRemove.clear();
2508+
2509+
return change;
2510+
}
2511+
2512+
/*
2513+
OCL instruction barrier(CLK_LOCAL_MEM_FENCE); is translate to two instructions
2514+
call void @llvm.genx.GenISA.memoryfence(i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true)
2515+
call void @llvm.genx.GenISA.threadgroupbarrier()
2516+
2517+
if we remove call void @llvm.genx.GenISA.memoryfence(i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true)
2518+
we must remove next instruction if it is call void @llvm.genx.GenISA.threadgroupbarrier()
2519+
*/
2520+
void TrivialLocalMemoryOpsElimination::findNextThreadGroupBarrierInst(Instruction& I)
2521+
{
2522+
auto nextInst = I.getNextNonDebugInstruction();
2523+
if (isa<GenIntrinsicInst>(nextInst))
2524+
{
2525+
GenIntrinsicInst* II = cast<GenIntrinsicInst>(nextInst);
2526+
if (II->getIntrinsicID() == GenISAIntrinsic::GenISA_threadgroupbarrier)
2527+
{
2528+
m_LocalFencesBariersToRemove.push_back(dyn_cast<CallInst>(nextInst));
2529+
}
2530+
}
2531+
}
2532+
2533+
void TrivialLocalMemoryOpsElimination::visitLoadInst(LoadInst& I)
2534+
{
2535+
if (I.getPointerAddressSpace() == ADDRESS_SPACE_LOCAL)
2536+
{
2537+
m_LocalLoadsToRemove.push_back(&I);
2538+
}
2539+
else if (I.getPointerAddressSpace() == ADDRESS_SPACE_GENERIC)
2540+
{
2541+
abortPass = true;
2542+
}
2543+
}
2544+
2545+
void TrivialLocalMemoryOpsElimination::visitStoreInst(StoreInst& I)
2546+
{
2547+
if (I.getPointerAddressSpace() == ADDRESS_SPACE_LOCAL)
2548+
{
2549+
if (auto *GV = dyn_cast<GlobalVariable>(I.getPointerOperand()->stripPointerCasts()))
2550+
{
2551+
// Device sanitizer instrumentation pass inserts a new local memory
2552+
// variable and inserts store to the variable in a kernel. The
2553+
// variable is loaded later in no-inline functions. For this case,
2554+
// do not eliminate the store.
2555+
if (GV->getName().startswith("__Asan"))
2556+
{
2557+
return;
2558+
}
2559+
}
2560+
m_LocalStoresToRemove.push_back(&I);
2561+
}
2562+
else if (I.getPointerAddressSpace() == ADDRESS_SPACE_GENERIC)
2563+
{
2564+
abortPass = true;
2565+
}
2566+
}
2567+
2568+
bool TrivialLocalMemoryOpsElimination::isLocalBarrier(CallInst& I)
2569+
{
2570+
//check arguments in call void @llvm.genx.GenISA.memoryfence(i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true) if match to
2571+
// (i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true) it is local barrier
2572+
std::vector<bool> argumentsOfMemoryBarrier;
2573+
2574+
for (auto arg = I.arg_begin(); arg != I.arg_end(); ++arg)
2575+
{
2576+
ConstantInt* ci = dyn_cast<ConstantInt>(arg);
2577+
if (ci) {
2578+
argumentsOfMemoryBarrier.push_back(ci->getValue().getBoolValue());
2579+
}
2580+
else {
2581+
// argument is not a constant, so we can't tell.
2582+
return false;
2583+
}
2584+
}
2585+
2586+
return argumentsOfMemoryBarrier == m_argumentsOfLocalMemoryBarrier;
2587+
}
2588+
2589+
// If any call instruction use pointer to local memory abort pass execution
2590+
void TrivialLocalMemoryOpsElimination::anyCallInstUseLocalMemory(CallInst& I)
2591+
{
2592+
Function* fn = I.getCalledFunction();
2593+
2594+
if (fn != NULL)
2595+
{
2596+
for (auto arg = fn->arg_begin(); arg != fn->arg_end(); ++arg)
2597+
{
2598+
if (arg->getType()->isPointerTy())
2599+
{
2600+
if (arg->getType()->getPointerAddressSpace() == ADDRESS_SPACE_LOCAL || arg->getType()->getPointerAddressSpace() == ADDRESS_SPACE_GENERIC) abortPass = true;
2601+
}
2602+
}
2603+
}
2604+
}
2605+
2606+
void TrivialLocalMemoryOpsElimination::visitCallInst(CallInst& I)
2607+
{
2608+
// detect only: llvm.genx.GenISA.memoryfence(i1 true, i1 false, i1 false, i1 false, i1 false, i1 false, i1 true)
2609+
// (note: the first and last arguments are true)
2610+
// and add them with immediately following barriers to m_LocalFencesBariersToRemove
2611+
anyCallInstUseLocalMemory(I);
2612+
2613+
if (isa<GenIntrinsicInst>(I))
2614+
{
2615+
GenIntrinsicInst* II = cast<GenIntrinsicInst>(&I);
2616+
if (II->getIntrinsicID() == GenISAIntrinsic::GenISA_memoryfence)
2617+
{
2618+
if (isLocalBarrier(I))
2619+
{
2620+
m_LocalFencesBariersToRemove.push_back(&I);
2621+
findNextThreadGroupBarrierInst(I);
2622+
}
2623+
}
2624+
}
2625+
}
2626+
24542627
////////////////////////////////////////////////////////////////////////////////
24552628
IGC_INITIALIZE_PASS_BEGIN(TrivialUnnecessaryTGMFenceElimination, "TrivialUnnecessaryTGMFenceElimination", "TrivialUnnecessaryTGMFenceElimination", false, false)
24562629
IGC_INITIALIZE_PASS_END(TrivialUnnecessaryTGMFenceElimination, "TrivialUnnecessaryTGMFenceElimination", "TrivialUnnecessaryTGMFenceElimination", false, false)

IGC/Compiler/CustomSafeOptPass.hpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,43 @@ namespace IGC
108108
llvm::Value* analyzeTreeForTrunc64bto32b(const llvm::Use& OperandUse, llvm::SmallVector<llvm::BinaryOperator*, 8>& OpsToDelete);
109109
};
110110

111+
// TODO: Remove this pass as unused
112+
class TrivialLocalMemoryOpsElimination : public llvm::FunctionPass, public llvm::InstVisitor<TrivialLocalMemoryOpsElimination>
113+
{
114+
public:
115+
static char ID;
116+
117+
TrivialLocalMemoryOpsElimination();
118+
119+
virtual void getAnalysisUsage(llvm::AnalysisUsage& AU) const override
120+
{
121+
AU.addRequired<CodeGenContextWrapper>();
122+
AU.addRequired<MetaDataUtilsWrapper>();
123+
AU.setPreservesCFG();
124+
}
125+
126+
virtual bool runOnFunction(llvm::Function& F) override;
127+
128+
virtual llvm::StringRef getPassName() const override
129+
{
130+
return "TrivialLocalMemoryOpsElimination";
131+
}
132+
133+
void visitLoadInst(llvm::LoadInst& I);
134+
void visitStoreInst(llvm::StoreInst& I);
135+
void visitCallInst(llvm::CallInst& I);
136+
bool isLocalBarrier(llvm::CallInst& I);
137+
void findNextThreadGroupBarrierInst(llvm::Instruction& I);
138+
void anyCallInstUseLocalMemory(llvm::CallInst& I);
139+
140+
private:
141+
llvm::SmallVector<llvm::LoadInst*, 16> m_LocalLoadsToRemove;
142+
llvm::SmallVector<llvm::StoreInst*, 16> m_LocalStoresToRemove;
143+
llvm::SmallVector<llvm::CallInst*, 16> m_LocalFencesBariersToRemove;
144+
145+
bool abortPass = false;
146+
const std::vector<bool> m_argumentsOfLocalMemoryBarrier{ true, false, false, false, false, false, true };
147+
};
111148
class TrivialUnnecessaryTGMFenceElimination : public llvm::FunctionPass, public llvm::InstVisitor<TrivialUnnecessaryTGMFenceElimination>
112149
{
113150
public:

IGC/Compiler/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ void initializeRegisterEstimatorPass(llvm::PassRegistry&);
232232
void initializeVariableReuseAnalysisPass(llvm::PassRegistry &);
233233
void initializeResourceLoopAnalysisPass(llvm::PassRegistry &);
234234
void initializeTranslationTablePass(llvm::PassRegistry&);
235+
void initializeTrivialLocalMemoryOpsEliminationPass(llvm::PassRegistry&);
235236
void initializeTrivialUnnecessaryTGMFenceEliminationPass(llvm::PassRegistry&);
236237
void initializeSLMConstPropPass(llvm::PassRegistry&);
237238
void initializeBlendToDiscardPass(llvm::PassRegistry&);
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2022-2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; RUN: igc_opt -TrivialLocalMemoryOpsElimination -S < %s | FileCheck %s
10+
; ------------------------------------------------
11+
; TrivialLocalMemoryOpsElimination
12+
; ------------------------------------------------
13+
; This test checks that TrivialLocalMemoryOpsElimination pass follows
14+
; 'How to Update Debug Info' llvm guideline.
15+
16+
; Debug MD for this test was created with debugify pass.
17+
; ------------------------------------------------
18+
19+
; CHECK: define spir_kernel void @test_load{{.*}} !dbg [[SCOPE1:![0-9]*]]
20+
; CHECK: ret {{.*}}, !dbg [[RET1_LOC:![0-9]*]]
21+
22+
define spir_kernel void @test_load(i32 addrspace(3)* %b) !dbg !10 {
23+
%1 = load i32, i32 addrspace(3)* %b, !dbg !15
24+
call void @llvm.dbg.value(metadata i32 %1, metadata !13, metadata !DIExpression()), !dbg !15
25+
ret void, !dbg !16
26+
}
27+
28+
; CHECK: define spir_kernel void @test_store{{.*}} !dbg [[SCOPE2:![0-9]*]]
29+
; CHECK: ret {{.*}}, !dbg [[RET2_LOC:![0-9]*]]
30+
31+
define spir_kernel void @test_store(i32 addrspace(3)* %b) !dbg !17 {
32+
store i32 13, i32 addrspace(3)* %b, !dbg !18
33+
ret void, !dbg !19
34+
}
35+
36+
; CHECK-DAG: [[FILE:![0-9]*]] = !DIFile(filename: "TrivialLocalMemoryOpsElimination.ll", directory: "/")
37+
; CHECK-DAG: [[SCOPE1]] = distinct !DISubprogram(name: "test_load", linkageName: "test_load", scope: null, file: [[FILE]], line: 1
38+
; CHECK-DAG: [[RET1_LOC]] = !DILocation(line: 2, column: 1, scope: [[SCOPE1]])
39+
; CHECK-DAG: [[SCOPE2]] = distinct !DISubprogram(name: "test_store", linkageName: "test_store", scope: null, file: [[FILE]], line: 3
40+
; CHECK-DAG: [[RET2_LOC]] = !DILocation(line: 4, column: 1, scope: [[SCOPE2]])
41+
42+
43+
; Function Attrs: nounwind readnone speculatable
44+
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
45+
46+
attributes #0 = { nounwind readnone speculatable }
47+
48+
!igc.functions = !{!0, !3}
49+
!llvm.dbg.cu = !{!4}
50+
!llvm.debugify = !{!7, !8}
51+
!llvm.module.flags = !{!9}
52+
53+
!0 = !{void (i32 addrspace(3)*)* @test_load, !1}
54+
!1 = !{!2}
55+
!2 = !{!"function_type", i32 0}
56+
!3 = !{void (i32 addrspace(3)*)* @test_store, !1}
57+
!4 = distinct !DICompileUnit(language: DW_LANG_C, file: !5, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !6)
58+
!5 = !DIFile(filename: "TrivialLocalMemoryOpsElimination.ll", directory: "/")
59+
!6 = !{}
60+
!7 = !{i32 4}
61+
!8 = !{i32 1}
62+
!9 = !{i32 2, !"Debug Info Version", i32 3}
63+
!10 = distinct !DISubprogram(name: "test_load", linkageName: "test_load", scope: null, file: !5, line: 1, type: !11, scopeLine: 1, unit: !4, retainedNodes: !12)
64+
!11 = !DISubroutineType(types: !6)
65+
!12 = !{!13}
66+
!13 = !DILocalVariable(name: "1", scope: !10, file: !5, line: 1, type: !14)
67+
!14 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
68+
!15 = !DILocation(line: 1, column: 1, scope: !10)
69+
!16 = !DILocation(line: 2, column: 1, scope: !10)
70+
!17 = distinct !DISubprogram(name: "test_store", linkageName: "test_store", scope: null, file: !5, line: 3, type: !11, scopeLine: 3, unit: !4, retainedNodes: !6)
71+
!18 = !DILocation(line: 3, column: 1, scope: !17)
72+
!19 = !DILocation(line: 4, column: 1, scope: !17)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2022-2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
10+
; REQUIRES: llvm-14-plus
11+
; RUN: igc_opt --opaque-pointers -TrivialLocalMemoryOpsElimination -S < %s | FileCheck %s
12+
; ------------------------------------------------
13+
; TrivialLocalMemoryOpsElimination
14+
; ------------------------------------------------
15+
; This test checks that TrivialLocalMemoryOpsElimination pass follows
16+
; 'How to Update Debug Info' llvm guideline.
17+
18+
; Debug MD for this test was created with debugify pass.
19+
; ------------------------------------------------
20+
21+
; CHECK: define spir_kernel void @test_load{{.*}} !dbg [[SCOPE1:![0-9]*]]
22+
; CHECK: ret {{.*}}, !dbg [[RET1_LOC:![0-9]*]]
23+
24+
define spir_kernel void @test_load(i32 addrspace(3)* %b) !dbg !10 {
25+
%1 = load i32, i32 addrspace(3)* %b, !dbg !15
26+
call void @llvm.dbg.value(metadata i32 %1, metadata !13, metadata !DIExpression()), !dbg !15
27+
ret void, !dbg !16
28+
}
29+
30+
; CHECK: define spir_kernel void @test_store{{.*}} !dbg [[SCOPE2:![0-9]*]]
31+
; CHECK: ret {{.*}}, !dbg [[RET2_LOC:![0-9]*]]
32+
33+
define spir_kernel void @test_store(i32 addrspace(3)* %b) !dbg !17 {
34+
store i32 13, i32 addrspace(3)* %b, !dbg !18
35+
ret void, !dbg !19
36+
}
37+
38+
; CHECK-DAG: [[FILE:![0-9]*]] = !DIFile(filename: "TrivialLocalMemoryOpsElimination.ll", directory: "/")
39+
; CHECK-DAG: [[SCOPE1]] = distinct !DISubprogram(name: "test_load", linkageName: "test_load", scope: null, file: [[FILE]], line: 1
40+
; CHECK-DAG: [[RET1_LOC]] = !DILocation(line: 2, column: 1, scope: [[SCOPE1]])
41+
; CHECK-DAG: [[SCOPE2]] = distinct !DISubprogram(name: "test_store", linkageName: "test_store", scope: null, file: [[FILE]], line: 3
42+
; CHECK-DAG: [[RET2_LOC]] = !DILocation(line: 4, column: 1, scope: [[SCOPE2]])
43+
44+
45+
; Function Attrs: nounwind readnone speculatable
46+
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
47+
48+
attributes #0 = { nounwind readnone speculatable }
49+
50+
!igc.functions = !{!0, !3}
51+
!llvm.dbg.cu = !{!4}
52+
!llvm.debugify = !{!7, !8}
53+
!llvm.module.flags = !{!9}
54+
55+
!0 = !{void (i32 addrspace(3)*)* @test_load, !1}
56+
!1 = !{!2}
57+
!2 = !{!"function_type", i32 0}
58+
!3 = !{void (i32 addrspace(3)*)* @test_store, !1}
59+
!4 = distinct !DICompileUnit(language: DW_LANG_C, file: !5, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !6)
60+
!5 = !DIFile(filename: "TrivialLocalMemoryOpsElimination.ll", directory: "/")
61+
!6 = !{}
62+
!7 = !{i32 4}
63+
!8 = !{i32 1}
64+
!9 = !{i32 2, !"Debug Info Version", i32 3}
65+
!10 = distinct !DISubprogram(name: "test_load", linkageName: "test_load", scope: null, file: !5, line: 1, type: !11, scopeLine: 1, unit: !4, retainedNodes: !12)
66+
!11 = !DISubroutineType(types: !6)
67+
!12 = !{!13}
68+
!13 = !DILocalVariable(name: "1", scope: !10, file: !5, line: 1, type: !14)
69+
!14 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
70+
!15 = !DILocation(line: 1, column: 1, scope: !10)
71+
!16 = !DILocation(line: 2, column: 1, scope: !10)
72+
!17 = distinct !DISubprogram(name: "test_store", linkageName: "test_store", scope: null, file: !5, line: 3, type: !11, scopeLine: 3, unit: !4, retainedNodes: !6)
73+
!18 = !DILocation(line: 3, column: 1, scope: !17)
74+
!19 = !DILocation(line: 4, column: 1, scope: !17)

0 commit comments

Comments
 (0)