Skip to content

Commit 9395376

Browse files
author
Greg Roth
authored
Skip trivially dead GVs during SROA (#4476)
Similar to how allocas are skipped when they are popped off of the worklist and found to have no users, GVs are similarly removed and no further processing is performed. That processing flattened the unused GV, creating new child GVs and associating the debug info from the parent with the children. Since the unused GV had all its uses replaced with another, no debug info is found and the compiler crashed. Also includes more graceful failure if debug info isn't found for any reason Add a test that prompts that memcpy replacement order and verifies that it doesn't crash and doesn't flatten the unused GV A change was made to the order in which identically sized GVs are processed in SROA to make the flattened GVs order consistently
1 parent 07bf1ae commit 9395376

3 files changed

Lines changed: 71 additions & 5 deletions

File tree

lib/HLSL/HLModule.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,10 @@ void HLModule::CreateElementGlobalVariableDebugInfo(
12141214
unsigned sizeInBits, unsigned alignInBits, unsigned offsetInBits,
12151215
StringRef eltName) {
12161216
DIGlobalVariable *DIGV = dxilutil::FindGlobalVariableDebugInfo(GV, DbgInfoFinder);
1217-
DXASSERT_NOMSG(DIGV);
1217+
if (!DIGV) {
1218+
DXASSERT(DIGV, "DIGV Parameter must be non-null");
1219+
return;
1220+
}
12181221
DIBuilder Builder(*GV->getParent());
12191222
DITypeIdentifierMap EmptyMap;
12201223

@@ -1242,7 +1245,10 @@ void HLModule::UpdateGlobalVariableDebugInfo(
12421245
llvm::GlobalVariable *GV, llvm::DebugInfoFinder &DbgInfoFinder,
12431246
llvm::GlobalVariable *NewGV) {
12441247
DIGlobalVariable *DIGV = dxilutil::FindGlobalVariableDebugInfo(GV, DbgInfoFinder);
1245-
DXASSERT_NOMSG(DIGV);
1248+
if (!DIGV) {
1249+
DXASSERT(DIGV, "DIGV Parameter must be non-null");
1250+
return;
1251+
}
12461252
DIBuilder Builder(*GV->getParent());
12471253
DITypeIdentifierMap EmptyMap;
12481254
DIType *DITy = DIGV->getType().resolve(EmptyMap);

lib/Transforms/Scalar/ScalarReplAggregatesHLSL.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,9 +1713,14 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) {
17131713
a1ty->isStructTy() && a1ty->getStructNumElements() == 1;
17141714
auto sz0 = DL.getTypeAllocSize(a0ty);
17151715
auto sz1 = DL.getTypeAllocSize(a1ty);
1716-
if (sz0 == sz1 && (isUnitSzStruct0 || isUnitSzStruct1))
1717-
return getNestedLevelInStruct(a0ty) < getNestedLevelInStruct(a1ty);
1718-
return sz0 < sz1;
1716+
if (sz0 == sz1 && (isUnitSzStruct0 || isUnitSzStruct1)) {
1717+
sz0 = getNestedLevelInStruct(a0ty);
1718+
sz1 = getNestedLevelInStruct(a1ty);
1719+
}
1720+
// If sizes are equal, tiebreak with alphabetically lesser at higher priority
1721+
return sz0 < sz1 || (sz0 == sz1 && isa<GlobalVariable>(a0) &&
1722+
isa<GlobalVariable>(a1) &&
1723+
a0->getName() > a1->getName());
17191724
};
17201725

17211726
std::priority_queue<Value *, std::vector<Value *>,
@@ -1888,6 +1893,14 @@ bool SROAGlobalAndAllocas(HLModule &HLM, bool bHasDbgInfo) {
18881893
}
18891894
} else {
18901895
GlobalVariable *GV = cast<GlobalVariable>(V);
1896+
// Handle dead GVs trivially. These can be formed by RAUWing one GV
1897+
// with another, leaving the original in the worklist
1898+
if (GV->use_empty()) {
1899+
GV->eraseFromParent();
1900+
Changed = true;
1901+
continue;
1902+
}
1903+
18911904
if (staticGVs.count(GV)) {
18921905
Type *Ty = GV->getType()->getPointerElementType();
18931906
// Skip basic types.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// RUN: %dxc -T vs_6_0 -Zi %s | FileCheck %s
2+
3+
// Test replacement of static global in a case where SROA may try to
4+
// process a static global replaced by memcpy lowering.
5+
// This processing includes creating flattened GVs for it
6+
// and then updating the debug info for them with the original DIGV,
7+
// which no longer matches because of the replacement, so null is found
8+
// and unnecessary flattened variables were created.
9+
// Trivially dead GVs are now removed in SROA
10+
11+
// Ensure the replacement var is flattened
12+
// CHECK: ReplacementVar.0 = internal unnamed_addr constant [2 x float]
13+
// CHECK: ReplacementVar.1 = internal unnamed_addr constant [2 x float]
14+
// CHECK: ReplacementVar.2 = internal unnamed_addr constant [2 x float]
15+
// CHECK: ReplacementVar.3 = internal unnamed_addr constant [2 x float]
16+
// Ensure there are no flattened variables created for the replaced GV
17+
// CHECK-NOT: UnusedVar.[0-3]
18+
19+
// CHECK: @main
20+
21+
// Ensure the replacement var gets its debug info
22+
// CHECK: DIGlobalVariable(name: "ReplacementVar",
23+
// CHECK: DIGlobalVariable(name: "ReplacementVar.0",
24+
// CHECK: DIGlobalVariable(name: "ReplacementVar.1",
25+
// CHECK: DIGlobalVariable(name: "ReplacementVar.2",
26+
// CHECK: DIGlobalVariable(name: "ReplacementVar.3",
27+
28+
// Ensure there are no DI for flattened variables created for the replaced GV
29+
// CHECK-NOT: DIGlobalVariable(name: "UnusedVar.[0-3]",
30+
31+
// All const does is force ReplacementVar to be processed first, which
32+
// replaces all uses of OrigVar, but leaves OrigVar in the worklist
33+
// which causes the aforementioned problems when it is reached
34+
// Otherwise, OrigVar would be encountered first and it would be
35+
// replaced at the same time as it was retrieved and removed from the worklist
36+
static const float4 ReplacementVar[2] = { float4(1.0f, 2.0f, 3.0f, 4.0f),
37+
float4(9.0f, 8.0f, 7.0f, 6.0f) };
38+
static float4 OrigVar[2];
39+
40+
float4 main(int ix : I) : SV_Position
41+
{
42+
OrigVar = ReplacementVar;
43+
return OrigVar[ix];
44+
}
45+
46+
// Exclude quoted source file (see readme)
47+
// CHECK-LABEL: {{!"[^"]*\\0A[^"]*"}}

0 commit comments

Comments
 (0)