ソースを参照

[spirv] more line info (#2279)

Emit line info using `OpLine`.
Jaebaek Seo 6 年 前
コミット
6c4afcc184

+ 11 - 10
tools/clang/include/clang/SPIRV/SpirvBuilder.h

@@ -180,12 +180,13 @@ public:
   /// the instruction pointer for the result.
   SpirvBinaryOp *createBinaryOp(spv::Op op, QualType resultType,
                                 SpirvInstruction *lhs, SpirvInstruction *rhs,
-                                SourceLocation loc = {});
+                                SourceLocation loc);
 
-  SpirvSpecConstantBinaryOp *
-  createSpecConstantBinaryOp(spv::Op op, QualType resultType,
-                             SpirvInstruction *lhs, SpirvInstruction *rhs,
-                             SourceLocation loc = {});
+  SpirvSpecConstantBinaryOp *createSpecConstantBinaryOp(spv::Op op,
+                                                        QualType resultType,
+                                                        SpirvInstruction *lhs,
+                                                        SpirvInstruction *rhs,
+                                                        SourceLocation loc);
 
   /// \brief Creates an operation with the given OpGroupNonUniform* SPIR-V
   /// opcode.
@@ -257,7 +258,7 @@ public:
                     SpirvInstruction *constOffset, SpirvInstruction *varOffset,
                     SpirvInstruction *constOffsets, SpirvInstruction *sample,
                     SpirvInstruction *minLod, SpirvInstruction *residencyCodeId,
-                    SourceLocation loc = {});
+                    SourceLocation loc);
 
   /// \brief Creates SPIR-V instructions for reading a texel from an image. If
   /// doImageFetch is true, OpImageFetch is used. OpImageRead is used otherwise.
@@ -273,12 +274,12 @@ public:
       SpirvInstruction *lod, SpirvInstruction *constOffset,
       SpirvInstruction *varOffset, SpirvInstruction *constOffsets,
       SpirvInstruction *sample, SpirvInstruction *residencyCode,
-      SourceLocation loc = {});
+      SourceLocation loc);
 
   /// \brief Creates SPIR-V instructions for writing to the given image.
   void createImageWrite(QualType imageType, SpirvInstruction *image,
                         SpirvInstruction *coord, SpirvInstruction *texel,
-                        SourceLocation loc = {});
+                        SourceLocation loc);
 
   /// \brief Creates SPIR-V instructions for gathering the given image.
   ///
@@ -444,7 +445,7 @@ public:
   /// constructed in this method.
   SpirvVariable *addStageIOVar(QualType type, spv::StorageClass storageClass,
                                std::string name, bool isPrecise,
-                               SourceLocation loc = {});
+                               SourceLocation loc);
 
   /// \brief Adds a stage builtin variable whose value is of the given type.
   ///
@@ -453,7 +454,7 @@ public:
   SpirvVariable *addStageBuiltinVar(QualType type,
                                     spv::StorageClass storageClass,
                                     spv::BuiltIn, bool isPrecise,
-                                    SourceLocation loc = {});
+                                    SourceLocation loc);
 
   /// \brief Adds a module variable. This variable should not have the Function
   /// storage class.

+ 16 - 16
tools/clang/lib/SPIRV/DeclResultIdMapper.cpp

@@ -1878,9 +1878,8 @@ bool DeclResultIdMapper::createStageVars(
             astContext.UnsignedIntTy, llvm::APInt(32, 1));
         const auto constZero = spvBuilder.getConstantInt(
             astContext.UnsignedIntTy, llvm::APInt(32, 0));
-        *value =
-            spvBuilder.createSelect(astContext.UnsignedIntTy, *value, constOne,
-                                    constZero, /*SourceLocation*/ {});
+        *value = spvBuilder.createSelect(astContext.UnsignedIntTy, *value,
+                                         constOne, constZero, thisSemantic.loc);
       }
       // Special handling of SV_Barycentrics, which is a float3, but the
       // underlying stage input variable is a float2 (only provides the first
@@ -1890,13 +1889,13 @@ bool DeclResultIdMapper::createStageVars(
             astContext.FloatTy, *value, {0}, thisSemantic.loc);
         const auto y = spvBuilder.createCompositeExtract(
             astContext.FloatTy, *value, {1}, thisSemantic.loc);
-        const auto xy = spvBuilder.createBinaryOp(spv::Op::OpFAdd,
-                                                  astContext.FloatTy, x, y);
+        const auto xy = spvBuilder.createBinaryOp(
+            spv::Op::OpFAdd, astContext.FloatTy, x, y, thisSemantic.loc);
         const auto z = spvBuilder.createBinaryOp(
             spv::Op::OpFSub, astContext.FloatTy,
             spvBuilder.getConstantFloat(astContext.FloatTy,
                                         llvm::APFloat(1.0f)),
-            xy);
+            xy, thisSemantic.loc);
         *value = spvBuilder.createCompositeConstruct(
             astContext.getExtVectorType(astContext.FloatTy, 3), {x, y, z},
             thisSemantic.loc);
@@ -1937,8 +1936,9 @@ bool DeclResultIdMapper::createStageVars(
         *value = spvBuilder.createBinaryOp(
             spv::Op::OpBitwiseOr, astContext.UnsignedIntTy,
             spvBuilder.createBinaryOp(spv::Op::OpShiftLeftLogical,
-                                      astContext.IntTy, x, constTwo),
-            y, /* SourceLocation */ {});
+                                      astContext.IntTy, x, constTwo,
+                                      thisSemantic.loc),
+            y, thisSemantic.loc);
       }
 
       // Reciprocate SV_Position.w if requested
@@ -2285,7 +2285,7 @@ DeclResultIdMapper::invertWIfRequested(SpirvInstruction *position,
     const auto newW = spvBuilder.createBinaryOp(
         spv::Op::OpFDiv, astContext.FloatTy,
         spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(1.0f)),
-        oldW);
+        oldW, loc);
     position = spvBuilder.createCompositeInsert(
         astContext.getExtVectorType(astContext.FloatTy, 4), position, {3}, newW,
         loc);
@@ -2427,7 +2427,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     case hlsl::SigPoint::Kind::VSIn:
     case hlsl::SigPoint::Kind::PCOut:
     case hlsl::SigPoint::Kind::DSIn:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     case hlsl::SigPoint::Kind::VSOut:
     case hlsl::SigPoint::Kind::HSCPIn:
     case hlsl::SigPoint::Kind::HSCPOut:
@@ -2472,7 +2472,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     case hlsl::SigPoint::Kind::GSVIn:
     case hlsl::SigPoint::Kind::GSOut:
     case hlsl::SigPoint::Kind::PSIn:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     default:
       llvm_unreachable("invalid usage of SV_InstanceID sneaked in");
     }
@@ -2506,7 +2506,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     case hlsl::SigPoint::Kind::VSIn:
     case hlsl::SigPoint::Kind::PCOut:
     case hlsl::SigPoint::Kind::DSIn:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     case hlsl::SigPoint::Kind::VSOut:
     case hlsl::SigPoint::Kind::HSCPIn:
     case hlsl::SigPoint::Kind::HSCPOut:
@@ -2527,7 +2527,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
   case hlsl::Semantic::Kind::IsFrontFace: {
     switch (sigPointKind) {
     case hlsl::SigPoint::Kind::GSOut:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     case hlsl::SigPoint::Kind::PSIn:
       stageVar->setIsSpirvBuiltin();
       return spvBuilder.addStageBuiltinVar(type, sc, BuiltIn::FrontFacing,
@@ -2543,7 +2543,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
   // An arbitrary semantic is defined by users. Generate normal Vulkan stage
   // input/output variables.
   case hlsl::Semantic::Kind::Arbitrary: {
-    return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+    return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     // TODO: patch constant function in hull shader
   }
   // According to DXIL spec, the DispatchThreadID SV can only be used by CSIn.
@@ -2678,7 +2678,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     case hlsl::SigPoint::Kind::DSIn:
     case hlsl::SigPoint::Kind::DSCPIn:
     case hlsl::SigPoint::Kind::GSVIn:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     case hlsl::SigPoint::Kind::VSOut:
     case hlsl::SigPoint::Kind::DSOut:
       stageVar->setIsSpirvBuiltin();
@@ -2706,7 +2706,7 @@ SpirvVariable *DeclResultIdMapper::createSpirvStageVar(
     case hlsl::SigPoint::Kind::DSIn:
     case hlsl::SigPoint::Kind::DSCPIn:
     case hlsl::SigPoint::Kind::GSVIn:
-      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise);
+      return spvBuilder.addStageIOVar(type, sc, name.str(), isPrecise, srcLoc);
     case hlsl::SigPoint::Kind::VSOut:
     case hlsl::SigPoint::Kind::DSOut:
       stageVar->setIsSpirvBuiltin();

+ 0 - 1
tools/clang/lib/SPIRV/EmitVisitor.cpp

@@ -74,7 +74,6 @@ bool isOpLineLegalForOp(spv::Op op) {
   case spv::Op::OpDecorationGroup:
   case spv::Op::OpDecorateStringGOOGLE:
   case spv::Op::OpMemberDecorateStringGOOGLE:
-    // Annotation binary
     return false;
   default:
     return true;

+ 1 - 1
tools/clang/lib/SPIRV/GlPerVertex.cpp

@@ -342,7 +342,7 @@ SpirvVariable *GlPerVertex::createClipCullDistanceVar(bool asInput, bool isClip,
   SpirvVariable *var = spvBuilder.addStageBuiltinVar(
       type, sc,
       isClip ? spv::BuiltIn::ClipDistance : spv::BuiltIn::CullDistance,
-      isPrecise);
+      isPrecise, /*SourceLocation*/ {});
 
   const auto index = isClip ? gClipDistanceIndex : gCullDistanceIndex;
   spvBuilder.decorateHlslSemantic(var, asInput ? inSemanticStrs[index]

+ 10 - 4
tools/clang/lib/SPIRV/InitListHandler.cpp

@@ -81,10 +81,16 @@ void InitListHandler::flatten(const InitListExpr *expr) {
   }
 }
 
-void InitListHandler::decompose(SpirvInstruction *inst) {
+// Note that we cannot use inst->getSourceLocation() for OpCompositeExtract.
+// For example, float3(sign(v4f.xyz - 2 * v4f.xyz)) is InitListExpr and the
+// result of "sign(v4f.xyz - 2 * v4f.xyz)" has its location as the start
+// location of "v4f.xyz". When InitListHandler::decompose() handles inst
+// for "sign(v4f.xyz - 2 * v4f.xyz)", inst->getSourceLocation() is the location
+// of "v4f.xyz". However, we must use the start location of "sign(" for
+// OpCompositeExtract.
+void InitListHandler::decompose(SpirvInstruction *inst,
+                                const SourceLocation &loc) {
   const QualType type = inst->getAstResultType();
-  auto loc = inst->getSourceLocation();
-
   QualType elemType = {};
   uint32_t elemCount = 0, rowCount = 0, colCount = 0;
 
@@ -245,7 +251,7 @@ InitListHandler::createInitForBuiltinType(QualType type,
   initializers.pop_back();
 
   if (!init->getAstResultType()->isBuiltinType()) {
-    decompose(init);
+    decompose(init, srcLoc);
     return createInitForBuiltinType(type, srcLoc);
   }
 

+ 1 - 1
tools/clang/lib/SPIRV/InitListHandler.h

@@ -111,7 +111,7 @@ private:
 
   /// Decomposes the given SpirvInstruction and puts all elements into the end
   /// of the scalars queue.
-  void decompose(SpirvInstruction *inst);
+  void decompose(SpirvInstruction *inst, const SourceLocation &loc);
 
   /// If the next initializer is a struct, replaces it with OpCompositeExtract
   /// its members and returns true. Otherwise, does nothing and return false.

+ 166 - 155
tools/clang/lib/SPIRV/SpirvEmitter.cpp

@@ -1037,7 +1037,7 @@ void SpirvEmitter::doFunctionDecl(const FunctionDecl *decl) {
     // Remember the parameter for the 'this' object so later we can handle
     // CXXThisExpr correctly.
     curThis = spvBuilder.addFnParam(paramTypes[0], /*isPrecise*/ false,
-                                    /*SourceLocation*/ {}, "param.this");
+                                    decl->getLocStart(), "param.this");
     if (isOrContainsAKindOfStructuredOrByteBuffer(paramTypes[0])) {
       curThis->setContainsAliasComponent(true);
       needsLegalization = true;
@@ -1441,7 +1441,8 @@ void SpirvEmitter::doDoStmt(const DoStmt *theDoStmt,
   // The header block must always branch to the body.
   spvBuilder.setInsertPoint(headerBB);
   const Stmt *body = theDoStmt->getBody();
-  spvBuilder.createBranch(bodyBB, body ? body->getLocStart() : SourceLocation(),
+  spvBuilder.createBranch(bodyBB,
+                          body ? body->getLocStart() : theDoStmt->getLocStart(),
                           mergeBB, continueBB, loopControl);
   spvBuilder.addSuccessor(bodyBB);
   // The current basic block has OpLoopMerge instruction. We need to set its
@@ -1455,8 +1456,8 @@ void SpirvEmitter::doDoStmt(const DoStmt *theDoStmt,
     doStmt(body);
   }
   if (!spvBuilder.isCurrentBasicBlockTerminated()) {
-    spvBuilder.createBranch(continueBB,
-                            body ? body->getLocEnd() : SourceLocation());
+    spvBuilder.createBranch(continueBB, body ? body->getLocEnd()
+                                             : theDoStmt->getLocStart());
   }
   spvBuilder.addSuccessor(continueBB);
 
@@ -1575,8 +1576,7 @@ void SpirvEmitter::doWhileStmt(const WhileStmt *whileStmt,
   }
   spvBuilder.createConditionalBranch(
       condition, bodyBB,
-      /*false branch*/ mergeBB,
-      check ? check->getLocEnd() : whileStmt->getLocStart(),
+      /*false branch*/ mergeBB, whileStmt->getLocStart(),
       /*merge*/ mergeBB, continueBB, spv::SelectionControlMask::MaskNone,
       loopControl);
   spvBuilder.addSuccessor(bodyBB);
@@ -1593,8 +1593,7 @@ void SpirvEmitter::doWhileStmt(const WhileStmt *whileStmt,
     doStmt(body);
   }
   if (!spvBuilder.isCurrentBasicBlockTerminated())
-    spvBuilder.createBranch(continueBB,
-                            body ? body->getLocEnd() : SourceLocation());
+    spvBuilder.createBranch(continueBB, whileStmt->getLocEnd());
   spvBuilder.addSuccessor(continueBB);
 
   // Process the <continue> block. While loops do not have an explicit
@@ -1666,8 +1665,8 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
     doStmt(initStmt);
   }
   const Expr *check = forStmt->getCond();
-  spvBuilder.createBranch(checkBB,
-                          check ? check->getLocStart() : SourceLocation());
+  spvBuilder.createBranch(checkBB, check ? check->getLocStart()
+                                         : forStmt->getLocStart());
   spvBuilder.addSuccessor(checkBB);
 
   // Process the <check> block
@@ -1683,7 +1682,7 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
       condition, bodyBB,
       /*false branch*/ mergeBB,
       check ? check->getLocEnd()
-            : (body ? body->getLocStart() : SourceLocation()),
+            : (body ? body->getLocStart() : forStmt->getLocStart()),
       /*merge*/ mergeBB, continueBB, spv::SelectionControlMask::MaskNone,
       loopControl);
   spvBuilder.addSuccessor(bodyBB);
@@ -1699,8 +1698,7 @@ void SpirvEmitter::doForStmt(const ForStmt *forStmt,
     doStmt(body);
   }
   if (!spvBuilder.isCurrentBasicBlockTerminated())
-    spvBuilder.createBranch(continueBB,
-                            body ? body->getLocEnd() : SourceLocation());
+    spvBuilder.createBranch(continueBB, forStmt->getLocEnd());
   spvBuilder.addSuccessor(continueBB);
 
   // Process the <continue> block
@@ -2124,8 +2122,8 @@ SpirvInstruction *SpirvEmitter::processCall(const CallExpr *callExpr) {
       // do not need to mark the "param.var.*" variables as precise.
       const bool isPrecise = false;
 
-      auto *tempVar = spvBuilder.addFnVar(varType, param->getLocation(),
-                                          varName, isPrecise);
+      auto *tempVar =
+          spvBuilder.addFnVar(varType, arg->getLocStart(), varName, isPrecise);
 
       vars.push_back(tempVar);
       isTempVar.push_back(true);
@@ -2235,7 +2233,7 @@ SpirvInstruction *SpirvEmitter::doCastExpr(const CastExpr *expr) {
     }
 
     auto *value = castToInt(loadIfGLValue(subExpr), subExprType, toType,
-                            subExpr->getExprLoc());
+                            subExpr->getLocStart());
     value->setRValue();
     return value;
   }
@@ -2251,7 +2249,7 @@ SpirvInstruction *SpirvEmitter::doCastExpr(const CastExpr *expr) {
     }
 
     auto *value = castToFloat(loadIfGLValue(subExpr), subExprType, toType,
-                              subExpr->getExprLoc());
+                              subExpr->getLocStart());
     value->setRValue();
     return value;
   }
@@ -2725,8 +2723,7 @@ SpirvEmitter::doConditionalOperator(const ConditionalOperator *expr) {
   }
 
   // If we can't use OpSelect, we need to create if-else control flow.
-  auto *tempVar =
-      spvBuilder.addFnVar(type, /*SourceLocation*/ {}, "temp.var.ternary");
+  auto *tempVar = spvBuilder.addFnVar(type, loc, "temp.var.ternary");
   auto *thenBB = spvBuilder.createBasicBlock("if.true");
   auto *mergeBB = spvBuilder.createBasicBlock("if.merge");
   auto *elseBB = spvBuilder.createBasicBlock("if.false");
@@ -2779,8 +2776,10 @@ SpirvEmitter::processByteAddressBufferStructuredBufferGetDimensions(
   if (isBABuf) {
     length = spvBuilder.createBinaryOp(
         spv::Op::OpIMul, astContext.UnsignedIntTy, length,
+        // TODO(jaebaek): What line info we should emit for constants?
         spvBuilder.getConstantInt(astContext.UnsignedIntTy,
-                                  llvm::APInt(32, 4u)));
+                                  llvm::APInt(32, 4u)),
+        expr->getExprLoc());
   }
   spvBuilder.createStore(doExpr(expr->getArg(0)), length,
                          expr->getArg(0)->getLocStart());
@@ -2818,7 +2817,8 @@ SpirvInstruction *SpirvEmitter::processRWByteAddressBufferAtomicMethods(
   // Right shift by 2 to convert the byte offset to uint32_t offset
   auto *address = spvBuilder.createBinaryOp(
       spv::Op::OpShiftRightLogical, astContext.UnsignedIntTy, offset,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 2)));
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 2)),
+      expr->getExprLoc());
   auto *ptr =
       spvBuilder.createAccessChain(astContext.UnsignedIntTy, objectInfo,
                                    {zero, address}, object->getLocStart());
