Skip to content

Commit 8b7e92a

Browse files
jaladreipsigcbot
authored andcommitted
Handle loops in liveness analysis for merge allocas
Liveness analysis does not consider the declaration (allocation instruction) as a part of live range of the allocation, instead finds the last possible point that still dominates all uses. That did not work with loops, where the analysis did not consider the need for the live range to wrap around the loop. The fix introduced by this change checks if the live range escapes the loop (flows out the exiting block and into the exit block), and if that's true, includes the whole loop in the live range.
1 parent 105c44c commit 8b7e92a

File tree

8 files changed

+141
-9
lines changed

8 files changed

+141
-9
lines changed

IGC/AdaptorCommon/RayTracing/MergeAllocas.cpp

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ SPDX-License-Identifier: MIT
1414
#include "common/LLVMWarningsPush.hpp"
1515
#include <llvm/ADT/SetVector.h>
1616
#include <llvm/ADT/SetOperations.h>
17+
#include <llvm/Analysis/LoopInfo.h>
18+
#include <llvm/IR/Constants.h>
1719
#include <llvm/IR/Dominators.h>
1820
#include <llvm/IR/InstIterator.h>
1921
#include <llvm/IR/Instructions.h>
20-
#include <llvm/IR/Constants.h>
2122
#include "common/LLVMWarningsPop.hpp"
2223

2324
using namespace llvm;
@@ -26,6 +27,7 @@ using namespace IGC;
2627
// Register pass to igc-opt
2728
IGC_INITIALIZE_PASS_BEGIN(AllocationBasedLivenessAnalysis, "igc-allocation-based-liveness-analysis", "Analyze the lifetimes of instruction allocated by a specific intrinsic", false, true)
2829
IGC_INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
30+
IGC_INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass)
2931
IGC_INITIALIZE_PASS_END(AllocationBasedLivenessAnalysis, "igc-allocation-based-liveness-analysis", "Analyze the lifetimes of instruction allocated by a specific intrinsic", false, true)
3032

3133
char AllocationBasedLivenessAnalysis::ID = 0;
@@ -34,6 +36,7 @@ void AllocationBasedLivenessAnalysis::getAnalysisUsage(llvm::AnalysisUsage& AU)
3436
{
3537
AU.setPreservesAll();
3638
AU.addRequired<DominatorTreeWrapperPass>();
39+
AU.addRequired<LoopInfoWrapperPass>();
3740
}
3841

3942
AllocationBasedLivenessAnalysis::AllocationBasedLivenessAnalysis() : FunctionPass(ID)
@@ -68,6 +71,7 @@ AllocationBasedLivenessAnalysis::LivenessData* AllocationBasedLivenessAnalysis::
6871
// that's a practice, but we only care about the last block that dominates all uses
6972
BasicBlock* commonDominator = nullptr;
7073
auto* DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
74+
auto* LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
7175

7276
bool hasNoLifetimeEnd = false;
7377

@@ -142,10 +146,10 @@ AllocationBasedLivenessAnalysis::LivenessData* AllocationBasedLivenessAnalysis::
142146
);
143147
}
144148

145-
return new LivenessData(I, allUsers, commonDominator);
149+
return new LivenessData(I, allUsers, *LI, commonDominator);
146150
}
147151

148-
AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocationInstruction, SetVector<Instruction*> usersOfAllocation, BasicBlock* userDominatorBlock)
152+
AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocationInstruction, const SetVector<Instruction*>& usersOfAllocation, const LoopInfo& LI, BasicBlock* userDominatorBlock)
149153
{
150154
if (!userDominatorBlock)
151155
userDominatorBlock = allocationInstruction->getParent();
@@ -176,13 +180,39 @@ AllocationBasedLivenessAnalysis::LivenessData::LivenessData(Instruction* allocat
176180
}
177181
}
178182

183+
// if the lifetime escapes any loop, we should make sure all the loops blocks are included
184+
for (const auto& loop : LI)
185+
{
186+
SmallVector<std::pair<BasicBlock*, BasicBlock*>> exitEdges;
187+
loop->getExitEdges(exitEdges);
188+
189+
if (llvm::any_of(exitEdges, [&](auto edge) { return bbOut.contains(edge.first) && bbIn.contains(edge.second); }))
190+
{
191+
llvm::for_each(
192+
loop->blocks(),
193+
[&](auto* block) {
194+
bbOut.insert(block);
195+
if (block != loop->getHeader())
196+
bbIn.insert(block);
197+
}
198+
);
199+
}
200+
}
201+
202+
// substract the inflow blocks from the outflow blocks to find the block which starts the lifetime - there should be only one!
203+
auto bbOutOnly = bbOut;
204+
set_subtract(bbOutOnly, bbIn);
205+
206+
IGC_ASSERT_MESSAGE(bbOutOnly.size() == 1, "Multiple lifetime start blocks?");
207+
208+
auto* lifetimeStartBB = *bbOutOnly.begin();
209+
179210
// fill out the lifetime start/ends instruction
180-
for (auto& I : *userDominatorBlock)
211+
for (auto& I : *lifetimeStartBB)
181212
{
182213
lifetimeStart = &I;
183214
if (usersOfAllocation.contains(&I))
184215
break;
185-
186216
}
187217

