Coverage Report

Created: 2026-11-13 01:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/runner/work/DirectXShaderCompiler/DirectXShaderCompiler/lib/DxilPIXPasses/DxilPIXMeshShaderOutputInstrumentation.cpp
Line
Count
Source
1
///////////////////////////////////////////////////////////////////////////////
2
//                                                                           //
3
// DxilAddPixelHitInstrumentation.cpp                                        //
4
// Copyright (C) Microsoft Corporation. All rights reserved.                 //
5
// This file is distributed under the University of Illinois Open Source     //
6
// License. See LICENSE.TXT for details.                                     //
7
//                                                                           //
8
// Provides a pass to add instrumentation to retrieve mesh shader output.    //
9
// Used by PIX.                                                              //
10
//                                                                           //
11
///////////////////////////////////////////////////////////////////////////////
12
13
#include "dxc/DXIL/DxilOperations.h"
14
#include "dxc/DXIL/DxilUtil.h"
15
16
#include "dxc/DXIL/DxilInstructions.h"
17
#include "dxc/DXIL/DxilModule.h"
18
#include "dxc/DxilPIXPasses/DxilPIXPasses.h"
19
#include "dxc/HLSL/DxilGenerationPass.h"
20
#include "dxc/HLSL/DxilSpanAllocator.h"
21
22
#include "llvm/IR/InstIterator.h"
23
#include "llvm/IR/PassManager.h"
24
#include "llvm/Support/FormattedStream.h"
25
#include "llvm/Transforms/Utils/Local.h"
26
#include <deque>
27
28
#ifdef _WIN32
29
#include <winerror.h>
30
#endif
31
32
#include "PixPassHelpers.h"
33
34
// Keep these in sync with the same-named value in the debugger application's
35
// WinPixShaderUtils.h
36
37
constexpr uint64_t DebugBufferDumpingGroundSize = 64 * 1024;
38
// The actual max size per record is much smaller than this, but it never
39
// hurts to be generous.
40
constexpr size_t CounterOffsetBeyondUsefulData =
41
    DebugBufferDumpingGroundSize / 2;