@@ -2883,7 +2883,7 @@ SpirvEmitter::processSubpassLoad(const CXXMemberCallExpr *expr) {
 
   return processBufferTextureLoad(object, location, /*constOffset*/ 0,
                                   /*varOffset*/ 0, /*lod*/ sample,
-                                  /*residencyCode*/ 0);
+                                  /*residencyCode*/ 0, expr->getExprLoc());
 }
 
 SpirvInstruction *
@@ -3213,7 +3213,8 @@ SpirvEmitter::processTextureGatherCmp(const CXXMemberCallExpr *expr) {
 SpirvInstruction *SpirvEmitter::processBufferTextureLoad(
     const Expr *object, SpirvInstruction *location,
     SpirvInstruction *constOffset, SpirvInstruction *varOffset,
-    SpirvInstruction *lod, SpirvInstruction *residencyCode) {
+    SpirvInstruction *lod, SpirvInstruction *residencyCode,
+    SourceLocation loc) {
   // Loading for Buffer and RWBuffer translates to an OpImageFetch.
   // The result type of an OpImageFetch must be a vec4 of float or int.
   const auto type = object->getType();
@@ -3258,16 +3259,14 @@ SpirvInstruction *SpirvEmitter::processBufferTextureLoad(
   const QualType texelType = astContext.getExtVectorType(elemType, 4u);
   auto *texel = spvBuilder.createImageFetchOrRead(
       doFetch, texelType, type, objectInfo, location, lod, constOffset,
-      varOffset, /*constOffsets*/ nullptr, sampleNumber, residencyCode);
+      varOffset, /*constOffsets*/ nullptr, sampleNumber, residencyCode, loc);
 
   // If the result type is a vec1, vec2, or vec3, some extra processing
   // (extraction) is required.
-  auto *retVal =
-      extractVecFromVec4(texel, elemCount, elemType, object->getLocStart());
+  auto *retVal = extractVecFromVec4(texel, elemCount, elemType, loc);
   if (isTemplateOverStruct) {
     // Convert to the struct so that we are consistent with types in the AST.
-    retVal = convertVectorToStruct(sampledType, elemType, retVal,
-                                   object->getLocStart());
+    retVal = convertVectorToStruct(sampledType, elemType, retVal, loc);
   }
   retVal->setRValue();
   return retVal;
@@ -3301,8 +3300,9 @@ SpirvInstruction *SpirvEmitter::processByteAddressBufferLoadStore(
   // by unsinged integer 2.
   auto *constUint2 =
       spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 2));
-  auto *address = spvBuilder.createBinaryOp(
-      spv::Op::OpShiftRightLogical, addressType, byteAddress, constUint2);
+  auto *address =
+      spvBuilder.createBinaryOp(spv::Op::OpShiftRightLogical, addressType,
+                                byteAddress, constUint2, expr->getExprLoc());
 
   // Perform access chain into the RWByteAddressBuffer.
   // First index must be zero (member 0 of the struct is a
@@ -3437,7 +3437,7 @@ SpirvEmitter::incDecRWACSBufferCounter(const CXXMemberCallExpr *expr,
         spv::Op::OpAtomicISub, astContext.IntTy, counterPtr, spv::Scope::Device,
         spv::MemorySemanticsMask::MaskNone, sOne, srcLoc);
     index = spvBuilder.createBinaryOp(spv::Op::OpISub, astContext.IntTy, prev,
-                                      sOne);
+                                      sOne, srcLoc);
   }
 
   return index;
@@ -3734,7 +3734,7 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
 
     const std::string varName =
         "var.GetSamplePosition.data." + std::to_string(len);
-    auto *var = spvBuilder.addFnVar(arrType, /*SourceLocation*/ {}, varName);
+    auto *var = spvBuilder.addFnVar(arrType, loc, varName);
     spvBuilder.createStore(var, val, loc);
     return var;
   };
@@ -3744,8 +3744,8 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
   auto *pos8Arr = createArray(pos8, 8);
   auto *pos16Arr = createArray(pos16, 16);
 
-  auto *resultVar = spvBuilder.addFnVar(v2f32Type, /*SourceLocation*/ {},
-                                        "var.GetSamplePosition.result");
+  auto *resultVar =
+      spvBuilder.addFnVar(v2f32Type, loc, "var.GetSamplePosition.result");
 
   auto *then2BB = spvBuilder.createBasicBlock("if.GetSamplePosition.then2");
   auto *then4BB = spvBuilder.createBasicBlock("if.GetSamplePosition.then4");
@@ -3765,9 +3765,9 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
   //   if (count == 2) {
   const auto check2 = spvBuilder.createBinaryOp(
       spv::Op::OpIEqual, astContext.BoolTy, sampleCount,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 2)));
-  spvBuilder.createConditionalBranch(check2, then2BB, else2BB,
-                                     /*SourceLocation*/ {}, merge2BB);
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 2)),
+      loc);
+  spvBuilder.createConditionalBranch(check2, then2BB, else2BB, loc, merge2BB);
   spvBuilder.addSuccessor(then2BB);
   spvBuilder.addSuccessor(else2BB);
   spvBuilder.setMergeTarget(merge2BB);
@@ -3779,16 +3779,16 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
       spvBuilder.createAccessChain(v2f32Type, pos2Arr, {sampleIndex}, loc);
   spvBuilder.createStore(resultVar, spvBuilder.createLoad(v2f32Type, ac, loc),
                          loc);
-  spvBuilder.createBranch(merge2BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge2BB, loc);
   spvBuilder.addSuccessor(merge2BB);
 
   //   else if (count == 4) {
   spvBuilder.setInsertPoint(else2BB);
   const auto check4 = spvBuilder.createBinaryOp(
       spv::Op::OpIEqual, astContext.BoolTy, sampleCount,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 4)));
-  spvBuilder.createConditionalBranch(check4, then4BB, else4BB,
-                                     /*SourceLocation*/ {}, merge4BB);
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 4)),
+      loc);
+  spvBuilder.createConditionalBranch(check4, then4BB, else4BB, loc, merge4BB);
   spvBuilder.addSuccessor(then4BB);
   spvBuilder.addSuccessor(else4BB);
   spvBuilder.setMergeTarget(merge4BB);
@@ -3799,16 +3799,16 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
   ac = spvBuilder.createAccessChain(v2f32Type, pos4Arr, {sampleIndex}, loc);
   spvBuilder.createStore(resultVar, spvBuilder.createLoad(v2f32Type, ac, loc),
                          loc);
-  spvBuilder.createBranch(merge4BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge4BB, loc);
   spvBuilder.addSuccessor(merge4BB);
 
   //   else if (count == 8) {
   spvBuilder.setInsertPoint(else4BB);
   const auto check8 = spvBuilder.createBinaryOp(
       spv::Op::OpIEqual, astContext.BoolTy, sampleCount,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 8)));
-  spvBuilder.createConditionalBranch(check8, then8BB, else8BB,
-                                     /*SourceLocation*/ {}, merge8BB);
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 8)),
+      loc);
+  spvBuilder.createConditionalBranch(check8, then8BB, else8BB, loc, merge8BB);
   spvBuilder.addSuccessor(then8BB);
   spvBuilder.addSuccessor(else8BB);
   spvBuilder.setMergeTarget(merge8BB);
@@ -3819,16 +3819,17 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
   ac = spvBuilder.createAccessChain(v2f32Type, pos8Arr, {sampleIndex}, loc);
   spvBuilder.createStore(resultVar, spvBuilder.createLoad(v2f32Type, ac, loc),
                          loc);
-  spvBuilder.createBranch(merge8BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge8BB, loc);
   spvBuilder.addSuccessor(merge8BB);
 
   //   else if (count == 16) {
   spvBuilder.setInsertPoint(else8BB);
   const auto check16 = spvBuilder.createBinaryOp(
       spv::Op::OpIEqual, astContext.BoolTy, sampleCount,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 16)));