188218
// if bbIn is empty, the entire lifetime is contained within userDominatorBlock

IGC/AdaptorCommon/RayTracing/MergeAllocas.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,18 @@ SPDX-License-Identifier: MIT
77
============================= end_copyright_notice ===========================*/
88

99
#include "common/LLVMWarningsPush.hpp"
10-
#include <llvm/IR/Instruction.h>
10+
#include <llvm/Pass.h>
11+
#include <llvm/ADT/DenseSet.h>
1112
#include <llvm/ADT/SetVector.h>
12-
#include <llvm/ADT/MapVector.h>
1313
#include "common/LLVMWarningsPop.hpp"
1414

15+
namespace llvm {
16+
class BasicBlock;
17+
class Function;
18+
class Instruction;
19+
class LoopInfo;
20+
}
21+
1522
namespace IGC
1623
{
1724
class MergeAllocas : public llvm::FunctionPass
@@ -58,7 +65,7 @@ namespace IGC
5865
llvm::DenseSet<llvm::BasicBlock*> bbIn;
5966
llvm::DenseSet<llvm::BasicBlock*> bbOut;
6067

61-
LivenessData(llvm::Instruction* allocationInstruction, llvm::SetVector<llvm::Instruction*> usersOfAllocation, llvm::BasicBlock* userDominatorBlock = nullptr);
68+
LivenessData(llvm::Instruction* allocationInstruction, const llvm::SetVector<llvm::Instruction*>& usersOfAllocation, const llvm::LoopInfo& LI, llvm::BasicBlock* userDominatorBlock = nullptr);
6269

6370
bool OverlapsWith(const LivenessData& LD) const;
6471
};
@@ -78,5 +85,4 @@ namespace IGC
7885
}
7986
}
8087
};
81-
8288
} // namespace IGC

IGC/Compiler/tests/MergeAllocas/test1.ll renamed to IGC/Compiler/tests/MergeAllocas/basic-1.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
19
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
210
target triple = "dxil-ms-dx"
311

IGC/Compiler/tests/MergeAllocas/test2.ll renamed to IGC/Compiler/tests/MergeAllocas/basic-2.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
19
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
210
target triple = "dxil-ms-dx"
311

IGC/Compiler/tests/MergeAllocas/test3.ll renamed to IGC/Compiler/tests/MergeAllocas/basic-3.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
19
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
210
target triple = "dxil-ms-dx"
311

IGC/Compiler/tests/MergeAllocas/test4.ll renamed to IGC/Compiler/tests/MergeAllocas/basic-4.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
19
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
210
target triple = "dxil-ms-dx"
311

IGC/Compiler/tests/MergeAllocas/test5.ll renamed to IGC/Compiler/tests/MergeAllocas/basic-5.ll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
19
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
210
target triple = "dxil-ms-dx"
311

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2024 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
target datalayout = "e-p:32:32:32-p1:64:64:64-p2:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:32:32-v96:32:32-v128:32:32-a0:0:32-n8:16:32-S32"
10+
target triple = "dxil-ms-dx"
11+
12+
; RUN: igc_opt --opaque-pointers -S --platformbmg --igc-merge-allocas %s | FileCheck %s
13+
14+
define void @test() #0 {
15+
%alloca1 = alloca i32
16+
%alloca2 = alloca i32
17+
; CHECK: alloca i32
18+
; CHECK: alloca i32
19+
br label %looppreheader
20+
21+
looppreheader:
22+
23+
br label %loopheader
24+
25+
loopheader:
26+
br label %loopbody1
27+
28+
loopbody1:
29+
store i32 9, ptr %alloca1
30+
br label %loopbody2
31+
32+
loopbody2:
33+
%a = load i32, ptr %alloca1
34+
store i32 10, ptr %alloca2
35+
br i1 false, label %loopheader, label %loopexit
36+
37+
loopexit:
38+
%load1 = load i32, ptr %alloca2
39+
br label %commonret
40+
41+
commonret:
42+
ret void
43+
}
44+
45+
attributes #0 = { nounwind readnone }
46+
47+
48+
!llvm.ident = !{!0, !0, !0, !0}
49+
!dx.version = !{!1, !1, !1, !1}
50+
!dx.valver = !{!2, !2, !2, !2}
51+
!dx.shaderModel = !{!3, !3, !3, !3}
52+
53+
!0 = !{!"clang version 3.7 (tags/RELEASE_370/final)"}
54+
!1 = !{i32 1, i32 5}
55+
!2 = !{i32 1, i32 6}
56+
!3 = !{!"lib", i32 6, i32 5}

0 commit comments

Comments
 (0)