42
43
// Keep these in sync with the same-named values in PIX's MeshShaderOutput.cpp
44
constexpr uint32_t triangleIndexIndicator = 0x1;
45
constexpr uint32_t int32ValueIndicator = 0x2;
46
constexpr uint32_t floatValueIndicator = 0x3;
47
constexpr uint32_t int16ValueIndicator = 0x4;
48
constexpr uint32_t float16ValueIndicator = 0x5;
49
50
using namespace llvm;
51
using namespace hlsl;
52
using namespace PIXPassHelpers;
53
54
class DxilPIXMeshShaderOutputInstrumentation : public ModulePass {
55
public:
56
  static char ID; // Pass identification, replacement for typeid
57
12
  explicit DxilPIXMeshShaderOutputInstrumentation() : ModulePass(ID) {}
58
12
  StringRef getPassName() const override {
59
12
    return "DXIL mesh shader output instrumentation";
60
12
  }
61
  void applyOptions(PassOptions O) override;
62
  bool runOnModule(Module &M) override;
63
64
private:
65
  CallInst *m_OutputUAV = nullptr;
66
  int m_RemainingReservedSpaceInBytes = 0;
67
  Constant *m_OffsetMask = nullptr;
68
  SmallVector<Value *, 2> m_threadUniquifier;
69
70
  uint64_t m_UAVSize = 1024 * 1024;
71
  bool m_ExpandPayload = false;
72
  uint32_t m_DispatchArgumentY = 1;
73
  uint32_t m_DispatchArgumentZ = 1;
74
75
  struct BuilderContext {
76
    Module &M;
77
    DxilModule &DM;
78
    LLVMContext &Ctx;
79
    OP *HlslOP;
80
    IRBuilder<> &Builder;
81
  };
82
83
  SmallVector<Value *, 2> insertInstructionsToCreateDisambiguationValue(
84
      IRBuilder<> &Builder, OP *HlslOP, LLVMContext &Ctx,
85
      StructType *originalPayloadStructType, Instruction *firstGetPayload);
86
  Value *reserveDebugEntrySpace(BuilderContext &BC, uint32_t SpaceInBytes);
87
  uint32_t UAVDumpingGroundOffset();
88
  Value *writeDwordAndReturnNewOffset(BuilderContext &BC, Value *TheOffset,
89
                                      Value *TheValue);
90
  template <typename... T> void Instrument(BuilderContext &BC, T... values);
91
};
92
93
12
void DxilPIXMeshShaderOutputInstrumentation::applyOptions(PassOptions O) {
94
12
  GetPassOptionUInt64(O, "UAVSize", &m_UAVSize, 1024 * 1024);
95
12
  GetPassOptionBool(O, "expand-payload", &m_ExpandPayload, 0);
96
12
  GetPassOptionUInt32(O, "dispatchArgY", &m_DispatchArgumentY, 1);
97
12
  GetPassOptionUInt32(O, "dispatchArgZ", &m_DispatchArgumentZ, 1);
98
12
}
99
100
58
uint32_t DxilPIXMeshShaderOutputInstrumentation::UAVDumpingGroundOffset() {
101
58
  return static_cast<uint32_t>(m_UAVSize - DebugBufferDumpingGroundSize);
102
58
}
103
104
Value *DxilPIXMeshShaderOutputInstrumentation::reserveDebugEntrySpace(
105
48
    BuilderContext &BC, uint32_t SpaceInBytes) {
106
  // Check the previous caller didn't reserve too much space:
107
48
  assert(m_RemainingReservedSpaceInBytes == 0);
108
109
  // Check that the caller didn't ask for so much memory that it will
110
  // overwrite the offset counter:
111
48
  assert(m_RemainingReservedSpaceInBytes < (int)CounterOffsetBeyondUsefulData);
112
113
48
  m_RemainingReservedSpaceInBytes = SpaceInBytes;
114
115
  // Insert the UAV increment instruction:
116
48
  Function *AtomicOpFunc =
117
48
      BC.HlslOP->GetOpFunc(OP::OpCode::AtomicBinOp, Type::getInt32Ty(BC.Ctx));
118
48
  Constant *AtomicBinOpcode =
119
48
      BC.HlslOP->GetU32Const((unsigned)OP::OpCode::AtomicBinOp);
120
48
  Constant *AtomicAdd =
121
48
      BC.HlslOP->GetU32Const((unsigned)DXIL::AtomicBinOpCode::Add);
122
48
  Constant *OffsetArg = BC.HlslOP->GetU32Const(UAVDumpingGroundOffset() +
123
48
                                               CounterOffsetBeyondUsefulData);
124
48
  UndefValue *UndefArg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
125
126
48
  Constant *Increment = BC.HlslOP->GetU32Const(SpaceInBytes);
127
128
48
  auto *PreviousValue = BC.Builder.CreateCall(
129
48
      AtomicOpFunc,
130
48
      {
131
48
          AtomicBinOpcode, // i32, ; opcode
132
48
          m_OutputUAV,     // %dx.types.Handle, ; resource handle
133
48
          AtomicAdd, // i32, ; binary operation code : EXCHANGE, IADD, AND, OR,
134
                     // XOR, IMIN, IMAX, UMIN, UMAX
135
48
          OffsetArg, // i32, ; coordinate c0: index in bytes
136
48
          UndefArg,  // i32, ; coordinate c1 (unused)
137
48
          UndefArg,  // i32, ; coordinate c2 (unused)
138
48
          Increment, // i32); increment value
139
48
      },
140
48
      "UAVIncResult");
141
142
48
  return BC.Builder.CreateAnd(PreviousValue, m_OffsetMask, "MaskedForUAVLimit");
143
48
}
144
145
Value *DxilPIXMeshShaderOutputInstrumentation::writeDwordAndReturnNewOffset(
146
376
    BuilderContext &BC, Value *TheOffset, Value *TheValue) {
147
148
376
  Function *StoreValue =
149
376
      BC.HlslOP->GetOpFunc(OP::OpCode::BufferStore, Type::getInt32Ty(BC.Ctx));
150
376
  Constant *StoreValueOpcode =
151
376
      BC.HlslOP->GetU32Const((unsigned)DXIL::OpCode::BufferStore);
152
376
  UndefValue *Undef32Arg = UndefValue::get(Type::getInt32Ty(BC.Ctx));
153
376
  Constant *WriteMask_X = BC.HlslOP->GetI8Const(1);
154
155
376
  (void)BC.Builder.CreateCall(
156
376
      StoreValue,
157
376
      {StoreValueOpcode, // i32 opcode
158
376
       m_OutputUAV,      // %dx.types.Handle, ; resource handle
159
376
       TheOffset,        // i32 c0: index in bytes into UAV
160
376
       Undef32Arg,       // i32 c1: unused
161
376
       TheValue,
162
376
       Undef32Arg, // unused values
163
376
       Undef32Arg, // unused values
164
376
       Undef32Arg, // unused values
165
376
       WriteMask_X});
166
167
376
  m_RemainingReservedSpaceInBytes -= sizeof(uint32_t);
168
376
  assert(m_RemainingReservedSpaceInBytes >=
169
376
         0); // or else the caller didn't reserve enough space
170
171
376
  return BC.Builder.CreateAdd(
172
376
      TheOffset,
173
376
      BC.HlslOP->GetU32Const(static_cast<unsigned int>(sizeof(uint32_t))));
174
376
}
175
176
template <typename... T>
177
void DxilPIXMeshShaderOutputInstrumentation::Instrument(BuilderContext &BC,
178
48
                                                        T... values) {
179
48
  llvm::SmallVector<llvm::Value *, 10> Values(
180
48
      {static_cast<llvm::Value *>(values)...});
181
48
  const uint32_t DwordCount = Values.size();
182
48
  llvm::Value *byteOffset =
183
48
      reserveDebugEntrySpace(BC, DwordCount * sizeof(uint32_t));
184
376
  for (llvm::Value *V : Values) {
185
376
    byteOffset = writeDwordAndReturnNewOffset(BC, byteOffset, V);
186
376
  }
187
48
}
void DxilPIXMeshShaderOutputInstrumentation::Instrument<llvm::Constant*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*>(DxilPIXMeshShaderOutputInstrumentation::BuilderContext&, llvm::Constant*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*)
Line
Count
Source
178
8
                                                        T... values) {
179
8
  llvm::SmallVector<llvm::Value *, 10> Values(
180
8
      {static_cast<llvm::Value *>(values)...});
181
8
  const uint32_t DwordCount = Values.size();
182
8
  llvm::Value *byteOffset =
183
8
      reserveDebugEntrySpace(BC, DwordCount * sizeof(uint32_t));
184
56
  for (llvm::Value *V : Values) {
185
56
    byteOffset = writeDwordAndReturnNewOffset(BC, byteOffset, V);
186
56
  }
187
8
}
void DxilPIXMeshShaderOutputInstrumentation::Instrument<llvm::Constant*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*>(DxilPIXMeshShaderOutputInstrumentation::BuilderContext&, llvm::Constant*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*, llvm::Value*)
Line
Count
Source
178
40
                                                        T... values) {
179
40
  llvm::SmallVector<llvm::Value *, 10> Values(
180
40
      {static_cast<llvm::Value *>(values)...});
181
40
  const uint32_t DwordCount = Values.size();
182
40
  llvm::Value *byteOffset =
183
40
      reserveDebugEntrySpace(BC, DwordCount * sizeof(uint32_t));
184
320
  for (llvm::Value *V : Values) {
185
320
    byteOffset = writeDwordAndReturnNewOffset(BC, byteOffset, V);
186
320
  }
187
40
}
188
189
Value *GetValueFromExpandedPayload(IRBuilder<> &Builder,
190
                                   StructType *originalPayloadStructType,
191
                                   Instruction *firstGetPayload,
192
12
                                   unsigned int offset, const char *name) {
193
12
  auto *DerefPointer = Builder.getInt32(0);
194
12
  auto *OffsetToExpandedData = Builder.getInt32(offset);
195
12
  auto *GEP = Builder.CreateGEP(
196
12
      cast<PointerType>(firstGetPayload->getType()->getScalarType())
197
12
          ->getElementType(),
198
12
      firstGetPayload, {DerefPointer, OffsetToExpandedData});
199
12
  return Builder.CreateLoad(GEP, name);
200
12
}
201
202
SmallVector<Value *, 2> DxilPIXMeshShaderOutputInstrumentation::
203
    insertInstructionsToCreateDisambiguationValue(
204
        IRBuilder<> &Builder, OP *HlslOP, LLVMContext &Ctx,
205
10
        StructType *originalPayloadStructType, Instruction *firstGetPayload) {
206
207
  // When a mesh shader is called from an amplification shader, all of the
208
  // thread id values are relative to the DispatchMesh call made by
209
  // that amplification shader. Data about what thread counts were passed
210
  // by the CPU to *CommandList::DispatchMesh are not available, but we
211
  // will have added that value to the AS->MS payload...
212
213
10
  SmallVector<Value *, 2> ret;
214
10
  Constant *Zero32Arg = HlslOP->GetU32Const(0);
215
216
10
  bool AmplificationShaderIsActive = originalPayloadStructType != nullptr;
217
218
10
  llvm::Value *ASDispatchMeshYCount = nullptr;
219
10
  llvm::Value *ASDispatchMeshZCount = nullptr;
220
10
  if (AmplificationShaderIsActive) {
221
222
4
    auto *ASThreadId = GetValueFromExpandedPayload(
223
4
        Builder, originalPayloadStructType, firstGetPayload,
224
4
        originalPayloadStructType->getStructNumElements(), "ASThreadId");
225
4
    ret.push_back(ASThreadId);
226
4
    ASDispatchMeshYCount = GetValueFromExpandedPayload(
227
4
        Builder, originalPayloadStructType, firstGetPayload,
228
4
        originalPayloadStructType->getStructNumElements() + 1,
229
4
        "ASDispatchMeshYCount");
230
4
    ASDispatchMeshZCount = GetValueFromExpandedPayload(
231
4
        Builder, originalPayloadStructType, firstGetPayload,
232
4
        originalPayloadStructType->getStructNumElements() + 2,
233
4
        "ASDispatchMeshZCount");
234
6
  } else {
235
6
    ret.push_back(Zero32Arg);
236
6
  }
237
238
10
  Constant *One32Arg = HlslOP->GetU32Const(1);
239
10
  Constant *Two32Arg = HlslOP->GetU32Const(2);
240
241
10
  auto GroupIdFunc =
242
10
      HlslOP->GetOpFunc(DXIL::OpCode::GroupId, Type::getInt32Ty(Ctx));
243
10
  Constant *Opcode = HlslOP->GetU32Const((unsigned)DXIL::OpCode::GroupId);
244
10
  auto *GroupIdX =
245
10
      Builder.CreateCall(GroupIdFunc, {Opcode, Zero32Arg}, "GroupIdX");
246
10
  auto *GroupIdY =
247
10
      Builder.CreateCall(GroupIdFunc, {Opcode, One32Arg}, "GroupIdY");
248
10
  auto *GroupIdZ =
249
10
      Builder.CreateCall(GroupIdFunc, {Opcode, Two32Arg}, "GroupIdZ");
250
251
  // flattend group number = z + y*numZ + x*numY*numZ
252
10
  if (AmplificationShaderIsActive) {
253
4
    auto *GroupYxNumZ = Builder.CreateMul(GroupIdY, ASDispatchMeshZCount);
254
4
    auto *FlatGroupNumZY = Builder.CreateAdd(GroupIdZ, GroupYxNumZ);
255
4
    auto *GroupXxNumZ = Builder.CreateMul(GroupIdX, ASDispatchMeshZCount);
256
4
    auto *GroupXxNumYZ = Builder.CreateMul(GroupXxNumZ, ASDispatchMeshYCount);
257
4
    auto *FlatGroupNum = Builder.CreateAdd(GroupXxNumYZ, FlatGroupNumZY);
258
4
    ret.push_back(FlatGroupNum);
259
6
  } else {
260
6
    auto *GroupYxNumZ =
261
6
        Builder.CreateMul(GroupIdY, HlslOP->GetU32Const(m_DispatchArgumentZ));
262
6
    auto *FlatGroupNumZY = Builder.CreateAdd(GroupIdZ, GroupYxNumZ);
263
6
    auto *GroupXxNumYZ =
264
6
        Builder.CreateMul(GroupIdX, HlslOP->GetU32Const(m_DispatchArgumentY *
265
6
                                                        m_DispatchArgumentZ));
266
6
    auto *FlatGroupNum = Builder.CreateAdd(GroupXxNumYZ, FlatGroupNumZY);
267
6
    ret.push_back(FlatGroupNum);
268
6
  }
269
270
10
  return ret;
271
10
}
272
273
12
bool DxilPIXMeshShaderOutputInstrumentation::runOnModule(Module &M) {
274
12
  DxilModule &DM = M.GetOrCreateDxilModule();
275
12
  LLVMContext &Ctx = M.getContext();
276
12
  OP *HlslOP = DM.GetOP();
277
278
12
  Type *OriginalPayloadStructType = nullptr;
279
12
  ExpandedStruct expanded = {};
280
12
  Instruction *FirstNewStructGetMeshPayload = nullptr;
281
12
  if (m_ExpandPayload) {
282
6
    Instruction *getMeshPayloadInstructions = nullptr;
283
6
    llvm::Function *entryFunction = PIXPassHelpers::GetEntryFunction(DM);
284
6
    for (inst_iterator I = inst_begin(entryFunction),
285
6
                       E = inst_end(entryFunction);
286
32
         I != E; 
++I26
) {
287
30
      if (auto *Instr = llvm::cast<Instruction>(&*I)) {
288
30
        if (hlsl::OP::IsDxilOpFuncCallInst(Instr,
289
30
                                           hlsl::OP::OpCode::GetMeshPayload)) {
290
4
          getMeshPayloadInstructions = Instr;
291
4
          Type *OriginalPayloadStructPointerType = Instr->getType();
292
4
          OriginalPayloadStructType =
293
4
              OriginalPayloadStructPointerType->getPointerElementType();
294
          // The validator assures that there is only one call to
295
          // GetMeshPayload...
296
4
          break;
297
4
        }
298
30
      }
299
30
    }
300
301
6
    if (OriginalPayloadStructType == nullptr) {
302
      // If the application used no payload, then we won't attempt to add one.
303
      // TODO: Is there a credible use case with no AS->MS payload?
304
      // PIX bug #35288335
305
2
      return false;
306
2
    }
307
308
4
    if (expanded.ExpandedPayloadStructPtrType == nullptr) {
309
4
      expanded = ExpandStructType(Ctx, OriginalPayloadStructType);
310
4
    }
311
312
4
    if (getMeshPayloadInstructions != nullptr) {
313
4
      llvm::Function *OriginalGetMeshPayloadFunction =
314
4
          cast<CallInst>(getMeshPayloadInstructions)->getCalledFunction();
315
316
4
      Function *DxilFunc = HlslOP->GetOpFunc(
317
4
          OP::OpCode::GetMeshPayload, expanded.ExpandedPayloadStructPtrType);
318
4
      Constant *opArg =
319
4
          HlslOP->GetU32Const((unsigned)OP::OpCode::GetMeshPayload);
320
4
      IRBuilder<> Builder(getMeshPayloadInstructions);
321
4
      Value *args[] = {opArg};
322
4
      Instruction *payload = Builder.CreateCall(DxilFunc, args);
323
324
4
      if (FirstNewStructGetMeshPayload == nullptr) {
325
4
        FirstNewStructGetMeshPayload = payload;
326
4
      }
327
328
4
      ReplaceAllUsesOfInstructionWithNewValueAndDeleteInstruction(
329
4
          getMeshPayloadInstructions, payload,
330
4
          expanded.ExpandedPayloadStructType);
331
4
      PIXPassHelpers::eraseIfUnused(DM, OriginalGetMeshPayloadFunction);
332
4
    }
333
4
  }
334
335
10
  Instruction *firstInsertionPt =
336
10
      dxilutil::FirstNonAllocaInsertionPt(GetEntryFunction(DM));
337
10
  IRBuilder<> Builder(firstInsertionPt);
338
339
10
  BuilderContext BC{M, DM, Ctx, HlslOP, Builder};
340
341
10
  m_OffsetMask = BC.HlslOP->GetU32Const(UAVDumpingGroundOffset() - 1);
342
343
10
  m_OutputUAV = CreateUAVOnceForModule(DM, Builder, 0, "PIX_DebugUAV_Handle");
344
345
10
  if (FirstNewStructGetMeshPayload == nullptr) {
346
6
    Instruction *firstInsertionPt = dxilutil::FirstNonAllocaInsertionPt(
347
6
        PIXPassHelpers::GetEntryFunction(DM));
348
6
    IRBuilder<> Builder(firstInsertionPt);
349
6
    m_threadUniquifier = insertInstructionsToCreateDisambiguationValue(
350
6
        Builder, HlslOP, Ctx, nullptr, nullptr);
351
6
  } else {
352
4
    IRBuilder<> Builder(FirstNewStructGetMeshPayload->getNextNode());
353
4
    m_threadUniquifier = insertInstructionsToCreateDisambiguationValue(
354
4
        Builder, HlslOP, Ctx, cast<StructType>(OriginalPayloadStructType),
355
4
        FirstNewStructGetMeshPayload);
356
4
  }
357
358
10
  Function *EmitIndicesFunction =
359
10
      HlslOP->GetOpFunc(DXIL::OpCode::EmitIndices, Type::getVoidTy(Ctx));
360
10
  auto FunctionUses = EmitIndicesFunction->uses();
361
18
  for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) {
362
8
    auto &FunctionUse = *FI++;
363
8
    auto FunctionUser = FunctionUse.getUser();
364
365
8
    auto Call = cast<CallInst>(FunctionUser);
366
367
8
    IRBuilder<> Builder2(Call);
368
8
    BuilderContext BC2{M, DM, Ctx, HlslOP, Builder2};
369
370
8
    Instrument(BC2, BC2.HlslOP->GetI32Const(triangleIndexIndicator),
371
8
               m_threadUniquifier[0], m_threadUniquifier[1],
372
8
               Call->getOperand(1), Call->getOperand(2), Call->getOperand(3),
373
8
               Call->getOperand(4));
374
8
  }
