فهرست منبع

[SPIR-V] Add support for empty string (#4363)

Fixes #4360
Greg Fischer 3 سال پیش
والد
کامیت
b71bfeac6a

+ 6 - 1
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -754,6 +754,7 @@ public:
                        bool specConst = false);
   SpirvConstant *getConstantNull(QualType);
 
+  SpirvString *createString(llvm::StringRef str);
   SpirvString *getString(llvm::StringRef str);
 
   const HybridPointerType *getPhysicalStorageBufferType(QualType pointee);
@@ -855,8 +856,12 @@ private:
   SpirvDebugExpression *nullDebugExpr;
 
   // To avoid generating multiple OpStrings for the same string literal
-  // the SpirvBuilder will generate and reuse them.
+  // the SpirvBuilder will generate and reuse them. The empty string is
+  // kept track of separately. This is because the empty string is used
+  // as the EmptyKey and TombstoneKey for the map, prohibiting insertion
+  // of the empty string as a contained value.
   llvm::DenseMap<llvm::StringRef, SpirvString *, StringMapInfo> stringLiterals;
+  SpirvString *emptyString;
 
   /// Mapping of CTBuffers including matrix 1xN with FXC memory layout to their
   /// clone variables. We need it to avoid multiple clone variables for the same

+ 20 - 9
tools/clang/lib/SPIRV/SpirvBuilder.cpp

@@ -32,7 +32,7 @@ SpirvBuilder::SpirvBuilder(ASTContext &ac, SpirvContext &ctx,
       mod(llvm::make_unique<SpirvModule>()), function(nullptr),
       moduleInit(nullptr), moduleInitInsertPoint(nullptr), spirvOptions(opt),
       builtinVars(), debugNone(nullptr), nullDebugExpr(nullptr),
-      stringLiterals() {}
+      stringLiterals(), emptyString(nullptr) {}
 
 SpirvBuilder::SpirvBuilder(SpirvContext &ctx, const SpirvCodeGenOptions &opt,
                            FeatureManager &featureMg)
@@ -40,7 +40,7 @@ SpirvBuilder::SpirvBuilder(SpirvContext &ctx, const SpirvCodeGenOptions &opt,
       mod(llvm::make_unique<SpirvModule>()), function(nullptr),
       moduleInit(nullptr), moduleInitInsertPoint(nullptr), spirvOptions(opt),
       builtinVars(), debugNone(nullptr), nullDebugExpr(nullptr),
-      stringLiterals() {}
+      stringLiterals(), emptyString(nullptr) {}
 
 SpirvFunction *SpirvBuilder::createSpirvFunction(QualType returnType,
                                                  SourceLocation loc,
@@ -1708,20 +1708,31 @@ SpirvConstant *SpirvBuilder::getConstantNull(QualType type) {
   return nullConst;
 }
 
-SpirvString *SpirvBuilder::getString(llvm::StringRef str) {
-  // Reuse an existing instruction if possible.
-  auto iter = stringLiterals.find(str.str());
-  if (iter != stringLiterals.end())
-    return iter->second;
-
+SpirvString *SpirvBuilder::createString(llvm::StringRef str) {
   // Create a SpirvString instruction
   auto *instr = new (context) SpirvString(/* SourceLocation */ {}, str);
   instr->setRValue();
-  stringLiterals[str.str()] = instr;
+  if (str.empty())
+    emptyString = instr;
+  else
+    stringLiterals[str.str()] = instr;
   mod->addString(instr);
   return instr;
 }
 
+SpirvString *SpirvBuilder::getString(llvm::StringRef str) {
+  // Reuse an existing instruction if possible.
+  if (str.empty()) {
+    if (emptyString)
+      return emptyString;
+  } else {
+    auto iter = stringLiterals.find(str.str());
+    if (iter != stringLiterals.end())
+      return iter->second;
+  }
+  return createString(str);
+}
+
 const HybridPointerType *
 SpirvBuilder::getPhysicalStorageBufferType(QualType pointee) {
   return context.getPointerType(pointee,

+ 16 - 0
tools/clang/test/CodeGenSPIRV/spirv.string.hlsl

@@ -0,0 +1,16 @@
+// RUN: %dxc -Wno-effects-syntax -E MainPs -T ps_6_0 
+string g_renderState_FillMode < string arg1 = "WIREFRAME" ; > = "" ;
+struct PS_OUTPUT
+{
+    float4 vColor0 : SV_Target0 ;
+} ;
+
+// CHECK: {{%\d+}} = OpString ""
+
+PS_OUTPUT MainPs (  )
+{
+    PS_OUTPUT o ;
+    o . vColor0 = float4( 0, 0, 0, 1 );
+    return o ;
+}
+

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

@@ -1548,6 +1548,10 @@ TEST_F(FileTest, WaveOpNoTargetEnvError) {
 // SPIR-V specific
 TEST_F(FileTest, SpirvStorageClass) { runFileTest("spirv.storage-class.hlsl"); }
 
+TEST_F(FileTest, SpirvString) {
+  runFileTest("spirv.string.hlsl");
+}
+
 TEST_F(FileTest, SpirvControlFlowMissingReturn) {
   runFileTest("spirv.cf.ret-missing.hlsl");
 }