-  spvBuilder.createConditionalBranch(check16, then16BB, else16BB,
-                                     /*SourceLocation*/ {}, merge16BB);
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 16)),
+      loc);
+  spvBuilder.createConditionalBranch(check16, then16BB, else16BB, loc,
+                                     merge16BB);
   spvBuilder.addSuccessor(then16BB);
   spvBuilder.addSuccessor(else16BB);
   spvBuilder.setMergeTarget(merge16BB);
@@ -3839,7 +3840,7 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
   ac = spvBuilder.createAccessChain(v2f32Type, pos16Arr, {sampleIndex}, loc);
   spvBuilder.createStore(resultVar, spvBuilder.createLoad(v2f32Type, ac, loc),
                          loc);
-  spvBuilder.createBranch(merge16BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge16BB, loc);
   spvBuilder.addSuccessor(merge16BB);
 
   //   else {
@@ -3850,19 +3851,19 @@ SpirvEmitter::emitGetSamplePosition(SpirvInstruction *sampleCount,
       spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(0.0f));
   auto *v2f32Zero = spvBuilder.getConstantComposite(v2f32Type, {zero, zero});
   spvBuilder.createStore(resultVar, v2f32Zero, loc);
-  spvBuilder.createBranch(merge16BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge16BB, loc);
   spvBuilder.addSuccessor(merge16BB);
 
   spvBuilder.setInsertPoint(merge16BB);
-  spvBuilder.createBranch(merge8BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge8BB, loc);
   spvBuilder.addSuccessor(merge8BB);
 
   spvBuilder.setInsertPoint(merge8BB);
-  spvBuilder.createBranch(merge4BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge4BB, loc);
   spvBuilder.addSuccessor(merge4BB);
 
   spvBuilder.setInsertPoint(merge4BB);
-  spvBuilder.createBranch(merge2BB, /*SourceLocation*/ {});
+  spvBuilder.createBranch(merge2BB, loc);
   spvBuilder.addSuccessor(merge2BB);
 
   spvBuilder.setInsertPoint(merge2BB);
@@ -4046,7 +4047,7 @@ SpirvInstruction *SpirvEmitter::createImageSample(
     return spvBuilder.createImageSample(retType, imageType, image, sampler,
                                         coordinate, compareVal, bias, lod, grad,
                                         constOffset, varOffset, constOffsets,
-                                        sample, minLod, residencyCodeId);
+                                        sample, minLod, residencyCodeId, loc);
   }
 
   // Non-Dref Sample instructions in SPIR-V must always return a vec4.
@@ -4072,7 +4073,7 @@ SpirvInstruction *SpirvEmitter::createImageSample(
   auto *retVal = spvBuilder.createImageSample(
       texelType, imageType, image, sampler, coordinate, compareVal, bias, lod,
       grad, constOffset, varOffset, constOffsets, sample, minLod,
-      residencyCodeId);
+      residencyCodeId, loc);
 
   // Extract smaller vector from the vec4 result if necessary.
   if (texelType != retType) {
@@ -4434,11 +4435,12 @@ SpirvEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
       expr->getArg(numArgs - 1)->getType()->isUnsignedIntegerType();
   auto *status = hasStatusArg ? doExpr(expr->getArg(numArgs - 1)) : nullptr;
 
+  auto loc = expr->getExprLoc();
   if (isBuffer(objectType) || isRWBuffer(objectType) || isRWTexture(objectType))
     return processBufferTextureLoad(object, doExpr(locationArg),
                                     /*constOffset*/ nullptr,
                                     /*varOffset*/ nullptr, /*lod*/ nullptr,
-                                    /*residencyCode*/ status);
+                                    /*residencyCode*/ status, loc);
 
   // Subtract 1 for status (if it exists), and 1 for sampleIndex (if it exists),
   // and 1 for location.
@@ -4471,7 +4473,7 @@ SpirvEmitter::processBufferTextureLoad(const CXXMemberCallExpr *expr) {
     }
 
     return processBufferTextureLoad(object, coordinate, constOffset, varOffset,
-                                    lod, status);
+                                    lod, status, loc);
   }
   emitError("Load() of the given object type unimplemented",
             object->getExprLoc());
@@ -4513,7 +4515,8 @@ SpirvEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
                                       /*constOffset*/ nullptr,
                                       /*varOffset*/ nullptr, lod,
-                                      /*residencyCode*/ nullptr);
+                                      /*residencyCode*/ nullptr,
+                                      expr->getExprLoc());
     }
     // .mips[][] or .sample[][] must use the correct slice.
     if (isTextureMipsSampleIndexing(expr, &baseExpr, &indexExpr, &lodExpr)) {
@@ -4521,7 +4524,8 @@ SpirvEmitter::doCXXOperatorCallExpr(const CXXOperatorCallExpr *expr) {
       return processBufferTextureLoad(baseExpr, doExpr(indexExpr),
                                       /*constOffset*/ nullptr,
                                       /*varOffset*/ nullptr, lod,
-                                      /*residencyCode*/ nullptr);
+                                      /*residencyCode*/ nullptr,
+                                      expr->getExprLoc());
     }
   }
 
@@ -4773,7 +4777,7 @@ SpirvInstruction *SpirvEmitter::doUnaryOperator(const UnaryOperator *expr) {
     SpirvInstruction *originValue =
         subValue->isRValue()
             ? subValue
-            : spvBuilder.createLoad(subType, subValue, expr->getLocStart());
+            : spvBuilder.createLoad(subType, subValue, subExpr->getLocStart());
     auto *one = hlsl::IsHLSLMatType(subType) ? getMatElemValueOne(subType)
                                              : getValueOne(subType);
 
@@ -4791,7 +4795,8 @@ SpirvInstruction *SpirvEmitter::doUnaryOperator(const UnaryOperator *expr) {
       incValue = processEachVectorInMatrix(subExpr, originValue, actOnEachVec,
                                            expr->getLocStart());
     } else {
-      incValue = spvBuilder.createBinaryOp(spvOp, subType, originValue, one);
+      incValue = spvBuilder.createBinaryOp(spvOp, subType, originValue, one,
+                                           expr->getOperatorLoc());
     }
 
     // If this is a RWBuffer/RWTexture assignment, OpImageWrite will be used.
@@ -5281,9 +5286,9 @@ SpirvInstruction *SpirvEmitter::processBinaryOp(
   case BO_ShrAssign:
     // We need to cull the RHS to make sure that we are not shifting by an
     // amount that is larger than the bitwidth of the LHS.
-    rhsVal =
-        spvBuilder.createBinaryOp(spv::Op::OpBitwiseAnd, computationType,
-                                  rhsVal, getMaskForBitwidthValue(rhsType));
+    rhsVal = spvBuilder.createBinaryOp(spv::Op::OpBitwiseAnd, computationType,
+                                       rhsVal, getMaskForBitwidthValue(rhsType),
+                                       loc);
     // Fall through
   case BO_Add:
   case BO_Sub:
@@ -5317,8 +5322,8 @@ SpirvInstruction *SpirvEmitter::processBinaryOp(
         if (isAcceptedSpecConstantBinaryOp(spvOp)) {
           if (lhsValConstant->isSpecConstant() ||
               rhsValConstant->isSpecConstant()) {
-            auto *val = spvBuilder.createSpecConstantBinaryOp(spvOp, resultType,
-                                                              lhsVal, rhsVal);
+            auto *val = spvBuilder.createSpecConstantBinaryOp(
+                spvOp, resultType, lhsVal, rhsVal, loc);
             val->setRValue();
             return val;
           }
@@ -5329,14 +5334,15 @@ SpirvInstruction *SpirvEmitter::processBinaryOp(
     // Normal binary operation
     SpirvInstruction *val = nullptr;
     if (BinaryOperator::isCompoundAssignmentOp(opcode)) {
-      val = spvBuilder.createBinaryOp(spvOp, computationType, lhsVal, rhsVal);
+      val = spvBuilder.createBinaryOp(spvOp, computationType, lhsVal, rhsVal,
+                                      loc);
       // For a compound assignments, the AST does not have the proper implicit
       // cast if lhs and rhs have different types. So we need to manually cast
       // the result back to lhs' type.
       if (computationType != lhsType)
         val = castToType(val, computationType, lhsType, lhs->getExprLoc());
     } else {
-      val = spvBuilder.createBinaryOp(spvOp, resultType, lhsVal, rhsVal);
+      val = spvBuilder.createBinaryOp(spvOp, resultType, lhsVal, rhsVal, loc);
     }
 
     val->setRValue();
@@ -5579,8 +5585,8 @@ SpirvInstruction *SpirvEmitter::createVectorSplat(const Expr *scalarExpr,
     return value;
   } else {
     llvm::SmallVector<SpirvInstruction *, 4> elements(size_t(size), scalarVal);
-    auto *value = spvBuilder.createCompositeConstruct(vecType, elements,
-                                                      scalarExpr->getLocEnd());
+    auto *value = spvBuilder.createCompositeConstruct(
+        vecType, elements, scalarExpr->getLocStart());
     value->setRValue();
     return value;
   }
@@ -5892,7 +5898,7 @@ SpirvEmitter::tryToAssignToRWBufferRWTexture(const Expr *lhs,
     auto *baseInfo = doExpr(baseExpr);
     auto *image =
         spvBuilder.createLoad(imageType, baseInfo, baseExpr->getExprLoc());
-    spvBuilder.createImageWrite(imageType, image, loc, rhs);
+    spvBuilder.createImageWrite(imageType, image, loc, rhs, lhs->getExprLoc());
     return rhs;
   }
   return nullptr;
@@ -6299,7 +6305,7 @@ SpirvInstruction *SpirvEmitter::castToBool(SpirvInstruction *fromVal,
   // Converting to bool means comparing with value zero.
   const spv::Op spvOp = translateOp(BO_NE, fromType);
   auto *zeroVal = getValueZero(fromType);
-  return spvBuilder.createBinaryOp(spvOp, toBoolType, fromVal, zeroVal);
+  return spvBuilder.createBinaryOp(spvOp, toBoolType, fromVal, zeroVal, loc);
 }
 
 SpirvInstruction *SpirvEmitter::castToInt(SpirvInstruction *fromVal,
@@ -7065,10 +7071,11 @@ SpirvEmitter::processIntrinsicNonUniformResourceIndex(const CallExpr *expr) {
 
 SpirvInstruction *
 SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
+  const auto loc = callExpr->getExprLoc();
   if (!spirvOptions.noWarnEmulatedFeatures)
     emitWarning("msad4 intrinsic function is emulated using many SPIR-V "
                 "instructions due to lack of direct SPIR-V equivalent",
-                callExpr->getExprLoc());
+                loc);
 
   // Compares a 4-byte reference value and an 8-byte source value and
   // accumulates a vector of 4 sums. Each sum corresponds to the masked sum
@@ -7101,7 +7108,6 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
   auto *reference = doExpr(callExpr->getArg(0));
   auto *source = doExpr(callExpr->getArg(1));
   auto *accum = doExpr(callExpr->getArg(2));
-  const auto loc = callExpr->getExprLoc();
   const auto uint0 =
       spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 0));
   const auto uint8 =
@@ -7115,13 +7121,13 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
   auto *v1x = spvBuilder.createCompositeExtract(uintType, source, {0}, loc);
   // r0.x = v1xS8 = v1.x shifted by 8 bits
   auto *v1xS8 = spvBuilder.createBinaryOp(spv::Op::OpShiftLeftLogical, uintType,
-                                          v1x, uint8);
+                                          v1x, uint8, loc);
   // r0.y = v1xS16 = v1.x shifted by 16 bits
   auto *v1xS16 = spvBuilder.createBinaryOp(spv::Op::OpShiftLeftLogical,
-                                           uintType, v1x, uint16);
+                                           uintType, v1x, uint16, loc);
   // r0.z = v1xS24 = v1.x shifted by 24 bits
   auto *v1xS24 = spvBuilder.createBinaryOp(spv::Op::OpShiftLeftLogical,
-                                           uintType, v1x, uint24);
+                                           uintType, v1x, uint24, loc);
 
   // Step 2.
   // Do bfi 3 times. DXIL bfi is equivalent to SPIR-V OpBitFieldInsert.
@@ -7202,7 +7208,7 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
     signedRefBytes.push_back(spvBuilder.createUnaryOp(
         spv::Op::OpBitcast, intType, refBytes.back(), loc));
     isRefByteZero.push_back(spvBuilder.createBinaryOp(
-        spv::Op::OpIEqual, boolType, refBytes.back(), uint0));
+        spv::Op::OpIEqual, boolType, refBytes.back(), uint0, loc));
   }
 
   for (uint32_t msadNum = 0; msadNum < 4; ++msadNum) {
@@ -7216,8 +7222,9 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
           /*count*/ uint8, /*isSigned*/ false, loc);
       auto *signedSrcByte =
           spvBuilder.createUnaryOp(spv::Op::OpBitcast, intType, srcByte, loc);
-      auto *sub = spvBuilder.createBinaryOp(
-          spv::Op::OpISub, intType, signedRefBytes[byteCount], signedSrcByte);
+      auto *sub = spvBuilder.createBinaryOp(spv::Op::OpISub, intType,
+                                            signedRefBytes[byteCount],
+                                            signedSrcByte, loc);
       auto *absSub = spvBuilder.createExtInst(
           intType, glsl, GLSLstd450::GLSLstd450SAbs, {sub}, loc);
       auto *diff = spvBuilder.createSelect(
@@ -7229,11 +7236,10 @@ SpirvEmitter::processIntrinsicMsad4(const CallExpr *callExpr) {
       // saturate the output to UINT_MAX in case of overflow. Wrapping around is
       // also allowed. For simplicity, we will wrap around at this point.
       accums[msadNum] = spvBuilder.createBinaryOp(spv::Op::OpIAdd, uintType,
-                                                  accums[msadNum], diff);
+                                                  accums[msadNum], diff, loc);
     }
   }