375
376
10
  struct OutputType {
377
10
    Type *type;
378
10
    uint32_t tag;
379
10
  };
380
10
  SmallVector<OutputType, 4> StoreVertexOutputOverloads{
381
10
      {Type::getInt32Ty(Ctx), int32ValueIndicator},
382
10
      {Type::getInt16Ty(Ctx), int16ValueIndicator},
383
10
      {Type::getFloatTy(Ctx), floatValueIndicator},
384
10
      {Type::getHalfTy(Ctx), float16ValueIndicator}};
385
10
  SmallVector<Function *, 4> StoreVertexOutputFunctions;
386
387
40
  for (auto const &Overload : StoreVertexOutputOverloads) {
388
40
    Function *StoreVertexOutputFunction =
389
40
        HlslOP->GetOpFunc(DXIL::OpCode::StoreVertexOutput, Overload.type);
390
40
    StoreVertexOutputFunctions.push_back(StoreVertexOutputFunction);
391
40
    FunctionUses = StoreVertexOutputFunction->uses();
392
80
    for (auto FI = FunctionUses.begin(); FI != FunctionUses.end();) {
393
40
      auto &FunctionUse = *FI++;
394
40
      auto FunctionUser = FunctionUse.getUser();
395
396
40
      auto Call = cast<CallInst>(FunctionUser);
397
398
40
      IRBuilder<> Builder2(Call);
399
40
      BuilderContext BC2{M, DM, Ctx, HlslOP, Builder2};
400
401
      // Expand column index to 32 bits:
402
40
      auto ColumnIndex = BC2.Builder.CreateCast(
403
40
          Instruction::ZExt, Call->getOperand(3), Type::getInt32Ty(Ctx));
404
405
      // Coerce actual value to int32
406
40
      Value *CoercedValue = Call->getOperand(4);
407
408
40
      if (Overload.tag == floatValueIndicator) {
409
40
        CoercedValue = BC2.Builder.CreateCast(
410
40
            Instruction::BitCast, CoercedValue, Type::getInt32Ty(Ctx));
411
40
      } else 
if (0
Overload.tag == float16ValueIndicator0
) {
412
0
        auto *HalfInt = BC2.Builder.CreateCast(
413
0
            Instruction::BitCast, CoercedValue, Type::getInt16Ty(Ctx));
414
415
0
        CoercedValue = BC2.Builder.CreateCast(Instruction::ZExt, HalfInt,
416
0
                                              Type::getInt32Ty(Ctx));
417
0
      } else if (Overload.tag == int16ValueIndicator) {
418
0
        CoercedValue = BC2.Builder.CreateCast(Instruction::ZExt, CoercedValue,
419
0
                                              Type::getInt32Ty(Ctx));
420
0
      }
421
422
40
      Instrument(BC2, BC2.HlslOP->GetI32Const(Overload.tag),
423
40
                 m_threadUniquifier[0], m_threadUniquifier[1],
424
40
                 Call->getOperand(1), Call->getOperand(2), ColumnIndex,
425
40
                 CoercedValue, Call->getOperand(5));
426
40
    }
427
40
  }
428
429
40
  for (Function *StoreVertexOutputFunction : StoreVertexOutputFunctions) {
430
40
    PIXPassHelpers::eraseIfUnused(DM, StoreVertexOutputFunction);
431
40
  }
432
10
  PIXPassHelpers::eraseIfUnused(DM, EmitIndicesFunction);
433
434
10
  DM.ReEmitDxilResources();
435
436
10
  return true;
437
12
}
438
439
char DxilPIXMeshShaderOutputInstrumentation::ID = 0;
440
441
0
ModulePass *llvm::createDxilDxilPIXMeshShaderOutputInstrumentation() {
442
0
  return new DxilPIXMeshShaderOutputInstrumentation();
443
0
}
444
445
INITIALIZE_PASS(DxilPIXMeshShaderOutputInstrumentation,
446
                "hlsl-dxil-pix-meshshader-output-instrumentation",
447
                "DXIL mesh shader output instrumentation for PIX", false, false)