@@ -32,23 +32,22 @@ RDOC_CONFIG(bool, D3D12_DXILShaderDebugger_Logging, false,
3232 " Debug logging for the DXIL shader debugger" );
3333
3434// TODO: Remove asserts using ^
35- // TODO: Support global shared memory pointers created as Constants using getElementPtr inside the constant
35+ // TODO: Extend support for Compound Constants: arithmetic, logical ops
3636// TODO: re-implement callstacks using scopes and inlined at metadata
3737// TODO: Assert m_Block in ThreadState is correct per instruction
3838// TODO: Automatically execute phi instructions after a branch
3939// TODO: Support MSAA
4040// TODO: Support UAVs with counter
41- // TODO: Extend support for Compound Constants: Vector, GetElementPtr
42- // TODO: Extend debug data parsing for DW_TAG_array_type for the base element type
43- // TODO: Extend debug data parsing: N-dimensional arrays, mapping covers whole sub-array
41+ // TODO: Extend debug data parsing: DW_TAG_array_type for the base element type
42+ // TODO: Extend debug data parsing: N-dimensional arrays, mapping covers whole sub-array
4443
4544// Notes:
4645// The phi node capture variables are not shown in the UI
4746// LLVM poison values are not supported
4847// Does it make sense to use ShaderVariable GPU pointers
4948// ExtractVal: only handles one index
5049// ComputeDXILTypeByteSize does not consider byte alignment
51- // GetElementPtr: only handles a two indexes
50+ // GetElementPtr: only handles two indexes
5251// Sample*: Argument 10 which is called Clamp is not used
5352// ShuffleVector: mask entries might be undef meaning "don't care"
5453
@@ -94,6 +93,36 @@ inline bool RDCISNORMAL(double input)
9493using namespace DXIL ;
9594using namespace DXDebug ;
9695
96+ const uint32_t POINTER_MAGIC = 0xBEAFDEAF ;
97+
98+ static void EncodePointer (DXILDebug::Id ptrId, uint64_t offset, uint64_t size, ShaderVariable &var)
99+ {
100+ var.type = VarType::GPUPointer;
101+ var.value .u32v [0 ] = ptrId;
102+ var.value .u32v [1 ] = POINTER_MAGIC;
103+ var.value .u64v [1 ] = offset;
104+ var.value .u64v [2 ] = size;
105+ }
106+
107+ static bool DecodePointer (DXILDebug::Id &ptrId, uint64_t &offset, uint64_t &size,
108+ const ShaderVariable &var)
109+ {
110+ if (var.type != VarType::GPUPointer)
111+ {
112+ RDCERR (" Calling DecodePointer on non-pointer type %s" , ToStr (var.type ).c_str ());
113+ return false ;
114+ }
115+ if (var.value .u32v [1 ] != POINTER_MAGIC)
116+ {
117+ RDCERR (" Calling DecodePointer on non encoded pointer type %u" , var.value .u32v [1 ]);
118+ return false ;
119+ }
120+ ptrId = var.value .u32v [0 ];
121+ offset = var.value .u64v [1 ];
122+ size = var.value .u64v [2 ];
123+ return true ;
124+ }
125+
97126static bool OperationFlushing (const Operation op, DXOp dxOpCode)
98127{
99128 if (dxOpCode != DXOp::NumOpCodes)
@@ -848,13 +877,98 @@ static bool ConvertDXILConstantToShaderVariable(const Constant *constant, Shader
848877 const rdcarray<DXIL::Value *> &members = constant->getMembers ();
849878 value = members[0 ];
850879 }
851- if (constant->op == Operation::GetElementPtr )
880+ if (constant->op == Operation::NoOp )
852881 {
853- RDCLOG ( " Unsupported Constant Op %s " , ToStr (constant-> op ). c_str ( ));
882+ RDCASSERT ( ConvertDXILValueToShaderValue (value, var. type , 0 , var. value ));
854883 return true ;
855884 }
856- RDCASSERT (ConvertDXILValueToShaderValue (value, var.type , 0 , var.value ));
857- return true ;
885+ else if (constant->op == Operation::GetElementPtr)
886+ {
887+ const rdcarray<DXIL::Value *> &members = constant->getMembers ();
888+ RDCASSERT (members.size () >= 3 , members.size ());
889+ value = members[0 ];
890+ const GlobalVar *gv = cast<GlobalVar>(value);
891+ if (!gv)
892+ {
893+ RDCERR (" Constant GetElementPtr first member is not a GlobalVar" );
894+ return false ;
895+ }
896+ const DXIL::Type *elementType = gv->type ;
897+ if (elementType->type != Type::TypeKind::Pointer)
898+ {
899+ RDCERR (" Constant GetElementPtr global variable is not a Pointer" );
900+ return false ;
901+ }
902+ elementType = elementType->inner ;
903+ VarType baseType = ConvertDXILTypeToVarType (elementType);
904+ uint32_t elementSize = GetElementByteSize (baseType);
905+ uint32_t countElems = RDCMAX (1U , elementType->elemCount );
906+ uint64_t size = countElems * GetElementByteSize (baseType);
907+
908+ DXILDebug::Id ptrId = gv->ssaId ;
909+ // members[1..] : indices 1...N
910+ rdcarray<uint64_t > indexes;
911+ indexes.reserve (members.size () - 1 );
912+ for (uint32_t a = 1 ; a < members.size (); ++a)
913+ {
914+ value = members[a];
915+ VarType argType = ConvertDXILTypeToVarType (value->type );
916+ ShaderValue argValue;
917+ memset (&argValue, 0 , sizeof (argValue));
918+ RDCASSERT (ConvertDXILValueToShaderValue (value, argType, 0 , argValue));
919+ indexes.push_back (argValue.u64v [0 ]);
920+ }
921+ // Index 0 is in ptr terms as if pointer was an array of pointers
922+ RDCASSERTEQUAL (indexes[0 ], 0 );
923+ uint64_t offset = 0 ;
924+
925+ if (indexes.size () > 1 )
926+ offset += indexes[1 ] * elementSize;
927+ RDCASSERT (indexes.size () <= 2 );
928+ // Encode the pointer allocation: ptrId, offset, size
929+ EncodePointer (ptrId, offset, size, var);
930+ return true ;
931+ }
932+ // case Operation::Trunc:
933+ // case Operation::ZExt:
934+ // case Operation::SExt:
935+ // case Operation::FToU:
936+ // case Operation::FToS:
937+ // case Operation::UToF:
938+ // case Operation::SToF:
939+ // case Operation::FPTrunc:
940+ // case Operation::FPExt:
941+ // case Operation::PtrToI:
942+ // case Operation::IToPtr:
943+ // case Operation::Bitcast:
944+ // case Operation::AddrSpaceCast:
945+ // case Operation::Select:
946+ // case Operation::IEqual:
947+ // plus other integer comparisons
948+ // case Operation::FOrdEqual:
949+ // plus other fp comparisons
950+ // case Operation::ExtractElement:
951+ // case Operation::ExtractVal:
952+ // case Operation::FAdd:
953+ // case Operation::FSub:
954+ // case Operation::FMul:
955+ // case Operation::FDiv:
956+ // case Operation::FRem:
957+ // case Operation::Add:
958+ // case Operation::Sub:
959+ // case Operation::Mul:
960+ // case Operation::UDiv:
961+ // case Operation::SDiv:
962+ // case Operation::URem:
963+ // case Operation::SRem:
964+ // case Operation::ShiftLeft:
965+ // case Operation::LogicalShiftRight:
966+ // case Operation::ArithShiftRight:
967+ // case Operation::And:
968+ // case Operation::Or:
969+ // case Operation::Xor:
970+ RDCLOG (" Unsupported Constant Op %s" , ToStr (constant->op ).c_str ());
971+ return false ;
858972 }
859973 return false ;
860974 }
@@ -4152,7 +4266,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
41524266 // Store(ptr, value)
41534267 Id baseMemoryId = DXILDebug::INVALID_ID;
41544268 void *baseMemoryBackingPtr = NULL ;
4155- size_t allocSize = 0 ;
4269+ uint64_t allocSize = 0 ;
41564270 void *allocMemoryBackingPtr = NULL ;
41574271 Id ptrId = GetArgumentId (0 );
41584272 if (ptrId == DXILDebug::INVALID_ID)
@@ -4267,8 +4381,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
42674381 backingMemory += offset;
42684382 m_Memory.m_AllocPointers [resultId] = {ptrId, backingMemory, size};
42694383
4270- RDCASSERT (size < sizeof (result. value . f32v ));
4271- if (size < sizeof (ShaderValue))
4384+ RDCASSERT (size <= sizeof (ShaderValue ));
4385+ if (size <= sizeof (ShaderValue))
42724386 memcpy (&result.value , backingMemory, size);
42734387 else
42744388 RDCERR (" Size %u too large MAX %u for GetElementPtr" , size, sizeof (ShaderValue));
@@ -5133,7 +5247,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
51335247 case Operation::AtomicUMin:
51345248 case Operation::CompareExchange:
51355249 {
5136- size_t allocSize = 0 ;
5250+ uint64_t allocSize = 0 ;
51375251 void *allocMemoryBackingPtr = NULL ;
51385252 void *baseMemoryBackingPtr = NULL ;
51395253 Id baseMemoryId = DXILDebug::INVALID_ID;
@@ -5617,7 +5731,7 @@ void ThreadState::MarkResourceAccess(const rdcstr &name, const ResourceReference
56175731 accessed.push_back (resRefInfo.binding );
56185732}
56195733
5620- void ThreadState::UpdateBackingMemoryFromVariable (void *ptr, size_t &allocSize,
5734+ void ThreadState::UpdateBackingMemoryFromVariable (void *ptr, uint64_t &allocSize,
56215735 const ShaderVariable &var)
56225736{
56235737 // Memory copy from value to backing memory
@@ -5626,7 +5740,7 @@ void ThreadState::UpdateBackingMemoryFromVariable(void *ptr, size_t &allocSize,
56265740 RDCASSERTEQUAL (var.rows , 1 );
56275741 const size_t elementSize = GetElementByteSize (var.type );
56285742 RDCASSERT (elementSize <= allocSize);
5629- RDCASSERT (elementSize < sizeof (var. value . f32v ));
5743+ RDCASSERT (elementSize <= sizeof (ShaderValue ));
56305744 const size_t varMemSize = var.columns * elementSize;
56315745 memcpy (ptr, &var.value .f32v [0 ], varMemSize);
56325746 allocSize -= varMemSize;
@@ -5654,7 +5768,7 @@ void ThreadState::UpdateMemoryVariableFromBackingMemory(Id memoryId, const void
56545768 {
56555769 RDCASSERTEQUAL (baseMemory.rows , 1 );
56565770 RDCASSERTEQUAL (baseMemory.columns , 1 );
5657- if (elementSize < sizeof (ShaderValue))
5771+ if (elementSize <= sizeof (ShaderValue))
56585772 memcpy (&baseMemory.value , src, elementSize);
56595773 else
56605774 RDCERR (" Updating MemoryVariable elementSize %u too large max %u" , elementSize,
@@ -5664,7 +5778,7 @@ void ThreadState::UpdateMemoryVariableFromBackingMemory(Id memoryId, const void
56645778 {
56655779 for (uint32_t i = 0 ; i < baseMemory.members .size (); ++i)
56665780 {
5667- if (elementSize < sizeof (ShaderValue))
5781+ if (elementSize <= sizeof (ShaderValue))
56685782 memcpy (&baseMemory.members [i].value , src, elementSize);
56695783 else
56705784 RDCERR (" Updating MemoryVariable member %u elementSize %u too large max %u" , i, elementSize,
@@ -6131,6 +6245,7 @@ ShaderValue ThreadState::DDY(bool fine, Operation opCode, DXOp dxOpCode,
61316245 }
61326246
61336247 ShaderValue ret;
6248+ memset (&ret, 0 , sizeof (ret));
61346249 ShaderVariable a;
61356250 ShaderVariable b;
61366251 RDCASSERT (quad[index + 2 ].GetShaderVariable (dxilValue, opCode, dxOpCode, a));
@@ -7633,10 +7748,6 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76337748 MemoryTracking &globalMemory = m_GlobalState.memory ;
76347749 for (const DXIL::GlobalVar *gv : m_Program->m_GlobalVars )
76357750 {
7636- // Ignore DXIL global variables which start with "dx.nothing."
7637- if (gv->name .beginsWith (" dx.nothing." ))
7638- continue ;
7639-
76407751 GlobalVariable globalVar;
76417752 rdcstr n = DXBC::BasicDemangle (gv->name );
76427753 DXIL::SanitiseName (n);
@@ -7656,7 +7767,7 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76567767 RDCASSERT (itAlloc != globalMemory.m_Allocs .end ());
76577768 const MemoryTracking::Alloc &alloc = itAlloc->second ;
76587769 void *allocMemoryBackingPtr = alloc.backingMemory ;
7659- size_t allocSize = alloc.size ;
7770+ uint64_t allocSize = alloc.size ;
76607771 state.UpdateBackingMemoryFromVariable (allocMemoryBackingPtr, allocSize, globalVar.var );
76617772 RDCASSERTEQUAL (allocSize, 0 );
76627773 }
@@ -7672,6 +7783,8 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76727783 {
76737784 for (Instruction *inst : f->instructions )
76747785 {
7786+ if (IsNopInstruction (*inst))
7787+ continue ;
76757788 for (const Value *arg : inst->args )
76767789 {
76777790 if (arg && arg->kind () == ValueKind::Constant)
@@ -7684,14 +7797,44 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
76847797 }
76857798
76867799 GlobalConstant constantVar;
7687- ConvertDXILTypeToShaderVariable (c-> type , constantVar.var ) ;
7688- ConvertDXILConstantToShaderVariable (c, constantVar. var );
7689- constantVar. var . name = m_Program-> GetArgumentName (c );
7690- constantVar. id = c-> ssaId ;
7800+ ShaderVariable &var = constantVar.var ;
7801+ ConvertDXILTypeToShaderVariable (c-> type , var);
7802+ ConvertDXILConstantToShaderVariable (c, var );
7803+ var. name = m_Program-> GetArgumentName (c) ;
76917804 Id id = c->ssaId ;
76927805 RDCASSERTNOTEQUAL (id, DXILDebug::INVALID_ID);
7806+ constantVar.id = id;
7807+ if (var.type == VarType::GPUPointer)
7808+ {
7809+ Id ptrId;
7810+ uint64_t offset;
7811+ uint64_t size;
7812+ // Decode the pointer allocation: ptrId, offset, size
7813+ RDCASSERT (DecodePointer (ptrId, offset, size, var));
7814+
7815+ auto it = globalMemory.m_Allocs .find (ptrId);
7816+ if (it != globalMemory.m_Allocs .end ())
7817+ {
7818+ const MemoryTracking::Alloc &alloc = it->second ;
7819+ uint8_t *backingMemory = (uint8_t *)alloc.backingMemory ;
7820+ RDCASSERT (offset + size <= alloc.size );
7821+ if (offset + size <= alloc.size )
7822+ {
7823+ backingMemory += offset;
7824+ globalMemory.m_AllocPointers [id] = {ptrId, backingMemory, size};
7825+ }
7826+ else
7827+ {
7828+ RDCERR (" Invalid GEP offset %u size %u for alloc size %u" , offset, size, alloc.size );
7829+ }
7830+ }
7831+ else
7832+ {
7833+ RDCERR (" Failed to find allocation for Constant global variable pointer %u" , ptrId);
7834+ }
7835+ }
76937836 m_GlobalState.constants .push_back (constantVar);
7694- m_LiveGlobals[constantVar. id ] = true ;
7837+ m_LiveGlobals[id] = true ;
76957838 }
76967839 }
76977840 }
0 commit comments