Procházet zdrojové kódy

[spirv] Use SetVector for storing Decorations.

Ehsan Nasiri před 6 roky
rodič
revize
259853a75a

+ 2 - 0
tools/clang/include/clang/SPIRV/SpirvInstruction.h

@@ -421,6 +421,8 @@ public:
 
   bool invokeVisitor(Visitor *v) override;
 
+  bool operator==(const SpirvDecoration &that) const;
+
   // Returns the instruction that is the target of the decoration.
   SpirvInstruction *getTarget() const { return target; }
 

+ 22 - 1
tools/clang/include/clang/SPIRV/SpirvModule.h

@@ -34,6 +34,19 @@ struct ExtensionComparisonInfo {
   }
 };
 
+struct DecorationComparisonInfo {
+  static inline SpirvDecoration *getEmptyKey() { return nullptr; }
+  static inline SpirvDecoration *getTombstoneKey() { return nullptr; }
+  static unsigned getHashValue(const SpirvDecoration *decor) {
+    return llvm::hash_combine(decor->getTarget(),
+                              static_cast<uint32_t>(decor->getDecoration()));
+  }
+  static bool isEqual(SpirvDecoration *LHS, SpirvDecoration *RHS) {
+    // Either both are null, or both should have the same underlying decoration.
+    return (LHS == RHS) || (LHS && RHS && *LHS == *RHS);
+  }
+};
+
 /// The class representing a SPIR-V module in memory.
 ///
 /// A SPIR-V module contains two main parts: instructions for "metadata" (e.g.,
@@ -122,7 +135,15 @@ private:
   llvm::SmallVector<SpirvExecutionMode *, 4> executionModes;
   SpirvSource *debugSource;
   std::vector<SpirvModuleProcessed *> moduleProcesses;
-  std::vector<SpirvDecoration *> decorations;
+
+  // Use a set for storing decoration. This will ensure that we don't apply the
+  // same decoration to the same target more than once. Although the set stores
+  // pointers, the provided DecorationComparisonInfo compares the
+  // SpirvDecoration objects, not the pointers.
+  llvm::SetVector<SpirvDecoration *, std::vector<SpirvDecoration *>,
+                  llvm::DenseSet<SpirvDecoration *, DecorationComparisonInfo>>
+      decorations;
+
   std::vector<SpirvConstant *> constants;
   std::vector<SpirvVariable *> variables;
   std::vector<SpirvFunction *> functions;

+ 7 - 0
tools/clang/lib/SPIRV/SpirvInstruction.cpp

@@ -236,6 +236,13 @@ spv::Op SpirvDecoration::getDecorateOpcode(
                                 : spv::Op::OpDecorate;
 }
 
+bool SpirvDecoration::operator==(const SpirvDecoration &that) const {
+  return target == that.target && decoration == that.decoration &&
+         params == that.params && idParams == that.idParams &&
+         index.hasValue() == that.index.hasValue() &&
+         (!index.hasValue() || index.getValue() == that.index.getValue());
+}
+
 SpirvVariable::SpirvVariable(QualType resultType, SourceLocation loc,
                              spv::StorageClass sc, bool precise,
                              SpirvInstruction *initializerInst)

+ 5 - 3
tools/clang/lib/SPIRV/SpirvModule.cpp

@@ -53,8 +53,10 @@ bool SpirvModule::invokeVisitor(Visitor *visitor, bool reverseOrder) {
         return false;
     }
 
-    for (auto iter = decorations.rbegin(); iter != decorations.rend(); ++iter) {
-      auto *decoration = *iter;
+    // Since SetVector doesn't have 'rbegin()' and 'rend()' methods, we use
+    // manual indexing.
+    for (auto decorIndex = decorations.size(); decorIndex > 0; --decorIndex) {
+      auto *decoration = decorations[decorIndex - 1];
       if (!decoration->invokeVisitor(visitor))
         return false;
     }
@@ -232,7 +234,7 @@ void SpirvModule::addVariable(SpirvVariable *var) {
 
 void SpirvModule::addDecoration(SpirvDecoration *decor) {
   assert(decor && "cannot add null decoration to the module");
-  decorations.push_back(decor);
+  decorations.insert(decor);
 }
 
 void SpirvModule::addConstant(SpirvConstant *constant) {

+ 10 - 0
tools/clang/test/CodeGenSPIRV/decoration.unique.hlsl

@@ -0,0 +1,10 @@
+// Run: %dxc -T ps_6_2 -E main -fspv-reflect
+
+// Make sure the same decoration is not applied twice.
+//
+// CHECK:     OpDecorateStringGOOGLE %gl_FragCoord HlslSemanticGOOGLE "SV_POSITION"
+// CHECK-NOT: OpDecorateStringGOOGLE %gl_FragCoord HlslSemanticGOOGLE "SV_POSITION"
+
+float4 main(float4 pix_pos : SV_POSITION, float4 pix_pos2: SV_POSITION): SV_Target {
+  return 0;
+}

+ 3 - 0
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -1849,6 +1849,9 @@ TEST_F(FileTest, RayTracingNVLibrary) {
   runFileTest("raytracing.nv.library.hlsl");
 }
 
+// For decoration uniqueness
+TEST_F(FileTest, DecorationUnique) { runFileTest("decoration.unique.hlsl"); }
+
 // For RelaxedPrecision decorations
 TEST_F(FileTest, DecorationRelaxedPrecisionBasic) {
   runFileTest("decoration.relaxed-precision.basic.hlsl");