-  return spvBuilder.createCompositeConstruct(uint4Type, accums,
-                                             callExpr->getLocEnd());
+  return spvBuilder.createCompositeConstruct(uint4Type, accums, loc);
 }
 
 SpirvInstruction *SpirvEmitter::processWaveQuery(const CallExpr *callExpr,
@@ -7601,9 +7607,9 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMad(const CallExpr *callExpr) {
   {
     if (isScalarType(argType) || isVectorType(argType)) {
       auto *mul = spvBuilder.createBinaryOp(spv::Op::OpIMul, argType, arg0Instr,
-                                            arg1Instr);
-      auto *add =
-          spvBuilder.createBinaryOp(spv::Op::OpIAdd, argType, mul, arg2Instr);
+                                            arg1Instr, loc);
+      auto *add = spvBuilder.createBinaryOp(spv::Op::OpIAdd, argType, mul,
+                                            arg2Instr, loc);
       spvBuilder.decorateNoContraction(mul, loc);
       spvBuilder.decorateNoContraction(add, loc);
       return add;
@@ -7625,9 +7631,9 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMad(const CallExpr *callExpr) {
         auto *rowArg2 =
             spvBuilder.createCompositeExtract(colType, arg2Instr, {i}, arg2Loc);
         auto *mul = spvBuilder.createBinaryOp(spv::Op::OpIMul, colType, rowArg0,
-                                              rowArg1);
-        auto *add =
-            spvBuilder.createBinaryOp(spv::Op::OpIAdd, colType, mul, rowArg2);
+                                              rowArg1, loc);
+        auto *add = spvBuilder.createBinaryOp(spv::Op::OpIAdd, colType, mul,
+                                              rowArg2, loc);
         spvBuilder.decorateNoContraction(mul, loc);
         spvBuilder.decorateNoContraction(add, loc);
         resultRows.push_back(add);
@@ -7667,8 +7673,9 @@ SpirvInstruction *SpirvEmitter::processIntrinsicLit(const CallExpr *callExpr) {
   auto *min = spvBuilder.createExtInst(
       floatType, glslInstSet, GLSLstd450::GLSLstd450FMin, {nDotL, nDotH}, loc);
   auto *isNeg = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolType,
-                                          min, floatZero);
-  auto *mul = spvBuilder.createBinaryOp(spv::Op::OpFMul, floatType, nDotH, m);
+                                          min, floatZero, loc);
+  auto *mul =
+      spvBuilder.createBinaryOp(spv::Op::OpFMul, floatType, nDotH, m, loc);
   auto *specular =
       spvBuilder.createSelect(floatType, isNeg, floatZero, mul, loc);
   return spvBuilder.createCompositeConstruct(
@@ -7792,8 +7799,8 @@ SpirvEmitter::processIntrinsicLdexp(const CallExpr *callExpr) {
   if (isScalarType(paramType) || isVectorType(paramType)) {
     const auto twoExp = spvBuilder.createExtInst(
         paramType, glsl, GLSLstd450::GLSLstd450Exp2, {expInstr}, loc);
-    return spvBuilder.createBinaryOp(spv::Op::OpFMul, paramType, xInstr,
-                                     twoExp);
+    return spvBuilder.createBinaryOp(spv::Op::OpFMul, paramType, xInstr, twoExp,
+                                     loc);
   }
 
   // For matrix argument types.
@@ -7834,13 +7841,14 @@ SpirvInstruction *SpirvEmitter::processIntrinsicDst(const CallExpr *callExpr) {
   auto *arg1y = spvBuilder.createCompositeExtract(f32, arg1Id, {1}, arg1Loc);
   auto *arg0z = spvBuilder.createCompositeExtract(f32, arg0Id, {2}, arg0Loc);
   auto *arg1w = spvBuilder.createCompositeExtract(f32, arg1Id, {3}, arg1Loc);
+  auto loc = callExpr->getLocEnd();
   auto *arg0yMularg1y =
-      spvBuilder.createBinaryOp(spv::Op::OpFMul, f32, arg0y, arg1y);
+      spvBuilder.createBinaryOp(spv::Op::OpFMul, f32, arg0y, arg1y, loc);
   return spvBuilder.createCompositeConstruct(
       callExpr->getType(),
       {spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(1.0f)),
        arg0yMularg1y, arg0z, arg1w},
-      callExpr->getLocEnd());
+      loc);
 }
 
 SpirvInstruction *SpirvEmitter::processIntrinsicClip(const CallExpr *callExpr) {
@@ -7866,13 +7874,13 @@ SpirvInstruction *SpirvEmitter::processIntrinsicClip(const CallExpr *callExpr) {
   if (isScalarType(argType)) {
     auto *zero = getValueZero(argType);
     condition = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolType,
-                                          argInstr, zero);
+                                          argInstr, zero, loc);
   } else if (isVectorType(argType, nullptr, &elemCount)) {
     auto *zero = getValueZero(argType);
     const QualType boolVecType =
         astContext.getExtVectorType(boolType, elemCount);
     auto *cmp = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan, boolVecType,
-                                          argInstr, zero);
+                                          argInstr, zero, loc);
     condition = spvBuilder.createUnaryOp(spv::Op::OpAny, boolType, cmp, loc);
   } else if (isMxNMatrix(argType, &elemType, &rowCount, &colCount)) {
     const auto floatVecType = astContext.getExtVectorType(elemType, colCount);
@@ -7885,7 +7893,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicClip(const CallExpr *callExpr) {
           spvBuilder.createCompositeExtract(floatVecType, argInstr, {i}, loc);
       const auto boolColType = astContext.getExtVectorType(boolType, colCount);
       auto *cmp = spvBuilder.createBinaryOp(spv::Op::OpFOrdLessThan,
-                                            boolColType, lhsVec, zero);
+                                            boolColType, lhsVec, zero, loc);
       auto *any = spvBuilder.createUnaryOp(spv::Op::OpAny, boolType, cmp, loc);
       cmpResults.push_back(any);
     }
@@ -8106,7 +8114,7 @@ SpirvInstruction *SpirvEmitter::processNonFpScalarTimesMatrix(
     auto *rowInstr =
         spvBuilder.createCompositeExtract(rowType, matrix, {row}, loc);
     mulRows.push_back(spvBuilder.createBinaryOp(
-        translateOp(BO_Mul, scalarType), rowType, rowInstr, scalarSplat));
+        translateOp(BO_Mul, scalarType), rowType, rowInstr, scalarSplat, loc));
   }
   return spvBuilder.createCompositeConstruct(matrixType, mulRows, loc);
 }
@@ -8221,6 +8229,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
   const Expr *arg1 = callExpr->getArg(1);
   const QualType arg0Type = arg0->getType();
   const QualType arg1Type = arg1->getType();
+  auto loc = callExpr->getExprLoc();
 
   // The HLSL mul() function takes 2 arguments. Each argument may be a scalar,
   // vector, or matrix. The frontend ensures that the two arguments have the
@@ -8236,12 +8245,12 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       // We can use OpVectorTimesScalar if arguments are floats.
       if (arg0Type->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpVectorTimesScalar,
-                                         returnType, arg1Id, doExpr(arg0));
+                                         returnType, arg1Id, doExpr(arg0), loc);
 
       // Use OpIMul for integers
       return spvBuilder.createBinaryOp(spv::Op::OpIMul, returnType,
                                        createVectorSplat(arg0, elemCount),
-                                       arg1Id);
+                                       arg1Id, loc);
     }
   }
 
@@ -8255,11 +8264,11 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       // We can use OpVectorTimesScalar if arguments are floats.
       if (arg1Type->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpVectorTimesScalar,
-                                         returnType, arg0Id, doExpr(arg1));
+                                         returnType, arg0Id, doExpr(arg1), loc);
 
       // Use OpIMul for integers
       return spvBuilder.createBinaryOp(spv::Op::OpIMul, returnType, arg0Id,
-                                       createVectorSplat(arg1, elemCount));
+                                       createVectorSplat(arg1, elemCount), loc);
     }
   }
 
@@ -8274,7 +8283,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
   // mul(scalar, scalar)
   if (isScalarType(arg0Type) && isScalarType(arg1Type))
     return spvBuilder.createBinaryOp(translateOp(BO_Mul, arg0Type), returnType,
-                                     arg0Id, arg1Id);
+                                     arg0Id, arg1Id, loc);
 
   // mul(scalar, matrix)
   {
@@ -8284,7 +8293,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       // and the scalar type are float.
       if (arg0Type->isFloatingType() && elemType->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpMatrixTimesScalar,
-                                         returnType, arg1Id, arg0Id);
+                                         returnType, arg1Id, arg0Id, loc);
       else
         return processNonFpScalarTimesMatrix(arg0Type, arg0Id, arg1Type, arg1Id,
                                              callExpr->getExprLoc());
@@ -8299,7 +8308,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       // and the scalar type are float.
       if (arg1Type->isFloatingType() && elemType->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpMatrixTimesScalar,
-                                         returnType, arg0Id, arg1Id);
+                                         returnType, arg0Id, arg1Id, loc);
       else
         return processNonFpScalarTimesMatrix(arg1Type, arg1Id, arg0Type, arg0Id,
                                              callExpr->getExprLoc());
@@ -8316,7 +8325,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
 
       if (vecElemType->isFloatingType() && matElemType->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpMatrixTimesVector,
-                                         returnType, arg1Id, arg0Id);
+                                         returnType, arg1Id, arg0Id, loc);
       else
         return processNonFpVectorTimesMatrix(arg0Type, arg0Id, arg1Type, arg1Id,
                                              callExpr->getExprLoc());
@@ -8332,7 +8341,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       assert(elemCount == numCols);
       if (vecElemType->isFloatingType() && matElemType->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpVectorTimesMatrix,
-                                         returnType, arg1Id, arg0Id);
+                                         returnType, arg1Id, arg0Id, loc);
       else
         return processNonFpMatrixTimesVector(arg0Type, arg0Id, arg1Type, arg1Id,
                                              callExpr->getExprLoc());
@@ -8349,7 +8358,7 @@ SpirvInstruction *SpirvEmitter::processIntrinsicMul(const CallExpr *callExpr) {
       assert(lhsCols == rhsRows);
       if (elemType->isFloatingType())
         return spvBuilder.createBinaryOp(spv::Op::OpMatrixTimesMatrix,
-                                         returnType, arg1Id, arg0Id);
+                                         returnType, arg1Id, arg0Id, loc);
       else
         return processNonFpMatrixTimesMatrix(arg0Type, arg0Id, arg1Type, arg1Id,
                                              callExpr->getExprLoc());
@@ -8384,6 +8393,8 @@ SpirvInstruction *SpirvEmitter::processIntrinsicDot(const CallExpr *callExpr) {
   (void)vec1ComponentType;
   (void)vec1Size;
 
+  auto loc = callExpr->getLocStart();
+
   // According to HLSL reference, the dot function only works on integers
   // and floats.
   assert(returnType->isFloatingType() || returnType->isIntegerType());
@@ -8392,13 +8403,13 @@ SpirvInstruction *SpirvEmitter::processIntrinsicDot(const CallExpr *callExpr) {
   // basically the same as regular multiplication of 2 scalars.
   if (vec0Size == 1) {
     const spv::Op spvOp = translateOp(BO_Mul, arg0Type);
-    return spvBuilder.createBinaryOp(spvOp, returnType, arg0Id, arg1Id);
+    return spvBuilder.createBinaryOp(spvOp, returnType, arg0Id, arg1Id, loc);
   }
 
   // If the vectors are of type Float, we can use OpDot.
   if (returnType->isFloatingType()) {
-    return spvBuilder.createBinaryOp(spv::Op::OpDot, returnType, arg0Id,
-                                     arg1Id);
+    return spvBuilder.createBinaryOp(spv::Op::OpDot, returnType, arg0Id, arg1Id,
+                                     loc);
   }
   // Vector component type is Integer (signed or unsigned).
   // Create all instructions necessary to perform a dot product on
@@ -8417,16 +8428,15 @@ SpirvInstruction *SpirvEmitter::processIntrinsicDot(const CallExpr *callExpr) {
           returnType, arg0Id, {i}, arg0->getLocStart());
       auto *vec1member = spvBuilder.createCompositeExtract(
           returnType, arg1Id, {i}, arg1->getLocStart());
-      auto *multId =
-          spvBuilder.createBinaryOp(multSpvOp, returnType, vec0member,
-                                    vec1member, callExpr->getLocStart());
+      auto *multId = spvBuilder.createBinaryOp(multSpvOp, returnType,
+                                               vec0member, vec1member, loc);
       multIds.push_back(multId);
     }
     // Add all the multiplications.
     result = multIds[0];
     for (unsigned int i = 1; i < vec0Size; ++i) {
-      auto *additionId = spvBuilder.createBinaryOp(
-          addSpvOp, returnType, result, multIds[i], callExpr->getLocStart());
+      auto *additionId = spvBuilder.createBinaryOp(addSpvOp, returnType, result,
+                                                   multIds[i], loc);
       result = additionId;
     }
     return result;
@@ -8441,25 +8451,25 @@ SpirvInstruction *SpirvEmitter::processIntrinsicRcp(const CallExpr *callExpr) {
   const Expr *arg = callExpr->getArg(0);
   auto *argId = doExpr(arg);
   const QualType argType = arg->getType();
+  auto loc = callExpr->getLocStart();
 
   // For cases with matrix argument.
   QualType elemType = {};
   uint32_t numRows = 0, numCols = 0;
   if (isMxNMatrix(argType, &elemType, &numRows, &numCols)) {
     auto *vecOne = getVecValueOne(elemType, numCols);
-    const auto actOnEachVec = [this, vecOne](uint32_t /*index*/,
-                                             QualType vecType,
-                                             SpirvInstruction *curRow) {
-      return spvBuilder.createBinaryOp(spv::Op::OpFDiv, vecType, vecOne,
-                                       curRow);
+    const auto actOnEachVec = [this, vecOne, loc](uint32_t /*index*/,
+                                                  QualType vecType,
+                                                  SpirvInstruction *curRow) {
+      return spvBuilder.createBinaryOp(spv::Op::OpFDiv, vecType, vecOne, curRow,
+                                       loc);
     };
-    return processEachVectorInMatrix(arg, argId, actOnEachVec,
-                                     callExpr->getLocStart());
+    return processEachVectorInMatrix(arg, argId, actOnEachVec, loc);
   }
 
   // For cases with scalar or vector arguments.
   return spvBuilder.createBinaryOp(spv::Op::OpFDiv, returnType,
-                                   getValueOne(argType), argId);
+                                   getValueOne(argType), argId, loc);
 }
 
 SpirvInstruction *
@@ -8658,13 +8668,14 @@ SpirvEmitter::processD3DCOLORtoUBYTE4(const CallExpr *callExpr) {
   const auto arg = callExpr->getArg(0);
   auto *argId = doExpr(arg);
   const auto argType = arg->getType();
-  auto *swizzle = spvBuilder.createVectorShuffle(
-      argType, argId, argId, {2, 1, 0, 3}, callExpr->getLocStart());
+  auto loc = callExpr->getLocStart();
+  auto *swizzle =
+      spvBuilder.createVectorShuffle(argType, argId, argId, {2, 1, 0, 3}, loc);
   auto *scaled = spvBuilder.createBinaryOp(
       spv::Op::OpVectorTimesScalar, argType, swizzle,
-      spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(255.002f)));
-  return castToInt(scaled, arg->getType(), callExpr->getType(),
-                   callExpr->getExprLoc());
+      spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(255.002f)),
+      loc);
+  return castToInt(scaled, arg->getType(), callExpr->getType(), loc);
 }
 
 SpirvInstruction *
