Browse Source

[spirv] Clean up usage of OpSource(Continued) in new infra.

Ehsan Nasiri 6 years ago
parent
commit
e2f5493518

+ 18 - 17
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -415,12 +415,10 @@ public:
                             llvm::ArrayRef<SpirvVariable *> interfaces,
                             SourceLocation loc = {});
 
-  inline void setShaderModelVersion(uint32_t major, uint32_t minor);
-
-  /// \brief Sets the source file name.
-  inline void setSourceFileName(llvm::StringRef name);
-  /// \brief Sets the main source file content.
-  inline void setSourceFileContent(llvm::StringRef content);
+  /// \brief Sets the shader model version, source file name, and source file
+  /// content.
+  inline void setDebugSource(uint32_t major, uint32_t minor,
+                             llvm::StringRef name, llvm::StringRef content);
 
   /// \brief Adds an execution mode to the module under construction.
   inline void addExecutionMode(SpirvFunction *entryPoint, spv::ExecutionMode em,
@@ -569,8 +567,8 @@ private:
   template <class T>
   SpirvConstant *getConstantInt(T value, bool isSigned, uint32_t bitwidth,
                                 bool specConst) {
-    const IntegerType *intType =
-        isSigned ? context.getSIntType(bitwidth) : context.getUIntType(bitwidth);
+    const IntegerType *intType = isSigned ? context.getSIntType(bitwidth)
+                                          : context.getUIntType(bitwidth);
     SpirvConstantInteger tempConstant(intType, value, specConst);
 
     auto found =
@@ -630,7 +628,6 @@ private:
     return nullConst;
   }
 
-
 private:
   ASTContext &astContext;
   SpirvContext &context; ///< From which we allocate various SPIR-V object
@@ -682,16 +679,20 @@ void SpirvBuilder::addEntryPoint(spv::ExecutionModel em, SpirvFunction *target,
       new (context) SpirvEntryPoint(loc, em, target, targetName, interfaces));
 }
 
-void SpirvBuilder::setShaderModelVersion(uint32_t major, uint32_t minor) {
-  module->setShaderModelVersion(100 * major + 10 * minor);
-}
+void SpirvBuilder::setDebugSource(uint32_t major, uint32_t minor,
+                                  llvm::StringRef name,
+                                  llvm::StringRef content) {
+  uint32_t version = 100 * major + 10 * minor;
 
-void SpirvBuilder::setSourceFileName(llvm::StringRef name) {
-  module->setSourceFileName(name);
-}
+  SpirvString *fileString =
+      name.empty() ? nullptr
+                   : new (context) SpirvString(/*SourceLocation*/ {}, name);
+
+  SpirvSource *debugSource = new (context)
+      SpirvSource(/*SourceLocation*/ {}, spv::SourceLanguage::HLSL, version,
+                  fileString, content);
 
-void SpirvBuilder::setSourceFileContent(llvm::StringRef content) {
-  module->setSourceFileContent(content);
+  module->addDebugSource(debugSource);
 }
 
 void SpirvBuilder::addExecutionMode(SpirvFunction *entryPoint,

+ 3 - 6
tools/clang/include/clang/SPIRV/SpirvModule.h

@@ -85,14 +85,13 @@ public:
   // Adds a constant to the module.
   void addConstant(SpirvConstant *);
 
-  void setShaderModelVersion(uint32_t v) { shaderModelVersion = v; }
-  void setSourceFileName(llvm::StringRef name) { sourceFileName = name; }
-  void setSourceFileContent(llvm::StringRef c) { sourceFileContent = c; }
+  // Adds the debug source to the module.
+  void addDebugSource(SpirvSource *);
+
   void setBound(uint32_t b) { bound = b; }
 
 private:
   uint32_t bound;
-  uint32_t shaderModelVersion;
 
   // "Metadata" instructions
   llvm::SmallVector<SpirvCapability *, 8> capabilities;
@@ -108,8 +107,6 @@ private:
 
   // Shader logic instructions
   llvm::SetVector<SpirvFunction *> functions;
-  std::string sourceFileName;
-  std::string sourceFileContent;
 };
 
 } // end namespace spirv

+ 60 - 3
tools/clang/lib/SPIRV/EmitVisitor.cpp

