Skip to content

Commit cd0e32c

Browse files
authored
[spirv] Prevent overlapping explicit locations (microsoft#5557)
When explicit location number assignments are used, ensure that if a variable consumes more than one Location (for example, in the case of double4) that all Locations are marked as used so that error messages are correctly emitted. Small improvements to error messaging and fixed up existing affected tests while migrating them to LIT at the same time. Fixes microsoft#5540
1 parent da36098 commit cd0e32c

File tree

6 files changed

+62
-63
lines changed

6 files changed

+62
-63
lines changed

tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1932,6 +1932,7 @@ bool DeclResultIdMapper::finalizeStageIOLocations(bool forInput) {
19321932

19331933
const auto *attr = var.getLocationAttr();
19341934
const auto loc = attr->getNumber();
1935+
const auto locCount = var.getLocationCount();
19351936
const auto attrLoc = attr->getLocation(); // Attr source code location
19361937
const auto idx = var.getIndexAttr() ? var.getIndexAttr()->getNumber() : 0;
19371938

@@ -1943,13 +1944,17 @@ bool DeclResultIdMapper::finalizeStageIOLocations(bool forInput) {
19431944
}
19441945

19451946
// Make sure the same location is not assigned more than once
1946-
if (locSet.isLocUsed(loc, idx)) {
1947-
emitError("stage %select{output|input}0 location #%1 already assigned",
1948-
attrLoc)
1949-
<< forInput << loc;
1950-
noError = false;
1947+
for (uint32_t l = loc; l < loc + locCount; ++l) {
1948+
if (locSet.isLocUsed(l, idx)) {
1949+
emitError("stage %select{output|input}0 location #%1 already "
1950+
"consumed by semantic '%2'",
1951+
attrLoc)
1952+
<< forInput << l << stageVars[idx].getSemanticStr();
1953+
noError = false;
1954+
}
1955+
1956+
locSet.useLoc(l, idx);
19511957
}
1952-
locSet.useLoc(loc, idx);
19531958

19541959
spvBuilder.decorateLocation(var.getSpirvInstr(), loc);
19551960
if (var.getIndexAttr())
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: not %dxc -T ps_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s
2+
3+
struct PSInput
4+
{
5+
[[vk::location(0)]] double4 data1 : COLOR0; // double4 consumes 2 Locations (0 and 1)
6+
[[vk::location(1)]] double4 data2 : COLOR1;
7+
// CHECK: error: stage input location #1 already consumed by semantic 'COLOR0'
8+
};
9+
10+
void main(PSInput input) : SV_TARGET
11+
{
12+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: not %dxc -T vs_6_0 -E main -fcgl -spirv %s 2>&1 | FileCheck %s
2+
3+
struct S {
4+
[[vk::location(3)]] float a : A;
5+
// CHECK: error: stage input location #3 already consumed by semantic 'M'
6+
};
7+
8+
float main(
9+
[[vk::location(3)]] float m : M,
10+
S s
11+
) : R {
12+
return 1.0;
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: not %dxc -T vs_6_0 -E main -fcgl -spirv %s 2>&1 | FileCheck %s
2+
3+
struct T {
4+
[[vk::location(3)]] float i : A;
5+
// CHECK: error: stage output location #3 already consumed by semantic 'M'
6+
};
7+
8+
[[vk::location(3)]]
9+
float main(
10+
[[vk::location(3)]] float m : M,
11+
out T t
12+
) : R {
13+
return 1.0;
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: not %dxc -T vs_6_0 -E main -fcgl %s -spirv 2>&1 | FileCheck %s
2+
3+
[[vk::location(3)]]
4+
float main(
5+
[[vk::location(3)]] float m : M,
6+
[[vk::location(3)]] float n : N,
7+
// CHECK: error: stage input location #3 already consumed by semantic 'M'
8+
[[vk::location(3)]] out float x : X
9+
// CHECK: error: stage output location #3 already consumed by semantic 'M'
10+
) : R {
11+
return 1.0;
12+
}

tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,63 +2041,6 @@ TEST_F(FileTest, VulkanLocationPartiallyAssigned) {
20412041
runFileTest("vk.location.mixed.hlsl", Expect::Failure);
20422042
}
20432043

2044-
std::string getStageLocationReassignTestShader(const std::string &typeDef,
2045-
const std::string &stageVar,
2046-
const std::string &check) {
2047-
const std::string command(R"(// RUN: %dxc -T vs_6_0 -E main)");
2048-
const std::string shader = command + typeDef + R"(
2049-
[[vk::location(3)]] // first use
2050-
float main(
2051-
[[vk::location(3)]] float m : M, // first use
2052-
)" + stageVar + R"(
2053-
) : R {
2054-
return 1.0;
2055-
}
2056-
)" + check;
2057-
return shader;
2058-
}
2059-
2060-
TEST_F(FileTest, VulkanLocationReassigned) {
2061-
runCodeTest(getStageLocationReassignTestShader(R"()",
2062-
R"(
2063-
[[vk::location(3)]] float n : N, // error
2064-
[[vk::location(3)]] out float x : X // error
2065-
)",
2066-
R"(
2067-
// CHECK: error: stage input location #3 already assigned
2068-
// CHECK: error: stage output location #3 already assigned
2069-
)"),
2070-
Expect::Failure);
2071-
}
2072-
2073-
TEST_F(FileTest, VulkanLocationReassignedForInputVar) {
2074-
runCodeTest(
2075-
getStageLocationReassignTestShader(
2076-
R"(
2077-
struct S {
2078-
[[vk::location(3)]] float a : A; // error
2079-
[[vk::location(3)]] float b : B; // error
2080-
};
2081-
)",
2082-
R"(S s)",
2083-
R"(// CHECK: error: stage input location #3 already assigned)"),
2084-
Expect::Failure);
2085-
}
2086-
2087-
TEST_F(FileTest, VulkanLocationReassignedForOutputVar) {
2088-
runCodeTest(getStageLocationReassignTestShader(
2089-
R"(
2090-
struct T {
2091-
[[vk::location(3)]] float i : A; // error
2092-
[[vk::location(3)]] float j : B; // error
2093-
};
2094-
)",
2095-
R"(out T t)",
2096-
R"(
2097-
// CHECK: error: stage output location #3 already assigned
2098-
)"),
2099-
Expect::Failure);
2100-
}
21012044
TEST_F(FileTest, StageVariableDuplicatedLocation) {
21022045
runFileTest("semantic.duplicated-location.hlsl", Expect::Failure);
21032046
}

0 commit comments

Comments
 (0)