@@ -8679,8 +8690,8 @@ SpirvEmitter::processIntrinsicIsFinite(const CallExpr *callExpr) {
       spvBuilder.createUnaryOp(spv::Op::OpIsNan, returnType, arg, loc);
   const auto isInf =
       spvBuilder.createUnaryOp(spv::Op::OpIsInf, returnType, arg, loc);
-  const auto isNanOrInf =
-      spvBuilder.createBinaryOp(spv::Op::OpLogicalOr, returnType, isNan, isInf);
+  const auto isNanOrInf = spvBuilder.createBinaryOp(
+      spv::Op::OpLogicalOr, returnType, isNan, isInf, loc);
   return spvBuilder.createUnaryOp(spv::Op::OpLogicalNot, returnType, isNanOrInf,
                                   loc);
 }
@@ -8782,7 +8793,7 @@ SpirvEmitter::processIntrinsicFloatSign(const CallExpr *callExpr) {
         argType, glslInstSet, GLSLstd450::GLSLstd450FSign, {argId}, loc);
   }
 
-  return castToInt(floatSign, arg->getType(), returnType, arg->getExprLoc());
+  return castToInt(floatSign, arg->getType(), returnType, arg->getLocStart());
 }
 
 SpirvInstruction *
@@ -9010,17 +9021,18 @@ SpirvEmitter::processIntrinsicLog10(const CallExpr *callExpr) {
   // Since there is no log10 instruction in SPIR-V, we can use:
   // log10(x) = log2(x) * ( 1 / log2(10) )
   // 1 / log2(10) = 0.30103
+  auto loc = callExpr->getExprLoc();
   auto *scale =
       spvBuilder.getConstantFloat(astContext.FloatTy, llvm::APFloat(0.30103f));
   auto *log2 = processIntrinsicUsingGLSLInst(
-      callExpr, GLSLstd450::GLSLstd450Log2, true, callExpr->getExprLoc());
+      callExpr, GLSLstd450::GLSLstd450Log2, true, loc);
   const auto returnType = callExpr->getType();
   spv::Op scaleOp = isScalarType(returnType)
                         ? spv::Op::OpFMul
                         : isVectorType(returnType)
                               ? spv::Op::OpVectorTimesScalar
                               : spv::Op::OpMatrixTimesScalar;
-  return spvBuilder.createBinaryOp(scaleOp, returnType, log2, scale);
+  return spvBuilder.createBinaryOp(scaleOp, returnType, log2, scale, loc);
 }
 
 SpirvInstruction *SpirvEmitter::processRayBuiltins(const CallExpr *callExpr,
@@ -10234,12 +10246,14 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
   // This method may only be called for Hull shaders.
   assert(spvContext.isHS());
 
+  auto loc = hullMainFuncDecl->getLocation();
+  auto locEnd = hullMainFuncDecl->getLocEnd();
+
   // For Hull shaders, the real output is an array of size
   // numOutputControlPoints. The results of the main should be written to the
   // correct offset in the array (based on InvocationID).
   if (!numOutputControlPoints) {
-    emitError("number of output control points cannot be zero",
-              hullMainFuncDecl->getLocation());
+    emitError("number of output control points cannot be zero", loc);
     return false;
   }
   // TODO: We should be able to handle cases where the SV_OutputControlPointID
@@ -10247,12 +10261,11 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
   if (!outputControlPointId) {
     emitError(
         "SV_OutputControlPointID semantic must be provided in hull shader",
-        hullMainFuncDecl->getLocation());
+        loc);
     return false;
   }
   if (!patchConstFunc) {
-    emitError("patch constant function not defined in hull shader",
-              hullMainFuncDecl->getLocation());
+    emitError("patch constant function not defined in hull shader", loc);
     return false;
   }
 
@@ -10264,13 +10277,11 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
     const QualType hullMainRetType = astContext.getConstantArrayType(
         retType, llvm::APInt(32, numOutputControlPoints),
         clang::ArrayType::Normal, 0);
-    hullMainOutputPatch = spvBuilder.addFnVar(
-        hullMainRetType, /*SourceLocation*/ {}, "temp.var.hullMainRetVal");
+    hullMainOutputPatch =
+        spvBuilder.addFnVar(hullMainRetType, locEnd, "temp.var.hullMainRetVal");
     auto *tempLocation = spvBuilder.createAccessChain(
-        retType, hullMainOutputPatch, {outputControlPointId},
-        hullMainFuncDecl->getLocation());
-    spvBuilder.createStore(tempLocation, retVal,
-                           hullMainFuncDecl->getLocation());
+        retType, hullMainOutputPatch, {outputControlPointId}, locEnd);
+    spvBuilder.createStore(tempLocation, retVal, locEnd);
   }
 
   // Now create a barrier before calling the Patch Constant Function (PCF).
@@ -10286,11 +10297,11 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
   // and we only allow ID 0 to call the PCF.
   auto *condition = spvBuilder.createBinaryOp(
       spv::Op::OpIEqual, astContext.BoolTy, outputControlPointId,
-      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 0)));
+      spvBuilder.getConstantInt(astContext.UnsignedIntTy, llvm::APInt(32, 0)),
+      loc);
   auto *thenBB = spvBuilder.createBasicBlock("if.true");
   auto *mergeBB = spvBuilder.createBasicBlock("if.merge");
-  spvBuilder.createConditionalBranch(condition, thenBB, mergeBB,
-                                     hullMainFuncDecl->getLocation(), mergeBB);
+  spvBuilder.createConditionalBranch(condition, thenBB, mergeBB, loc, mergeBB);
   spvBuilder.addSuccessor(thenBB);
   spvBuilder.addSuccessor(mergeBB);
   spvBuilder.setMergeTarget(mergeBB);
@@ -10312,12 +10323,12 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
       [this](const ParmVarDecl *param) {
         const QualType type = param->getType();
         std::string tempVarName = "param.var." + param->getNameAsString();
-        auto *tempVar =
-            spvBuilder.addFnVar(type, param->getLocation(), tempVarName,
-                                param->hasAttr<HLSLPreciseAttr>());
+        auto paramLoc = param->getLocation();
+        auto *tempVar = spvBuilder.addFnVar(type, paramLoc, tempVarName,
+                                            param->hasAttr<HLSLPreciseAttr>());
         SpirvInstruction *loadedValue = nullptr;
         declIdMapper.createStageInputVar(param, &loadedValue, /*forPCF*/ true);
-        spvBuilder.createStore(tempVar, loadedValue, param->getLocation());
+        spvBuilder.createStore(tempVar, loadedValue, paramLoc);
         return tempVar;
       };
 
@@ -10352,7 +10363,7 @@ bool SpirvEmitter::processHSEntryPointOutputAndPCF(
                                          /*forPCF*/ true))
     return false;
 
-  spvBuilder.createBranch(mergeBB, hullMainFuncDecl->getLocEnd());
+  spvBuilder.createBranch(mergeBB, locEnd);
   spvBuilder.addSuccessor(mergeBB);
   spvBuilder.setInsertPoint(mergeBB);
   return true;

+ 5 - 6
tools/clang/lib/SPIRV/SpirvEmitter.h

@@ -776,12 +776,11 @@ private:
   /// declaration for the Buffer/Texture object.
   /// If residencyCodeId is not zero,  the SPIR-V instruction for storing the
   /// resulting residency code will also be emitted.