@@ -19,6 +19,32 @@
 
 namespace {
 
+/// Chops the given original string into multiple smaller ones to make sure they
+/// can be encoded in a sequence of OpSourceContinued instructions following an
+/// OpSource instruction.
+void chopString(llvm::StringRef original,
+                llvm::SmallVectorImpl<llvm::StringRef> *chopped) {
+  const uint32_t maxCharInOpSource = 0xFFFFu - 5u; // Minus operands and nul
+  const uint32_t maxCharInContinue = 0xFFFFu - 2u; // Minus opcode and nul
+
+  chopped->clear();
+  if (original.size() > maxCharInOpSource) {
+    chopped->push_back(llvm::StringRef(original.data(), maxCharInOpSource));
+    original = llvm::StringRef(original.data() + maxCharInOpSource,
+                               original.size() - maxCharInOpSource);
+    while (original.size() > maxCharInContinue) {
+      chopped->push_back(llvm::StringRef(original.data(), maxCharInContinue));
+      original = llvm::StringRef(original.data() + maxCharInContinue,
+                                 original.size() - maxCharInContinue);
+    }
+    if (!original.empty()) {
+      chopped->push_back(original);
+    }
+  } else if (!original.empty()) {
+    chopped->push_back(original);
+  }
+}
+
 constexpr uint32_t kGeneratorNumber = 14;
 constexpr uint32_t kToolVersion = 0;
 
@@ -315,20 +341,51 @@ bool EmitVisitor::visit(SpirvString *inst) {
 }
 
 bool EmitVisitor::visit(SpirvSource *inst) {
+  // Emit the OpString for the file name.
+  if (inst->hasFile())
+    visit(inst->getFile());
+
+  // Chop up the source into multiple segments if it is too long.
+  llvm::Optional<llvm::StringRef> firstSnippet = llvm::None;
+  llvm::SmallVector<llvm::StringRef, 2> choppedSrcCode;
+  if (!inst->getSource().empty()) {
+    chopString(inst->getSource(), &choppedSrcCode);
+    if (!choppedSrcCode.empty()) {
+      firstSnippet = llvm::Optional<llvm::StringRef>(choppedSrcCode.front());
+    }
+  }
+
   initInstruction(inst);
   curInst.push_back(static_cast<uint32_t>(inst->getSourceLanguage()));
   curInst.push_back(static_cast<uint32_t>(inst->getVersion()));
-  if (inst->hasFile())
+  if (inst->hasFile()) {
     curInst.push_back(getResultId<SpirvInstruction>(inst->getFile()));
-  if (!inst->getSource().empty()) {
+  }
+  if (firstSnippet.hasValue()) {
+    // Note: in order to improve performance and avoid multiple copies, we
+    // encode this (potentially large) string directly into the debugBinary.
+    const auto &words = string::encodeSPIRVString(firstSnippet.getValue());
+    const auto numWordsInInstr = curInst.size() + words.size();
+    curInst[0] |= static_cast<uint32_t>(numWordsInInstr) << 16;
+    debugBinary.insert(debugBinary.end(), curInst.begin(), curInst.end());
+    debugBinary.insert(debugBinary.end(), words.begin(), words.end());
+  } else {
+    curInst[0] |= static_cast<uint32_t>(curInst.size()) << 16;
+    debugBinary.insert(debugBinary.end(), curInst.begin(), curInst.end());
+  }
+
+  // Now emit OpSourceContinued for the [second:last] snippet.
+  for (uint32_t i = 1; i < choppedSrcCode.size(); ++i) {
+    initInstruction(spv::Op::OpSourceContinued);
     // Note: in order to improve performance and avoid multiple copies, we
     // encode this (potentially large) string directly into the debugBinary.
-    const auto &words = string::encodeSPIRVString(inst->getSource());
+    const auto &words = string::encodeSPIRVString(choppedSrcCode[i]);
     const auto numWordsInInstr = curInst.size() + words.size();
     curInst[0] |= static_cast<uint32_t>(numWordsInInstr) << 16;
     debugBinary.insert(debugBinary.end(), curInst.begin(), curInst.end());
     debugBinary.insert(debugBinary.end(), words.begin(), words.end());
   }
+
   return true;
 }
 

+ 12 - 14
tools/clang/lib/SPIRV/SPIRVEmitter.cpp

@@ -641,23 +641,24 @@ SPIRVEmitter::SPIRVEmitter(CompilerInstance &ci)
     spirvOptions.sBufferLayoutRule = SpirvLayoutRule::RelaxedGLSLStd430;
   }
 
-  // Set shader module version
-  spvBuilder.setShaderModelVersion(shaderModel.GetMajor(),
-                                   shaderModel.GetMinor());
-
-  // Set debug info
+  // Set shader module version, source file name, and source file content (if
+  // needed).
+  llvm::StringRef source = "";
+  llvm::StringRef fileName = "";
   const auto &inputFiles = ci.getFrontendOpts().Inputs;
+  // File name
   if (spirvOptions.debugInfoFile && !inputFiles.empty()) {
-    // File name
-    spvBuilder.setSourceFileName(inputFiles.front().getFile().str());
-
-    // Source code
+    fileName = inputFiles.front().getFile();
+  }
+  // Source code
+  if (spirvOptions.debugInfoSource) {
     const auto &sm = ci.getSourceManager();
     const llvm::MemoryBuffer *mainFile =
         sm.getBuffer(sm.getMainFileID(), SourceLocation());
-    spvBuilder.setSourceFileContent(
-        StringRef(mainFile->getBufferStart(), mainFile->getBufferSize()));
+    source = StringRef(mainFile->getBufferStart(), mainFile->getBufferSize());
   }
+  spvBuilder.setDebugSource(shaderModel.GetMajor(), shaderModel.GetMinor(),
+                            fileName, source);
 }
 
 void SPIRVEmitter::HandleTranslationUnit(ASTContext &context) {
@@ -3025,7 +3026,6 @@ SPIRVEmitter::processBufferTextureGetDimensions(const CXXMemberCallExpr *expr) {
   return nullptr;
 }
 
-// ehsan was here.
 SpirvInstruction *
 SPIRVEmitter::processTextureLevelOfDetail(const CXXMemberCallExpr *expr,
                                           bool unclamped) {
@@ -6397,7 +6397,6 @@ SpirvInstruction *SPIRVEmitter::castToFloat(SpirvInstruction *fromVal,
   return nullptr;
 }
 
-// ehsan was here.
 SpirvInstruction *
 SPIRVEmitter::processIntrinsicCallExpr(const CallExpr *callExpr) {
   const FunctionDecl *callee = callExpr->getDirectCallee();
@@ -9650,7 +9649,6 @@ bool SPIRVEmitter::processHSEntryPointOutputAndPCF(
   // entry point, create a temporary function-scope variable and write the
   // results to it, so it can be passed to the PCF.
   if (patchConstFuncTakesHullOutputPatch(patchConstFunc)) {
-    // ehsan was here.
     const QualType hullMainRetType = astContext.getConstantArrayType(
         retType, llvm::APInt(32, numOutputControlPoints),
         clang::ArrayType::Normal, 0);

+ 9 - 4
tools/clang/lib/SPIRV/SpirvModule.cpp

@@ -14,10 +14,10 @@ namespace clang {
 namespace spirv {
 
 SpirvModule::SpirvModule()
-    : bound(0), shaderModelVersion(0), capabilities({}), extensions({}),
-      extInstSets({}), memoryModel(nullptr), entryPoints({}),
-      executionModes({}), debugSource(nullptr), decorations({}), constants({}),
-      variables({}), functions({}), sourceFileName(""), sourceFileContent("") {}
+    : bound(0), capabilities({}), extensions({}), extInstSets({}),
+      memoryModel(nullptr), entryPoints({}), executionModes({}),
+      debugSource(nullptr), decorations({}), constants({}), variables({}),
+      functions({}) {}
 
 bool SpirvModule::invokeVisitor(Visitor *visitor) {
   if (!visitor->visit(this, Visitor::Phase::Init))
@@ -136,5 +136,10 @@ void SpirvModule::addConstant(SpirvConstant *constant) {
   constants.push_back(constant);
 }
 
+void SpirvModule::addDebugSource(SpirvSource *src) {
+  assert(src);
+  debugSource = src;
+}
+
 } // end namespace spirv
 } // end namespace clang