-  SpirvInstruction *processBufferTextureLoad(const Expr *object,
-                                             SpirvInstruction *location,
-                                             SpirvInstruction *constOffset,
-                                             SpirvInstruction *varOffset,
-                                             SpirvInstruction *lod,
-                                             SpirvInstruction *residencyCode);
+  SpirvInstruction *
+  processBufferTextureLoad(const Expr *object, SpirvInstruction *location,
+                           SpirvInstruction *constOffset,
+                           SpirvInstruction *varOffset, SpirvInstruction *lod,
+                           SpirvInstruction *residencyCode, SourceLocation loc);
 
   /// \brief Processes .Sample() and .Gather() method calls for texture objects.
   SpirvInstruction *processTextureSampleGather(const CXXMemberCallExpr *expr,

+ 2 - 2
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.branch.hlsl

@@ -31,8 +31,8 @@ void main() {
 
 // CHECK:       OpLine [[file]] 37 3
 // CHECK-NEXT:  OpBranch %while_check
-// CHECK:       OpLine [[file]] 37 14
-// CHECK:       OpBranchConditional {{%\d+}} %while_body %while_merge
+// CHECK:       OpLine [[file]] 37 3
+// CHECK-NEXT:  OpLoopMerge %while_merge %while_continue None
   while (a < c) {
 // CHECK:       OpLine [[file]] 41 17
 // CHECK-NEXT:  OpSelectionMerge %if_merge_1 None

+ 8 - 8
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.composite.hlsl

@@ -45,15 +45,15 @@ void main() {
 
   int4 a = {
       float2(1, 0),
-// CHECK:                   OpConvertFToS %int %float_0
-// CHECK-NEXT:              OpLine [[file]] 53 7
-// CHECK-NEXT: [[z:%\d+]] = OpCompositeExtract %float {{%\d+}} 0
-// CHECK-NEXT: [[x:%\d+]] = OpCompositeExtract %float {{%\d+}} 1
+// CHECK: OpLine [[file]] 51 7
+// CHECK: OpFunctionCall %int4_bool_float3_0 %test_struct
       test_struct().c.zx
-// CHECK-NEXT:              OpLine [[file]] 47 12
-// CHECK-NEXT: [[z:%\d+]] = OpConvertFToS %int [[z]]
-// CHECK-NEXT: [[x:%\d+]] = OpConvertFToS %int [[x]]
-// CHECK-NEXT:   {{%\d+}} = OpCompositeConstruct %v4int {{%\d+}} {{%\d+}} [[z]] [[x]]
+// CHECK:      OpLine [[file]] 47 12
+// CHECK:      OpCompositeExtract %float {{%\d+}} 0
+// CHECK-NEXT: OpCompositeExtract %float {{%\d+}} 1
+// CHECK-NEXT: OpConvertFToS %int
+// CHECK-NEXT: OpConvertFToS %int
+// CHECK-NEXT: OpCompositeConstruct %v4int
   };
 
 // CHECK:                        OpFDiv %float {{%\d+}} %float_2

+ 0 - 26
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.func_decl.hlsl

@@ -1,26 +0,0 @@
-// Run: %dxc -T ps_6_0 -E main -Zi
-
-// CHECK:      [[file:%\d+]] = OpString
-// CHECK-SAME: spirv.debug.opline.func_decl.hlsl
-
-void foo();
-void bar();
-
-// CHECK:      OpLine [[file]] 24 1
-// CHECK-NEXT: %main = OpFunction %void None
-// CHECK:      OpLine [[file]] 14 1
-// CHECK-NEXT: %foo = OpFunction %void None
-void foo() {
-  bar();
-}
-
-// CHECK:      OpLine [[file]] 20 1
-// CHECK-NEXT: %bar = OpFunction %void None
-void bar() {
-  int a = 3;
-}
-
-void main() {
-  foo();
-  bar();
-}

+ 144 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.function.hlsl

@@ -0,0 +1,144 @@
+// Run: %dxc -T ps_6_0 -E main -Zi
+
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.function.hlsl
+
+void foo(in float4 a, out float3 b);
+
+// CHECK:              OpLine [[file]] 31 1
+// CHECK-NEXT: %main = OpFunction %void None
+
+void bar(int a, in float b, inout bool2 c, const float3 d, out uint4 e) {
+}
+
+float4 getV4f(float x, int y, bool z);
+
+struct R {
+  int a;
+  void incr();
+  void decr() { --a; }
+};
+
+RWStructuredBuffer<R> rwsb;
+
+void decr(inout R a, in R b, out R c, R d, const R e);
+
+groupshared R r[5];
+
+R getR(uint i);
+
+void main() {
+  float4 v4f;
+  float3 v3f;
+
+// CHECK:                     OpLine [[file]] 37 7
+// CHECK-NEXT: %param_var_a = OpVariable %_ptr_Function_v4float Function
+  foo(v4f, v3f);
+// CHECK:                     OpLine [[file]] 40 14
+// CHECK-NEXT: %param_var_x = OpVariable %_ptr_Function_float Function
+  foo(getV4f(v4f.x,
+// CHECK:                     OpLine [[file]] 47 21
+// CHECK-NEXT: %param_var_x_0 = OpVariable %_ptr_Function_float Function
+// CHECK-NEXT:                OpLine [[file]] 47 28
+// CHECK-NEXT: %param_var_y = OpVariable %_ptr_Function_int Function
+// CHECK-NEXT:                OpLine [[file]] 47 35
+// CHECK-NEXT: %param_var_z = OpVariable %_ptr_Function_bool Function
+             getV4f(v4f.y, v4f.z, v4f.w).z,
+// CHECK:                     OpLine [[file]] 47 14
+// CHECK-NEXT: %param_var_y_0 = OpVariable %_ptr_Function_int Function
+// CHECK-NEXT:                OpLine [[file]] 52 14
+// CHECK-NEXT: %param_var_z_0 = OpVariable %_ptr_Function_bool Function
+             v3f.y),
+      v3f);
+// CHECK-NEXT:                OpLine [[file]] 40 7
+// CHECK-NEXT: %param_var_a_0 = OpVariable %_ptr_Function_v4float Function
+
+  r[0].incr();
+  decr(r[0],
+// CHECK-NEXT:                OpLine [[file]] 63 13
+// CHECK-NEXT: %param_var_i = OpVariable %_ptr_Function_uint Function
+// CHECK-NEXT:                OpLine [[file]] 63 8
+// CHECK-NEXT: %param_var_b = OpVariable %_ptr_Function_R_0 Function
+       getR(1),
+       r[2],
+// CHECK-NEXT:                OpLine [[file]] 69 13
+// CHECK-NEXT: %param_var_i_0 = OpVariable %_ptr_Function_uint Function
+// CHECK-NEXT:                OpLine [[file]] 69 8
+// CHECK-NEXT: %param_var_d = OpVariable %_ptr_Function_R_0 Function
+       getR(3),
+// CHECK-NEXT:                OpLine [[file]] 74 13
+// CHECK-NEXT: %param_var_i_1 = OpVariable %_ptr_Function_uint Function
+// CHECK-NEXT:                OpLine [[file]] 74 8
+// CHECK-NEXT: %param_var_e = OpVariable %_ptr_Function_R_0 Function
+       getR(4));
+
+  rwsb[0].incr();
+
+  decr(rwsb[1],
+// CHECK-NEXT:                OpLine [[file]] 81 8
+// CHECK-NEXT: %param_var_b_0 = OpVariable %_ptr_Function_R_0 Function
+       rwsb[2],
+       rwsb[3],
+// CHECK-NEXT:                OpLine [[file]] 85 8
+// CHECK-NEXT: %param_var_d_0 = OpVariable %_ptr_Function_R_0 Function
+       rwsb[4],
+// CHECK-NEXT:                OpLine [[file]] 88 8
+// CHECK-NEXT: %param_var_e_0 = OpVariable %_ptr_Function_R_0 Function
+       rwsb[5]);
+}
+
+// CHECK:             OpLine [[file]] 97 1
+// CHECK-NEXT: %foo = OpFunction %void None
+// CHECK-NEXT:        OpLine [[file]] 97 20
+// CHECK-NEXT:   %a = OpFunctionParameter %_ptr_Function_v4float
+// CHECK-NEXT:        OpLine [[file]] 97 34
+// CHECK-NEXT:   %b = OpFunctionParameter %_ptr_Function_v3float
+void foo(in float4 a, out float3 b) {
+  a = b.xxzz;
+  b = a.yzw;
+// CHECK:                     OpLine [[file]] 104 7
+// CHECK-NEXT: %param_var_a_1 = OpVariable %_ptr_Function_int Function
+// CHECK-NEXT:                OpLine [[file]] 104 12
+// CHECK-NEXT: %param_var_b_1 = OpVariable %_ptr_Function_float Function
+  bar(a.x, b.y, a.yz, b, a);
+}
+
+// CHECK:                     OpLine [[file]] 113 1
+// CHECK-NEXT:      %getV4f = OpFunction %v4float None
+// CHECK-NEXT:                OpLine [[file]] 113 21
+// CHECK-NEXT:           %x = OpFunctionParameter %_ptr_Function_float
+// CHECK-NEXT:                OpLine [[file]] 113 28
+// CHECK-NEXT:           %y = OpFunctionParameter %_ptr_Function_int
+float4 getV4f(float x, int y, bool z) { return float4(x, y, z, z); }
+
+// CHECK:                     OpLine [[file]] 118 1
+// CHECK-NEXT:      %R_incr = OpFunction %void None
+// CHECK-NEXT:  %param_this = OpFunctionParameter %_ptr_Function_R_0
+void R::incr() { ++a; }
+
+// CHECK:                     OpLine [[file]] 124 1
+// CHECK-NEXT:        %getR = OpFunction %R_0 None
+// CHECK-NEXT:                OpLine [[file]] 124 13
+// CHECK-NEXT:           %i = OpFunctionParameter %_ptr_Function_uint
+R getR(uint i) { return r[i]; }
+
+// CHECK:                     OpLine [[file]] 132 1
+// CHECK-NEXT:        %decr = OpFunction %void None
+// CHECK-NEXT:                OpLine [[file]] 132 19
+// CHECK-NEXT:         %a_0 = OpFunctionParameter %_ptr_Function_R_0
+// CHECK-NEXT:                OpLine [[file]] 132 27
+// CHECK-NEXT:         %b_0 = OpFunctionParameter %_ptr_Function_R_0
+void decr(inout R a, in R b, out R c, R d, const R e) { a.a--; }
+
+// CHECK:             OpLine [[file]] 12 1
+// CHECK-NEXT: %bar = OpFunction %void None
+// CHECK-NEXT:        OpLine [[file]] 12 14
+// CHECK-NEXT: %a_1 = OpFunctionParameter %_ptr_Function_int
+// CHECK-NEXT:        OpLine [[file]] 12 26
+// CHECK-NEXT: %b_1 = OpFunctionParameter %_ptr_Function_float
+// CHECK-NEXT:        OpLine [[file]] 12 41
+// CHECK-NEXT: %c_0 = OpFunctionParameter %_ptr_Function_v2bool
+// CHECK-NEXT:        OpLine [[file]] 12 57
+// CHECK-NEXT: %d_0 = OpFunctionParameter %_ptr_Function_v3float
+// CHECK-NEXT:        OpLine [[file]] 12 70
+// CHECK-NEXT: %e_0 = OpFunctionParameter %_ptr_Function_v4uint

+ 8 - 11
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.hlsl

@@ -30,9 +30,8 @@ float4 main(uint val : A) : SV_Target {
   // CHECK-NEXT: OpLoad %type_2d_image %MyTexture
   float4 c = MyTexture.Sample(MySampler, float2(0.1, 0.2));
 
-  // CHECK:      OpLine [[file]] 37 7
+  // CHECK:      OpLine [[file]] 36 7
   // CHECK-NEXT: OpLoad %uint %val
-  // CHECK-NEXT: OpUGreaterThan
   if (val > 10) {
     a = 5;
   } else {
@@ -40,33 +39,31 @@ float4 main(uint val : A) : SV_Target {
   }
 
   for (
-  // CHECK:      OpLine [[file]] 46 7
+  // CHECK:      OpLine [[file]] 45 7
   // CHECK-NEXT: OpStore %b %uint_0
       b = 0;
-  // CHECK:      OpLine [[file]] 49 7
+  // CHECK:      OpLine [[file]] 48 7
   // CHECK-NEXT: OpBranch %for_check
       b < 10;
-  // CHECK:      OpLine [[file]] 53 7
+  // CHECK:      OpLine [[file]] 51 9
   // CHECK-NEXT: OpLoad %uint %b
-  // CHECK-NEXT: OpIAdd
       ++b) {
     a += 1;
   }
 
-  // CHECK:      OpLine [[file]] 60 10
+  // CHECK:      OpLine [[file]] 57 12
   // CHECK-NEXT: OpLoad %uint %b
-  // CHECK-NEXT: OpISub
   while (--b > 0);
 
   do {
     c++;
-  // CHECK:      OpLine [[file]] 66 12
+  // CHECK:      OpLine [[file]] 63 12
   // CHECK-NEXT: OpAccessChain %_ptr_Function_float %c %int_0
   } while (c.x < 10);
 
-// CHECK:      OpLine [[file]] 72 7
+// CHECK:      OpLine [[file]] 69 7
 // CHECK-NEXT: OpAccessChain %_ptr_Function_float %c %int_0
-// CHECK:      OpLine [[file]] 72 3
+// CHECK:      OpLine [[file]] 69 3
 // CHECK-NEXT: pStore %a
   a = c.x;
 

+ 24 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.intrinsic.control.barrier.hlsl

@@ -0,0 +1,24 @@
+// Run: %dxc -T cs_6_0 -E main -Zi
+
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.intrinsic.control.barrier.hlsl
+
+groupshared int dest_i;
+
+// Note that preprocessor prepends a "#line 1 ..." line to the whole file and
+// the compliation sees line numbers incremented by 1.
+
+void main() {
+
+// CHECK:      OpLine [[file]] 16 3
+// CHECK-NEXT: OpControlBarrier %uint_2 %uint_1 %uint_2376
+  AllMemoryBarrierWithGroupSync();
+
+// CHECK-NEXT: OpLine [[file]] 20 3
+// CHECK-NEXT: OpMemoryBarrier %uint_1 %uint_2120
+  DeviceMemoryBarrier();
+
+// CHECK-NEXT: OpLine [[file]] 24 3
+// CHECK-NEXT: OpMemoryBarrier %uint_2 %uint_264
+  GroupMemoryBarrier();
+}

+ 139 - 91
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.intrinsic.hlsl

@@ -3,14 +3,7 @@
 // CHECK:      [[file:%\d+]] = OpString
 // CHECK-SAME: spirv.debug.opline.intrinsic.hlsl
 
-ConsumeStructuredBuffer<bool2> consume_v2bool;
-AppendStructuredBuffer<float2> append_v2float;
-ByteAddressBuffer byte_addr;
-RWTexture2D<int3> rw_tex;
-SamplerState sam;
-Texture2D<float4> t2f4;
-RWByteAddressBuffer rw_byte;
-Texture2DMS<float> tex_2dms;
+groupshared int dest_i;
 
 // Note that preprocessor prepends a "#line 1 ..." line to the whole file and
 // the compliation sees line numbers incremented by 1.
@@ -20,122 +13,177 @@ void main() {
   uint4 v4i;
   float2x2 m2x2f;
 
-// CHECK:                     OpLine [[file]] 28 18
-// CHECK-NEXT: [[cnt:%\d+]] = OpAccessChain %_ptr_Uniform_int %counter_var_append_v2float %uint_0
-// CHECK:                     OpLine [[file]] 28 3
-// CHECK-NEXT: [[app:%\d+]] = OpAccessChain %_ptr_Uniform_v2float %append_v2float %uint_0
-  append_v2float.Append(
-// CHECK:                     OpLine [[file]] 33 22
-// CHECK-NEXT: [[cnt:%\d+]] = OpAccessChain %_ptr_Uniform_int %counter_var_consume_v2bool %uint_0
-// CHECK:                     OpLine [[file]] 33 7
-// CHECK-NEXT: [[app:%\d+]] = OpAccessChain %_ptr_Uniform_v2uint %consume_v2bool %uint_0
-      consume_v2bool.Consume());
-// CHECK:      OpLine [[file]] 28 18
-// CHECK-NEXT: OpStore
-
-// CHECK:                     OpLine [[file]] 40 3
+// CHECK:                     OpLine [[file]] 20 3
 // CHECK-NEXT: [[mod:%\d+]] = OpExtInst %ModfStructType {{%\d+}} ModfStruct {{%\d+}}
 // CHECK-NEXT:     {{%\d+}} = OpCompositeExtract %v2float [[mod]] 1
   modf(v2f,
-// CHECK:                     OpLine [[file]] 46 8
+// CHECK:                     OpLine [[file]] 26 8
 // CHECK-NEXT: [[mod:%\d+]] = OpConvertFToU %v2uint {{%\d+}}
 // CHECK-NEXT: [[v4i:%\d+]] = OpLoad %v4uint %v4i
 // CHECK-NEXT: [[v4i:%\d+]] = OpVectorShuffle %v4uint [[v4i]] [[mod]] 4 5 2 3
 // CHECK-NEXT:                OpStore %v4i [[v4i]]
        v4i.xy);
 
-// CHECK:                    OpLine [[file]] 52 13
-// CHECK-NEXT: [[ba:%\d+]] = OpAccessChain %_ptr_Uniform_uint %byte_addr %uint_0 {{%\d+}}
-// CHECK-NEXT:               OpLine [[file]] 52 23
-// CHECK-NEXT:    {{%\d+}} = OpLoad %uint [[ba]]
-  v4i.xyz = byte_addr.Load3(v4i.x);
-
-// CHECK:                      OpLine [[file]] 56 10
-// CHECK-NEXT: [[size:%\d+]] = OpImageQuerySize %v2uint {{%\d+}}
-  rw_tex.GetDimensions(
-// CHECK:                      OpLine [[file]] 60 7
-// CHECK-NEXT: [[v4ix:%\d+]] = OpAccessChain %_ptr_Function_uint %v4i %int_0
-// CHECK-NEXT:                 OpStore [[v4ix]]
-      v4i.x, v4i.y);
-
-// CHECK:                     OpLine [[file]] 65 3
-// CHECK-NEXT: [[len:%\d+]] = OpArrayLength %uint %byte_addr 0
-// CHECK-NEXT:     {{%\d+}} = OpIMul %uint [[len]] %uint_4
-  byte_addr.GetDimensions(v4i.z);
-
-// CHECK:                     OpLine [[file]] 70 14
-// CHECK-NEXT: [[sam:%\d+]] = OpSampledImage %type_sampled_image {{%\d+}} {{%\d+}}
-// CHECK-NEXT:     {{%\d+}} = OpImageGather %v4float [[sam]] {{%\d+}} %int_0 Offset
-  v4i = t2f4.GatherRed(sam, v2f, v4i.xy);
-
-// CHECK:                      OpLine [[file]] 77 9
+// CHECK:                      OpLine [[file]] 33 9
 // CHECK-NEXT: [[v4ix:%\d+]] = OpCompositeExtract %uint {{%\d+}} 0
 // CHECK-NEXT:      {{%\d+}} = OpShiftLeftLogical %uint [[v4ix]] %uint_8
 // CHECK-NEXT:      {{%\d+}} = OpShiftLeftLogical %uint [[v4ix]] %uint_16
 // CHECK-NEXT:      {{%\d+}} = OpShiftLeftLogical %uint [[v4ix]] %uint_24
   v4i = msad4(v4i.x, v4i.xy, v4i);
-// CHECK:                 OpLine [[file]] 77 33
-// CHECK-NEXT: {{%\d+}} = OpCompositeConstruct %v4uint
-
-// CHECK:                 OpLine [[file]] 83 9
-// CHECK-NEXT: {{%\d+}} = OpExtInst %v2float {{%\d+}} Fma
-  v4i = mad(m2x2f, float2x2(v4i), float2x2(v2f, v2f));
-// CHECK:      {{%\d+}} = OpConvertFToU %v4uint {{%\d+}}
-// CHECK-NEXT:            OpLine [[file]] 83 3
-// CHECK-NEXT:            OpStore %v4i
-
-// TODO(jaebaek): Add "OpLine 90 9" here.
-// CHECK: {{%\d+}} = OpMatrixTimesVector %v2float
+// CHECK:      OpLine [[file]] 33 3
+// CHECK-NEXT: OpStore %v4i {{%\d+}}
+
+// CHECK:      OpLine [[file]] 39 23
+// CHECK-NEXT: OpExtInst %v2float {{%\d+}} Fma
+  /* comment */ v4i = mad(m2x2f, float2x2(v4i), float2x2(v2f, v2f));
+// CHECK:      OpLine [[file]] 39 17
+// CHECK-NEXT: OpStore %v4i
+
+// CHECK:                 OpLine [[file]] 45 9
+// CHECK-NEXT: {{%\d+}} = OpMatrixTimesVector %v2float
   v2f = mul(v2f, m2x2f);
 
-// TODO(jaebaek): Add "OpLine 94 11" here.
-// CHECK: {{%\d+}} = OpDot %float
+// CHECK:                 OpLine [[file]] 49 11
+// CHECK-NEXT: {{%\d+}} = OpDot %float
   v2f.x = dot(v4i.xy, v2f);
 
-// CHECK:                 OpLine [[file]] 98 12
+// CHECK:                 OpLine [[file]] 53 11
 // CHECK-NEXT: {{%\d+}} = OpExtInst %v2float {{%\d+}} UnpackHalf2x16
-  half h = f16tof32(v4i.x);
+  v2f.x = f16tof32(v4i.x);
 
-// CHECK:                 OpLine [[file]] 102 11
+// CHECK:                 OpLine [[file]] 57 11
 // CHECK-NEXT: {{%\d+}} = OpDPdx %v2float
   m2x2f = ddx(m2x2f);
 
-// CHECK:                       OpLine [[file]] 109 11
+// CHECK:                       OpLine [[file]] 64 11
 // CHECK-NEXT: [[fmod0:%\d+]] = OpFMod %v2float {{%\d+}} {{%\d+}}
-// CHECK:                       OpLine [[file]] 109 11
+// CHECK:                       OpLine [[file]] 64 11
 // CHECK-NEXT: [[fmod1:%\d+]] = OpFMod %v2float {{%\d+}} {{%\d+}}
 // CHECK-NEXT:       {{%\d+}} = OpCompositeConstruct %mat2v2float [[fmod0]] [[fmod1]]
   m2x2f = fmod(m2x2f, float2x2(v4i));
 
-// CHECK:                     OpLine [[file]] 116 11
-// CHECK-NEXT: [[add:%\d+]] = OpAtomicIAdd %uint {{%\d+}} %uint_1 %uint_0 %uint_42
-// CHECK-NEXT:                OpLine [[file]] 116 34
-// CHECK-NEXT: [[v4i:%\d+]] = OpAccessChain %_ptr_Function_uint %v4i %int_0
-// CHECK-NEXT:                OpStore [[v4i]] [[add]]
-  rw_byte.InterlockedAdd(16, 42, v4i.x);
-
-// CHECK:                 OpLine [[file]] 121 7
-// TODO(jaebaek): Add "OpFOrdNotEqual %v2bool .." here
-// CHECK-NEXT: {{%\d+}} = OpAll %bool {{%\d+}}
+// CHECK:                     OpLine [[file]] 69 7
+// CHECK-NEXT: [[v2f:%\d+]] = OpFOrdNotEqual %v2bool
+// CHECK-NEXT:     {{%\d+}} = OpAll %bool [[v2f]]
   if (all(v2f))
-// CHECK:                      OpLoad %float {{%\d+}}
-// CHECK:                      OpLine [[file]] 129 5
-// CHECK-NEXT:  [[sin:%\d+]] = OpExtInst %float {{%\d+}} Sin {{%\d+}}
-// CHECK-NEXT:                 OpLine [[file]] 129 19
+// CHECK:                      OpLine [[file]] 76 5
+// CHECK:       [[sin:%\d+]] = OpExtInst %float {{%\d+}} Sin {{%\d+}}
+// CHECK-NEXT:                 OpLine [[file]] 76 19
 // CHECK-NEXT: [[v2fx:%\d+]] = OpAccessChain %_ptr_Function_float %v2f %int_1
-// CHECK-NEXT:                 OpLine [[file]] 129 5
+// CHECK-NEXT:                 OpLine [[file]] 76 5
 // CHECK-NEXT:                 OpStore [[v2fx]] [[sin]]
     sincos(v2f.x, v2f.y, v2f.x);
 
-// CHECK:                     OpLine [[file]] 135 18
-// CHECK-NEXT: [[v2f:%\d+]] = OpLoad %v2float %v2f
-// CHECK-NEXT:                OpLine [[file]] 135 9
-// CHECK-NEXT:     {{%\d+}} = OpExtInst %v2float {{%\d+}} FClamp [[v2f]]
+// CHECK:                 OpLine [[file]] 80 9
+// CHECK-NEXT: {{%\d+}} = OpExtInst %v2float {{%\d+}} FClamp
   v2f = saturate(v2f);
 
-// CHECK:      OpLine [[file]] 141 12
-// CHECK-NEXT: OpStore %var_GetSamplePosition_data_2
-// CHECK-NEXT: OpStore %var_GetSamplePosition_data_4
-// CHECK-NEXT: OpStore %var_GetSamplePosition_data_8
-  tex_2dms.GetSamplePosition(v4i.x);
+// CHECK:      OpLine [[file]] 84 17
+// CHECK-NEXT: OpAtomicCompareExchange %int %dest_i %uint_1 %uint_0 %uint_0
+  /* comment */ InterlockedCompareStore(dest_i, v4i.x, v4i.y);
+
+// CHECK:                     OpLine [[file]] 91 41
+// CHECK-NEXT: [[idx:%\d+]] = OpIAdd %uint
+// CHECK-NEXT:                OpLine [[file]] 91 3
+// CHECK-NEXT: [[v4i:%\d+]] = OpAccessChain %_ptr_Function_uint %v4i %int_0
+// CHECK-NEXT:                OpStore [[v4i]] [[idx]]
+  v4i.x = NonUniformResourceIndex(v4i.y + v4i.z);
+
+// CHECK:      OpLine [[file]] 97 11
+// CHECK-NEXT: OpImageSparseTexelsResident %bool
+// CHECK:      OpLine [[file]] 97 3
+// CHECK-NEXT: OpAccessChain %_ptr_Function_uint %v4i %int_2
+  v4i.z = CheckAccessFullyMapped(v4i.w);
+
+// CHECK:                     OpLine [[file]] 105 34
+// CHECK-NEXT: [[add:%\d+]] = OpFAdd %v2float
+// CHECK-NEXT:                OpLine [[file]] 105 12
+// CHECK-NEXT:                OpBitcast %v2uint [[add]]
+// CHECK-NEXT:                OpLine [[file]] 105 3
+// CHECK-NEXT:                OpLoad %v4uint %v4i
+  v4i.xy = asuint(m2x2f._m00_m11 + v2f);
+
+// CHECK:      OpLine [[file]] 111 15
+// CHECK-NEXT: OpFMul %v2float
+// CHECK-NEXT: OpLine [[file]] 111 3
+// CHECK-NEXT: OpFOrdLessThan %v2bool
+  clip(v4i.yz * m2x2f._m00_m11);
+
+  float4 v4f;
+
+// CHECK:      OpLine [[file]] 119 37
+// CHECK-NEXT: OpFMul %float
+// CHECK:      OpLine [[file]] 119 9
+// CHECK-NEXT: OpConvertFToU %v4uint
+  v4i = dst(v4f + 3 * v4f, v4f - v4f);
+
+// CHECK:      OpLine [[file]] 125 17
+// CHECK-NEXT: OpExtInst %float {{%\d+}} Exp2
+// CHECK:      OpLine [[file]] 125 11
+// CHECK-NEXT: OpBitcast %int
+  v4i.x = asint(ldexp(v4f.x + v4f.y, v4f.w));
+
+// CHECK:      OpLine [[file]] 133 25
+// CHECK-NEXT: OpFAdd %float
+// CHECK-NEXT: OpLine [[file]] 133 34
+// CHECK-NEXT: OpAccessChain %_ptr_Function_float %v4f %int_3
+// CHECK-NEXT: OpLine [[file]] 133 13
+// CHECK-NEXT: OpExtInst %FrexpStructType {{%\d+}} FrexpStruct
+  v4f = lit(frexp(v4f.x + v4f.y, v4f.w),
+// CHECK:                     OpLine [[file]] 137 13
+// CHECK-NEXT: [[v4f:%\d+]] = OpAccessChain %_ptr_Function_float %v4f %int_2
+// CHECK-NEXT:                OpLoad %float [[v4f]]
+            v4f.z,
+// CHECK:                       OpLine [[file]] 144 13
+// CHECK-NEXT: [[clamp:%\d+]] = OpExtInst %uint {{%\d+}} UClamp
+// CHECK-NEXT:                  OpConvertUToF %float [[clamp]]
+// CHECK-NEXT:                  OpLine [[file]] 133 9
+// CHECK-NEXT:                  OpExtInst %float {{%\d+}} FMax %float_0
+// CHECK-NEXT:                  OpExtInst %float {{%\d+}} FMin
+            clamp(v4i.x + v4i.y, 2 * v4i.z, v4i.w - v4i.z));
+
+// CHECK:                      OpLine [[file]] 150 33
+// CHECK-NEXT: [[sign:%\d+]] = OpExtInst %v3float {{%\d+}} FSign
+// CHECK-NEXT:                 OpLine [[file]] 150 38
+// CHECK-NEXT:                 OpConvertFToS %v3int [[sign]]
+  v4i = D3DCOLORtoUBYTE4(float4(sign(v4f.xyz - 2 * v4f.xyz),
+// CHECK:      OpLine [[file]] 153 33
+// CHECK-NEXT: OpExtInst %float {{%\d+}} FSign
+                                sign(v4f.w)));
+// CHECK:                     OpLine [[file]] 150 9
+// CHECK-NEXT: [[arg:%\d+]] = OpVectorShuffle %v4float {{%\d+}} {{%\d+}} 2 1 0 3
+// CHECK-NEXT:                OpVectorTimesScalar %v4float [[arg]]
+
+// CHECK:      OpLine [[file]] 160 7
+// CHECK-NEXT: OpIsNan %v4bool
+  if (isfinite(v4f).x)
+// CHECK:                     OpLine [[file]] 165 15
+// CHECK-NEXT: [[rcp:%\d+]] = OpFDiv %v4float
+// CHECK-NEXT:                OpLine [[file]] 165 11
+// CHECK-NEXT:                OpExtInst %v4float {{%\d+}} Sin [[rcp]]
+    v4f = sin(rcp(v4f / v4i.x));
+
+// CHECK:                     OpLine [[file]] 172 20
+// CHECK-NEXT:                OpExtInst %float {{%\d+}} Log2
+// CHECK:                     OpLine [[file]] 172 11
+// CHECK-NEXT: [[arg:%\d+]] = OpCompositeConstruct %v2float
+// CHECK-NEXT:                OpExtInst %uint {{%\d+}} PackHalf2x16 [[arg]]
+  v4i.x = f32tof16(log10(v2f.x * v2f.y + v4f.x));
+
+// CHECK:      OpLine [[file]] 176 3
+// CHECK-NEXT: OpTranspose %mat2v2float
+  transpose(m2x2f + m2x2f);
+
+// CHECK:                     OpLine [[file]] 184 25
+// CHECK-NEXT: [[abs:%\d+]] = OpExtInst %float {{%\d+}} FAbs
+// CHECK-NEXT:                OpLine [[file]] 184 20
+// CHECK-NEXT:                OpExtInst %float {{%\d+}} Sqrt [[abs]]
+// CHECK:      OpLine [[file]] 184 7
+// CHECK-NEXT: OpExtInst %uint {{%\d+}} FindUMsb
+  max(firstbithigh(sqrt(abs(v2f.x * v4f.w)) + v4i.x),
+// CHECK:      OpLine [[file]] 187 7
+// CHECK-NEXT: OpExtInst %float {{%\d+}} Cos %468
+      cos(v4f.x));
+// CHECK:      OpLine [[file]] 184 3
+// CHECK-NEXT: OpExtInst %float {{%\d+}} FMax
 }

+ 60 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.intrinsic.vulkan1.1.hlsl

@@ -0,0 +1,60 @@
+// Run: %dxc -T cs_6_0 -E main -Zi -fspv-target-env=vulkan1.1
+
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.intrinsic.vulkan1.1.hlsl
+
+// Note that preprocessor prepends a "#line 1 ..." line to the whole file and
+// the compliation sees line numbers incremented by 1.
+void main() {
+// CHECK:      OpLine [[file]] 14 11
+// CHECK:      OpLoad %uint %SubgroupSize
+// CHECK-NEXT: OpLine [[file]] 14 32
+// CHECK-NEXT: OpLoad %uint %SubgroupLocalInvocationId
+  int i = WaveGetLaneCount() + WaveGetLaneIndex();
+
+// CHECK:      OpLine [[file]] 18 3
+// CHECK-NEXT: OpGroupNonUniformElect %bool %uint_3
+  WaveIsFirstLane();
+
+// CHECK:      OpLine [[file]] 22 3
+// CHECK-NEXT: OpGroupNonUniformAll %bool %uint_3
+  WaveActiveAllTrue(i == 1);
+
+// CHECK:      OpLine [[file]] 26 3
+// CHECK-NEXT: OpGroupNonUniformAny %bool %uint_3
+  WaveActiveAnyTrue(i == 0);
+
+// CHECK:      OpLine [[file]] 30 3
+// CHECK-NEXT: OpGroupNonUniformBallot %v4uint %uint_3
+  WaveActiveBallot(i == 2);
+
+// CHECK:      OpLine [[file]] 34 3
+// CHECK-NEXT: OpGroupNonUniformAllEqual %bool %uint_3
+  WaveActiveAllEqual(i);
+
+// CHECK:      OpLine [[file]] 39 3
+// CHECK-NEXT: OpGroupNonUniformBallot %v4uint %uint_3
+// CHECK-NEXT: OpGroupNonUniformBallotBitCount %uint %uint_3 Reduce
+  WaveActiveCountBits(i);
+
+// CHECK:      OpLine [[file]] 43 3
+// CHECK-NEXT: OpGroupNonUniformIAdd %int %uint_3 Reduce
+  WaveActiveSum(i);
+
+// CHECK:      OpLine [[file]] 47 3
+// CHECK-NEXT: OpGroupNonUniformIAdd %int %uint_3 ExclusiveScan
+  WavePrefixSum(i);
+
+// CHECK:      OpLine [[file]] 52 3
+// CHECK-NEXT: OpGroupNonUniformBallot %v4uint %uint_3
+// CHECK-NEXT: OpGroupNonUniformBallotBitCount %uint %uint_3 ExclusiveScan
+  WavePrefixCountBits(i == 1);
+
+// CHECK:      OpLine [[file]] 56 3
+// CHECK-NEXT: OpGroupNonUniformBroadcast %int %uint_3
+  WaveReadLaneAt(i, 15);
+
+// CHECK:      OpLine [[file]] 60 3
+// CHECK-NEXT: OpGroupNonUniformQuadBroadcast %int %uint_3
+  QuadReadLaneAt(i, 15);
+}

+ 175 - 0
tools/clang/test/CodeGenSPIRV/spirv.debug.opline.operators.hlsl

@@ -0,0 +1,175 @@
+// Run: %dxc -T ps_6_0 -E main -Zi
+
+// CHECK:      [[file:%\d+]] = OpString
+// CHECK-SAME: spirv.debug.opline.operators.hlsl
+
+static int a, b, c;
+
+// Note that preprocessor prepends a "#line 1 ..." line to the whole file and
+// the compliation sees line numbers incremented by 1.
+
+void main() {
+// CHECK:      OpLine [[file]] 15 13
+// CHECK-NEXT: OpIAdd %int
+  int d = a + b;
+
+// CHECK:      OpLine [[file]] 19 9
+// CHECK-NEXT: OpIMul %int
+  c = a * b;
+
+// CHECK:      OpLine [[file]] 23 23
+// CHECK-NEXT: OpISub %int
+  /* comment */ c = a - b;
+
+// CHECK:      OpLine [[file]] 27 9
+// CHECK-NEXT: OpSDiv %int
+  c = a / b;
+
+// CHECK:      OpLine [[file]] 31 10
+// CHECK-NEXT: OpSLessThan %bool
+  c = (a < b);
+
+// CHECK:      OpLine [[file]] 35 9
+// CHECK-NEXT: OpSGreaterThan %bool
+  c = a > b;
+
+// CHECK:      OpLine [[file]] 39 11
+// CHECK-NEXT: OpLogicalAnd %bool
+  c = (a) && b;
+
+// CHECK:      OpLine [[file]] 43 5
+// CHECK-NEXT: OpLogicalOr %bool
+  a || b;
+
+// CHECK: OpLine [[file]] 47 5
+// CHECK: OpShiftLeftLogical %int
+  a << b;
+
+// CHECK: OpLine [[file]] 51 9
+// CHECK: OpShiftRightArithmetic %int
+  c = a >> b;
+
+// CHECK:      OpLine [[file]] 55 9
+// CHECK-NEXT: OpBitwiseAnd %int
+  c = a & b;
+
+// CHECK:      OpLine [[file]] 59 7
+// CHECK-NEXT: OpNot %int
+  c = ~b;
+
+// CHECK:      OpLine [[file]] 63 9
+// CHECK-NEXT: OpBitwiseXor %int
+  c = a ^ b;
+
+// CHECK:      OpLine [[file]] 71 5
+// CHECK-NEXT: OpIAdd %int
+// CHECK:      OpLine [[file]] 71 11
+// CHECK-NEXT: OpNot %int
+// CHECK-NEXT: OpLine [[file]] 71 9
+// CHECK-NEXT: OpBitwiseXor %int
+  c + a ^ ~b;
+
+// CHECK:      OpLine [[file]] 75 3
+// CHECK-NEXT: OpIAdd %int
+  ++a;
+
+// CHECK:      OpLine [[file]] 79 4
+// CHECK-NEXT: OpIAdd %int
+  a++;
+
+// CHECK:      OpLine [[file]] 83 4
+// CHECK-NEXT: OpISub %int
+  a--;
+
+// CHECK:      OpLine [[file]] 87 3
+// CHECK-NEXT: OpISub %int
+  --a;
+
+// CHECK: OpLine [[file]] 91 5
+// CHECK: OpShiftLeftLogical %int
+  a <<= 10;
+
+// CHECK:      OpLine [[file]] 95 5
+// CHECK-NEXT: OpISub %int
+  a -= 10;
+
+// CHECK:      OpLine [[file]] 99 5
+// CHECK-NEXT: OpIMul %int
+  a *= 10;
+
+// CHECK:      OpLine [[file]] 107 15
+// CHECK-NEXT: OpIAdd %int
+// CHECK-NEXT: OpLine [[file]] 107 10
+// CHECK-NEXT: OpIAdd %int
+// CHECK:      OpLine [[file]] 107 5
+// CHECK-NEXT: OpSDiv %int
+  a /= d + (b + c);
+
+// CHECK:      OpLine [[file]] 113 10
+// CHECK-NEXT: OpSLessThan %bool
+// CHECK-NEXT: OpLine [[file]] 113 15
+// CHECK-NEXT: OpLogicalAnd %bool
+  b = (a < c) && true;
+
+// CHECK:      OpLine [[file]] 117 5
+// CHECK-NEXT: OpIAdd %int
+  a += c;
+
+// CHECK:      OpLine [[file]] 125 15
+// CHECK-NEXT: OpIMul %int %int_100
+// CHECK:      OpLine [[file]] 125 25
+// CHECK-NEXT: OpISub %int %int_20
+// CHECK-NEXT: OpLine [[file]] 125 19
+// CHECK-NEXT: OpSDiv %int
+  d = a + 100 * b / (20 - c);
+// CHECK-NEXT: OpLine [[file]] 125 9
+// CHECK-NEXT: OpIAdd %int
+
+  float2x2 m2x2f;
+  int2x2 m2x2i;
+
+// CHECK:      OpLine [[file]] 136 13
+// CHECK-NEXT: OpMatrixTimesScalar %mat2v2float
+// CHECK:      OpLine [[file]] 136 21
+// CHECK-NEXT: OpFAdd %v2float
+  m2x2f = 2 * m2x2f + m2x2i;
+
+// CHECK:      OpLine [[file]] 144 17
+// CHECK-NEXT: OpFMul %v2float
+// CHECK:      OpLine [[file]] 144 17
+// CHECK-NEXT: OpFMul %v2float
+// CHECK-NEXT: OpLine [[file]] 144 11
+// CHECK-NEXT: OpCompositeConstruct %mat2v2float
+  m2x2f = m2x2f * m2x2i;
+
+  float4 v4f;
+  int4 v4i;
+
+// CHECK:      OpLine [[file]] 151 13
+// CHECK-NEXT: OpFDiv %v4float
+  v4i = v4f / v4i;
+
+// CHECK:      OpLine [[file]] 159 17
+// CHECK-NEXT: OpFMul %v2float
+// CHECK:      OpLine [[file]] 159 17
+// CHECK-NEXT: OpFMul %v2float
+// CHECK-NEXT: OpLine [[file]] 159 11
+// CHECK-NEXT: OpCompositeConstruct %mat2v2float
+  m2x2f = m2x2f * v4f;
+
+// CHECK:      OpLine [[file]] 163 17
+// CHECK-NEXT: OpMatrixTimesScalar %mat2v2float
+  m2x2f = m2x2f * v4f.x;
+
+// CHECK:      OpLine [[file]] 169 8
+// CHECK-NEXT: OpIMul %v4int
+// CHECK:      OpLine [[file]] 169 13
+// CHECK-NEXT: OpFOrdLessThan %v4bool
+  (v4i * a) < m2x2f;
+
+// CHECK:      OpLine [[file]] 175 8
+// CHECK-NEXT: OpSDiv %v4int
+// CHECK:      OpLine [[file]] 175 13
+// CHECK-NEXT: OpLogicalAnd %v4bool
+  (v4i / a) && v4f;
+}

+ 13 - 2
tools/clang/unittests/SPIRV/CodeGenSpirvTest.cpp

@@ -1440,12 +1440,23 @@ TEST_F(FileTest, SpirvDebugOpLineComposite) {
 TEST_F(FileTest, SpirvDebugOpLineEntry) {
   runFileTest("spirv.debug.opline.entry.hlsl");
 }
-TEST_F(FileTest, SpirvDebugOpLineFuncDecl) {
-  runFileTest("spirv.debug.opline.func_decl.hlsl");
+TEST_F(FileTest, SpirvDebugOpLineFunction) {
+  setBeforeHLSLLegalization();
+  runFileTest("spirv.debug.opline.function.hlsl");
 }
 TEST_F(FileTest, SpirvDebugOpLineIntrinsics) {
   runFileTest("spirv.debug.opline.intrinsic.hlsl");
 }
+TEST_F(FileTest, SpirvDebugOpLineIntrinsicsControlBarrier) {
+  runFileTest("spirv.debug.opline.intrinsic.control.barrier.hlsl");
+}
+TEST_F(FileTest, SpirvDebugOpLineIntrinsicsVulkan1_1) {
+  useVulkan1p1();
+  runFileTest("spirv.debug.opline.intrinsic.vulkan1.1.hlsl");
+}
+TEST_F(FileTest, SpirvDebugOpLineOperators) {
+  runFileTest("spirv.debug.opline.operators.hlsl");
+}
 TEST_F(FileTest, SpirvDebugOpLineVariables) {
   runFileTest("spirv.debug.opline.variables.hlsl");
 }