in renderdoc/driver/shaders/dxil/dxil_disassemble.cpp [2029:3986]
void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
{
DXIL::dxcStyleFormatting = false;
DXIL::dxilIdentifier = '_';
m_Disassembly.clear();
m_DisassemblyInstructionLine = 1;
m_Disassembly += StringFormat::Fmt("; %s Shader, compiled under SM%u.%u",
shaderNames[int(m_Type)], m_Major, m_Minor);
DisassemblyAddNewLine(2);
// TODO: output structs using named meta data if it exists
m_Disassembly += DisassembleTypes(m_DisassemblyInstructionLine);
m_Disassembly += DisassembleGlobalVars(m_DisassemblyInstructionLine);
const char *swizzle = "xyzw";
rdcarray<EntryPointInterface> entryPoints;
FetchEntryPointInterfaces(entryPoints);
for(size_t i = 0; i < m_Functions.size(); i++)
{
const Function &func = *m_Functions[i];
m_Accum.processFunction(m_Functions[i]);
if(func.external)
continue;
if(!func.external)
{
EntryPointInterface *entryPoint = NULL;
for(size_t e = 0; e < entryPoints.size(); ++e)
{
if(func.name == entryPoints[e].name)
{
entryPoint = &entryPoints[e];
break;
}
}
// Display inputs/outputs and resource
if(entryPoint)
{
bool needBlankLine = false;
if(!entryPoint->inputs.empty())
{
m_Disassembly += "Inputs";
DisassemblyAddNewLine();
for(size_t j = 0; j < entryPoint->inputs.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::Signature &sig = entryPoint->inputs[j];
VarType varType = VarTypeForComponentType(sig.type);
m_Disassembly += " ";
m_Disassembly += ToStr(varType).c_str();
if(sig.cols > 1)
m_Disassembly += ToStr(sig.cols);
if(reflection && sig.rows == 1)
{
const SigParameter &sigParam = reflection->InputSig[j];
if(sigParam.semanticName == sig.name)
{
sig.name = sigParam.semanticIdxName;
}
}
m_Disassembly += " " + sig.name;
if(sig.rows > 1)
m_Disassembly += "[" + ToStr(sig.rows) + "]";
m_Disassembly += ";";
needBlankLine = true;
}
DisassemblyAddNewLine();
}
if(!entryPoint->outputs.empty())
{
if(needBlankLine)
{
DisassemblyAddNewLine();
needBlankLine = false;
}
m_Disassembly += "Outputs";
DisassemblyAddNewLine();
for(size_t j = 0; j < entryPoint->outputs.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::Signature &sig = entryPoint->outputs[j];
VarType varType = VarTypeForComponentType(sig.type);
m_Disassembly += " ";
m_Disassembly += ToStr(varType).c_str();
if(sig.cols > 1)
m_Disassembly += ToStr(sig.cols);
if(reflection && sig.rows == 1)
{
const SigParameter &sigParam = reflection->OutputSig[j];
if(sigParam.semanticName == sig.name)
sig.name = sigParam.semanticIdxName;
}
m_Disassembly += " " + sig.name;
if(sig.rows > 1)
m_Disassembly += "[" + ToStr(sig.rows) + "]";
m_Disassembly += ";";
needBlankLine = true;
}
DisassemblyAddNewLine();
}
if(!entryPoint->srvs.empty())
{
for(size_t j = 0; j < entryPoint->srvs.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::SRV &srv = entryPoint->srvs[j];
if(srv.name.empty() && reflection)
{
for(DXBC::ShaderInputBind bind : reflection->SRVs)
{
if((bind.space == srv.space) && (bind.reg == srv.regBase) &&
(bind.bindCount == srv.regCount))
srv.name = bind.name;
}
}
m_Disassembly += GetResourceShapeName(srv.shape, false);
m_Disassembly += "<" + GetResourceTypeName(srv.type) + ">";
m_Disassembly += " " + srv.name;
if(srv.regCount > 1)
{
m_Disassembly += "[";
if(srv.regCount != ~0U)
m_Disassembly += ToStr(srv.regCount);
m_Disassembly += "]";
}
m_Disassembly +=
" : register(t" + ToStr(srv.regBase) + ", space" + ToStr(srv.space) + ")";
m_Disassembly += ";";
needBlankLine = true;
}
DisassemblyAddNewLine();
}
if(!entryPoint->uavs.empty())
{
for(size_t j = 0; j < entryPoint->uavs.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::UAV &uav = entryPoint->uavs[j];
if(uav.name.empty() && reflection)
{
for(DXBC::ShaderInputBind bind : reflection->UAVs)
{
if((bind.space == uav.space) && (bind.reg == uav.regBase) &&
(bind.bindCount == uav.regCount))
uav.name = bind.name;
}
}
m_Disassembly += GetResourceShapeName(uav.shape, true);
m_Disassembly += "<" + GetResourceTypeName(uav.type) + ">";
m_Disassembly += " " + uav.name;
if(uav.regCount > 1)
{
m_Disassembly += "[";
if(uav.regCount != ~0U)
m_Disassembly += ToStr(uav.regCount);
m_Disassembly += "]";
}
m_Disassembly +=
" : register(u" + ToStr(uav.regBase) + ", space" + ToStr(uav.space) + ")";
m_Disassembly += ";";
needBlankLine = true;
}
DisassemblyAddNewLine();
}
if(!entryPoint->cbuffers.empty())
{
for(size_t j = 0; j < entryPoint->cbuffers.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::CBuffer &cbuffer = entryPoint->cbuffers[j];
if(reflection)
{
for(size_t cbIdx = 0; cbIdx < reflection->CBuffers.size(); ++cbIdx)
{
const DXBC::CBuffer &cb = reflection->CBuffers[cbIdx];
if((cb.space == cbuffer.space) && (cb.reg == cbuffer.regBase) &&
(cb.bindCount == cbuffer.regCount))
{
if(cbuffer.name.empty())
cbuffer.name = cb.name;
if(!cbuffer.cbufferRefl)
cbuffer.cbufferRefl = &reflection->CBuffers[cbIdx];
}
}
}
m_Disassembly += "cbuffer " + cbuffer.name;
if(cbuffer.regCount > 1)
{
m_Disassembly += "[";
if(cbuffer.regCount != ~0U)
m_Disassembly += ToStr(cbuffer.regCount);
m_Disassembly += "]";
}
m_Disassembly +=
" : register(b" + ToStr(cbuffer.regBase) + ", space" + ToStr(cbuffer.space) + ")";
if(cbuffer.cbufferRefl)
{
if(!cbuffer.cbufferRefl->variables.empty())
{
DisassemblyAddNewLine();
m_Disassembly += "{";
DisassemblyAddNewLine();
for(const DXBC::CBufferVariable &cbVar : cbuffer.cbufferRefl->variables)
{
const DXBC::CBufferVariableType &cbType = cbVar.type;
m_Disassembly += " ";
m_Disassembly += cbType.name;
m_Disassembly += " " + cbVar.name;
if(cbType.elements > 1)
m_Disassembly += "[" + ToStr(cbType.elements) + "]";
m_Disassembly += ";";
DisassemblyAddNewLine();
}
m_Disassembly += "};";
DisassemblyAddNewLine();
}
}
needBlankLine = true;
}
}
if(!entryPoint->samplers.empty())
{
for(size_t j = 0; j < entryPoint->samplers.size(); ++j)
{
if(needBlankLine)
DisassemblyAddNewLine();
EntryPointInterface::Sampler &sampler = entryPoint->samplers[j];
if(sampler.name.empty() && reflection)
{
for(DXBC::ShaderInputBind s : reflection->Samplers)
{
if((s.space == sampler.space) && (s.reg == sampler.regBase) &&
(s.bindCount == sampler.regCount))
sampler.name = s.name;
}
}
m_Disassembly += GetResourceTypeName(sampler.type);
m_Disassembly += " " + sampler.name;
if(sampler.regCount > 1)
{
m_Disassembly += "[";
if(sampler.regCount != ~0U)
m_Disassembly += ToStr(sampler.regCount);
m_Disassembly += "]";
}
m_Disassembly +=
" : register(s" + ToStr(sampler.regBase) + ", space" + ToStr(sampler.space) + ")";
m_Disassembly += ";";
needBlankLine = true;
}
DisassemblyAddNewLine();
}
if(needBlankLine)
DisassemblyAddNewLine();
}
if(func.internalLinkage)
m_Disassembly += "internal ";
m_Disassembly +=
func.type->declFunction("@" + escapeStringIfNeeded(func.name), func.args, func.attrs);
if(func.comdatIdx < m_Comdats.size())
m_Disassembly += StringFormat::Fmt(
" comdat($%s)", escapeStringIfNeeded(m_Comdats[func.comdatIdx].second).c_str());
if(func.align)
m_Disassembly += StringFormat::Fmt(" align %u", (1U << func.align) >> 1);
if(func.attrs && func.attrs->functionSlot)
m_Disassembly +=
StringFormat::Fmt(" #%u", m_FuncAttrGroups.indexOf(func.attrs->functionSlot));
DisassemblyAddNewLine();
m_Disassembly += "{";
DisassemblyAddNewLine();
std::map<rdcstr, ResourceHandle> resHandles;
std::map<rdcstr, rdcstr> ssaAliases;
size_t curBlock = 0;
// if the first block has a name, use it
if(!func.blocks[curBlock]->name.empty())
{
m_Disassembly +=
StringFormat::Fmt("%s:", escapeStringIfNeeded(func.blocks[curBlock]->name).c_str());
DisassemblyAddNewLine(2);
}
for(size_t funcIdx = 0; funcIdx < func.instructions.size(); funcIdx++)
{
Instruction &inst = *func.instructions[funcIdx];
inst.disassemblyLine = m_DisassemblyInstructionLine;
rdcstr lineStr;
if(!inst.type->isVoid())
{
lineStr += inst.type->toString();
lineStr += " ";
}
rdcstr resultIdStr;
if(!inst.getName().empty())
resultIdStr = StringFormat::Fmt("%c%s", DXIL::dxilIdentifier,
escapeStringIfNeeded(inst.getName()).c_str());
else if(inst.slot != ~0U)
resultIdStr = StringFormat::Fmt("%c%s", DXIL::dxilIdentifier, ToStr(inst.slot).c_str());
if(!resultIdStr.empty())
lineStr += resultIdStr + " = ";
bool showDxFuncName = false;
rdcstr commentStr;
switch(inst.op)
{
case Operation::NoOp: lineStr += "??? "; break;
case Operation::Call:
{
rdcstr funcCallName = inst.getFuncCall()->name;
showDxFuncName = funcCallName.beginsWith("dx.op");
if(showDxFuncName && funcCallName.beginsWith("dx.op.loadInput"))
{
// LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::loadInput);
rdcstr name;
rdcstr rowStr;
rdcstr componentStr;
uint32_t inputIdx;
uint32_t rowIdx;
bool hasRowIdx = getival<uint32_t>(inst.args[2], rowIdx);
if(getival<uint32_t>(inst.args[1], inputIdx))
{
EntryPointInterface::Signature &sig = entryPoint->inputs[inputIdx];
name = sig.name;
if(hasRowIdx)
{
if(sig.rows > 1)
rowStr = "[" + ToStr(rowIdx) + "]";
}
}
else
{
name = ArgToString(inst.args[1], false);
rowStr = "[";
if(hasRowIdx)
rowStr += ToStr(rowIdx);
else
rowStr += ArgToString(inst.args[2], false);
rowStr += +"]";
}
uint32_t componentIdx;
if(getival<uint32_t>(inst.args[3], componentIdx))
componentStr = StringFormat::Fmt("%c", swizzle[componentIdx & 0x3]);
else
componentStr = ArgToString(inst.args[3], false);
lineStr += "<IN>." + name + rowStr + "." + componentStr;
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.storeOutput"))
{
// StoreOutput(outputSigId,rowIndex,colIndex,value)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::storeInput);
rdcstr name;
rdcstr rowStr;
rdcstr componentStr;
uint32_t outputIdx;
uint32_t rowIdx;
bool hasRowIdx = getival<uint32_t>(inst.args[2], rowIdx);
if(getival<uint32_t>(inst.args[1], outputIdx))
{
EntryPointInterface::Signature &sig = entryPoint->outputs[outputIdx];
name = sig.name;
if(hasRowIdx)
{
if(sig.rows > 1)
rowStr = "[" + ToStr(rowIdx) + "]";
}
}
else
{
name = ArgToString(inst.args[1], false);
rowStr = "[";
if(hasRowIdx)
rowStr += ToStr(rowIdx);
else
rowStr += ArgToString(inst.args[2], false);
rowStr += +"]";
}
uint32_t componentIdx;
if(getival<uint32_t>(inst.args[3], componentIdx))
componentStr = StringFormat::Fmt("%c", swizzle[componentIdx & 0x3]);
else
componentStr = ArgToString(inst.args[3], false);
lineStr += "<OUT>." + name + rowStr + "." + componentStr;
lineStr += " = " + ArgToString(inst.args[4], false);
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.createHandle"))
{
// CreateHandle(resourceClass,rangeId,index,nonUniformIndex)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::createHandle);
rdcstr handleStr = resultIdStr;
ResourceClass resClass;
rdcstr resName;
uint32_t resIndex;
bool hasResIndex = getival<uint32_t>(inst.args[2], resIndex);
if(getival<ResourceClass>(inst.args[1], resClass))
{
if(hasResIndex)
{
ResourceHandle resHandle;
bool validRes = true;
switch(resClass)
{
case ResourceClass::SRV:
resName = entryPoint->srvs[resIndex].name;
resHandle.srv = &entryPoint->srvs[resIndex];
break;
case ResourceClass::UAV:
resName = entryPoint->uavs[resIndex].name;
resHandle.uav = &entryPoint->uavs[resIndex];
break;
case ResourceClass::CBuffer:
resName = entryPoint->cbuffers[resIndex].name;
resHandle.cbuffer = &entryPoint->cbuffers[resIndex];
break;
case ResourceClass::Sampler:
resName = entryPoint->samplers[resIndex].name;
resHandle.sampler = &entryPoint->samplers[resIndex];
break;
default:
validRes = false;
resName = "INVALID RESOURCE CLASS";
break;
};
if(validRes)
{
resHandle.name = resName;
resHandle.resourceClass = resClass;
resHandle.resourceIndex = resIndex;
resHandles[handleStr] = resHandle;
ssaAliases[handleStr] = resName;
}
uint32_t index;
if(getival<uint32_t>(inst.args[3], index))
{
if(index != resIndex)
commentStr += " index = " + ToStr(index);
}
}
else
{
switch(resClass)
{
case ResourceClass::SRV: resName = "SRV"; break;
case ResourceClass::UAV: resName = "UAV"; break;
case ResourceClass::CBuffer: resName = "CBuffer"; break;
case ResourceClass::Sampler: resName = "Sampler"; break;
default: resName = "INVALID RESOURCE CLASS"; break;
};
}
}
else
{
resName = "ResourceClass:" + ArgToString(inst.args[1], false);
}
if(!hasResIndex)
{
resName += "[" + ArgToString(inst.args[2], false) + "]";
commentStr += " index = " + ArgToString(inst.args[3], false);
}
uint32_t value;
if(getival<uint32_t>(inst.args[4], value))
{
if(value != 0)
commentStr += " nonUniformIndex = true";
}
lineStr += resName;
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.cbufferLoad"))
{
// CBufferLoad(handle,byteOffset,alignment)
// CBufferLoadLegacy(handle,regIndex)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
bool loadLegacy = funcCallName.beginsWith("dx.op.cbufferLoadLegacy");
if(loadLegacy)
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::cbufferLoadLegacy);
else
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::cbufferLoad);
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
uint32_t regIndex;
if(getival<uint32_t>(inst.args[2], regIndex))
{
if(!loadLegacy)
{
// TODO: handle non 16-byte aligned offsets
// Convert byte offset to a register index
regIndex = regIndex / 16;
// uint32_t alignment = getival<uint32_t>(inst.args[3]);
}
uint32_t resourceIndex = resHandles[handleStr].resourceIndex;
lineStr += MakeCBufferRegisterStr(regIndex, entryPoint->cbuffers[resourceIndex]);
}
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.bufferLoad"))
{
// BufferLoad(srv,index,wot)
// wot is unused
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::bufferLoad);
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
lineStr += resHandles[handleStr].name;
lineStr += "[" + ArgToString(inst.args[2], false) + "]";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.rawBufferLoad"))
{
// RawBufferLoad(srv,index,elementOffset,mask,alignment)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::rawBufferLoad);
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
lineStr += resHandles[handleStr].name;
if(!isUndef(inst.args[2]))
{
lineStr += "[" + ArgToString(inst.args[2], false) + "]";
if(!isUndef(inst.args[3]))
{
uint32_t elementOffset;
if(getival<uint32_t>(inst.args[3], elementOffset))
{
if(elementOffset > 0)
lineStr += " + " + ToStr(elementOffset) + " bytes";
}
else
{
lineStr += " + " + ArgToString(inst.args[3], false) + " bytes";
}
}
}
else
{
lineStr += "[" + ArgToString(inst.args[3], false) + "]";
}
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.bufferStore") ||
funcCallName.beginsWith("dx.op.rawBufferStore"))
{
if(funcCallName.beginsWith("dx.op.bufferStore"))
{
// BufferStore(uav,coord0,coord1,value0,value1,value2,value3,mask)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::bufferStore);
}
else
{
// RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::rawBufferStore);
}
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
uint32_t offset = 0;
bool validElementOffset = !isUndef(inst.args[3]);
bool constantElementOffset = validElementOffset && getival(inst.args[3], offset);
lineStr += resHandles[handleStr].name;
uint32_t index;
if(getival(inst.args[2], index))
{
if((offset == 0) || (index > 0))
lineStr += "[" + ToStr(index) + "]";
}
else
{
lineStr += "[" + ArgToString(inst.args[2], false) + "]";
}
if(validElementOffset)
{
if(constantElementOffset)
{
if(offset > 0)
lineStr += " + " + ToStr(offset) + " bytes";
}
else
{
lineStr += " + " + ArgToString(inst.args[3], false) + " bytes";
}
}
lineStr += " = ";
lineStr += "{";
bool needComma = false;
for(uint32_t a = 4; a < 8; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "}";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.textureLoad"))
{
// TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::textureLoad);
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
lineStr += resHandles[handleStr].name;
lineStr += ".Load(";
bool needComma = false;
const EntryPointInterface::SRV *texture = resHandles[handleStr].srv;
for(uint32_t a = 3; a < 6; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
bool needText = true;
if(!isUndef(inst.args[2]))
{
rdcstr prefix;
bool showArg = true;
if(needText)
{
if(texture && texture->sampleCount > 1)
{
prefix = "SampleIndex = ";
}
else
{
prefix = "MipSlice = ";
uint32_t mipSlice;
if(getival<uint32_t>(inst.args[2], mipSlice))
showArg = mipSlice > 0;
}
}
if(showArg)
{
needText = false;
lineStr += ", ";
lineStr += prefix;
lineStr += ArgToString(inst.args[2], false);
}
}
needText = true;
for(uint32_t a = 6; a < 9; ++a)
{
if(!isUndef(inst.args[a]))
{
lineStr += ", ";
if(needText)
{
lineStr += "Offset = ";
needText = false;
}
lineStr += ArgToString(inst.args[a], false);
}
}
lineStr += ")";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.textureStore"))
{
// TextureStore(srv,coord0,coord1,coord2,value0,value1,value2,value3,mask)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::textureStore);
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
lineStr += resHandles[handleStr].name;
lineStr += "[";
bool needComma = false;
for(uint32_t a = 2; a < 5; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "]";
lineStr += " = ";
lineStr += "{";
needComma = false;
for(uint32_t a = 5; a < 9; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "}";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.sample") &&
!funcCallName.beginsWith("dx.op.sampleIndex"))
{
// Sample(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,clamp)
// SampleBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,bias,clamp)
// SampleLevel(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,LOD)
// SampleGrad(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)
// SampleCmp(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,clamp)
// SampleCmpLevelZero(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue)
// SampleCmpLevel(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,lod)
// SampleCmpGrad(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)
// SampleCmpBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,bias,clamp)
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERT((dxopCode == (uint32_t)DXOp::sample) ||
(dxopCode == (uint32_t)DXOp::sampleBias) ||
(dxopCode == (uint32_t)DXOp::sampleLevel) ||
(dxopCode == (uint32_t)DXOp::sampleGrad) ||
(dxopCode == (uint32_t)DXOp::sampleCmp) ||
(dxopCode == (uint32_t)DXOp::sampleCmpLevelZero) ||
(dxopCode == (uint32_t)DXOp::sampleCmpLevel) ||
(dxopCode == (uint32_t)DXOp::sampleCmpGrad) ||
(dxopCode == (uint32_t)DXOp::sampleCmpBias));
showDxFuncName = false;
rdcstr handleStr = ArgToString(inst.args[1], false);
if(resHandles.count(handleStr) > 0)
{
lineStr += resHandles[handleStr].name;
lineStr += ".";
rdcstr dxFuncSig = funcNameSigs[dxopCode];
int paramStart = dxFuncSig.find('(') + 1;
if(paramStart > 0)
lineStr += dxFuncSig.substr(0, paramStart);
else
lineStr += "UNKNOWN DX FUNCTION";
// sampler is 2
rdcstr samplerStr = ArgToString(inst.args[2], false);
if(resHandles.count(samplerStr) > 0)
samplerStr = resHandles[samplerStr].name;
lineStr += samplerStr;
for(uint32_t a = 3; a < 7; ++a)
{
if(!isUndef(inst.args[a]))
{
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
}
}
bool needText = true;
for(uint32_t a = 7; a < 10; ++a)
{
if(!isUndef(inst.args[a]))
{
lineStr += ", ";
if(needText)
{
lineStr += "Offset = {";
needText = false;
}
lineStr += ArgToString(inst.args[a], false);
}
}
if(!needText)
lineStr += "}";
int paramStrCount = (int)dxFuncSig.size();
for(size_t a = 1; a < 10; ++a)
{
if(paramStart < paramStrCount)
{
int paramEnd = dxFuncSig.find(',', paramStart);
if(paramEnd == -1)
paramEnd = paramStrCount;
paramStart = paramEnd + 1;
}
}
for(uint32_t a = 10; a < inst.args.size(); ++a)
{
rdcstr paramNameStr;
if(paramStart < paramStrCount)
{
int paramEnd = dxFuncSig.find(',', paramStart);
if(paramEnd == -1)
paramEnd = paramStrCount - 1;
if(paramEnd > paramStart)
{
rdcstr dxParamName = dxFuncSig.substr(paramStart, paramEnd - paramStart);
paramStart = paramEnd + 1;
paramNameStr = "/*";
paramNameStr += dxParamName;
paramNameStr += "*/ ";
}
}
if(!isUndef(inst.args[a]))
{
lineStr += ", ";
lineStr += paramNameStr;
lineStr += ArgToString(inst.args[a], false);
}
}
lineStr += ")";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.atomicBinOp"))
{
// AtomicBinOp(handle, atomicOp, offset0, offset1, offset2, newValue)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::atomicBinOp);
rdcstr handleStr = ArgToString(inst.args[1], false);
AtomicBinOpCode atomicBinOpCode;
if((resHandles.count(handleStr) > 0) &&
getival<AtomicBinOpCode>(inst.args[2], atomicBinOpCode))
{
lineStr += resHandles[handleStr].name;
lineStr += ".";
lineStr += "Interlocked";
lineStr += ToStr(atomicBinOpCode);
lineStr += "(";
lineStr += "{";
bool needComma = false;
for(uint32_t a = 3; a < 6; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "}";
if(!isUndef(inst.args[6]))
{
lineStr += ", ";
lineStr += ArgToString(inst.args[6], false);
}
lineStr += ")";
}
else
{
showDxFuncName = true;
}
}
else if(showDxFuncName && funcCallName.beginsWith("dx.op.dot"))
{
// Dot4(ax,ay,az,aw,bx,by,bz,bw)
// Dot3(ax,ay,az,bx,by,bz)
// Dot2(ax,ay,bx,by)
showDxFuncName = false;
uint32_t dxopCode;
RDCASSERT(getival<uint32_t>(inst.args[0], dxopCode));
uint32_t countComponents = 0;
if(funcCallName.beginsWith("dx.op.dot4"))
{
countComponents = 4;
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::dot4);
}
else if(funcCallName.beginsWith("dx.op.dot3"))
{
countComponents = 3;
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::dot3);
}
else if(funcCallName.beginsWith("dx.op.dot2"))
{
countComponents = 2;
RDCASSERTEQUAL(dxopCode, (uint32_t)DXOp::dot2);
}
lineStr += "dot(";
lineStr += "{";
bool needComma = false;
uint32_t aVecStart = 1;
uint32_t aVecEnd = 1 + countComponents;
for(uint32_t a = aVecStart; a < aVecEnd; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "}";
needComma = false;
uint32_t bVecStart = aVecEnd;
uint32_t bVecEnd = bVecStart + countComponents;
lineStr += ", {";
for(uint32_t a = bVecStart; a < bVecEnd; ++a)
{
if(!isUndef(inst.args[a]))
{
if(needComma)
lineStr += ", ";
lineStr += ArgToString(inst.args[a], false);
needComma = true;
}
}
lineStr += "}";
lineStr += ")";
}
else if(funcCallName.beginsWith("llvm.dbg."))
{
}
else
{
if(showDxFuncName)
{
rdcstr dxFuncSig;
int paramStart = -1;
if(Constant *op = cast<Constant>(inst.args[0]))
{
uint32_t opcode = op->getU32();
if(opcode < ARRAY_COUNT(funcNameSigs))
{
dxFuncSig = funcNameSigs[opcode];
paramStart = dxFuncSig.find('(') + 1;
if(paramStart > 0)
lineStr += dxFuncSig.substr(0, paramStart);
else
lineStr += dxFuncSig;
}
else
{
lineStr += escapeStringIfNeeded(funcCallName);
}
}
bool first = true;
int paramStrCount = (int)dxFuncSig.size();
for(size_t a = 1; a < inst.args.size(); ++a)
{
rdcstr paramNameStr;
if(paramStart < paramStrCount)
{
int paramEnd = dxFuncSig.find(',', paramStart);
if(paramEnd == -1)
paramEnd = paramStrCount - 1;
if(paramEnd > paramStart)
{
rdcstr dxParamName = dxFuncSig.substr(paramStart, paramEnd - paramStart);
paramStart = paramEnd + 1;
paramNameStr = "/*";
paramNameStr += dxParamName;
paramNameStr += "*/ ";
}
}
// Don't show "undef" parameters
if(!isUndef(inst.args[a]))
{
if(!first)
lineStr += ", ";
lineStr += paramNameStr;
rdcstr ssaStr = ArgToString(inst.args[a], false);
if(ssaAliases.count(ssaStr) == 0)
lineStr += ssaStr;
else
lineStr += ssaAliases[ssaStr];
first = false;
}
}
lineStr += ")";
}
else
{
lineStr += escapeStringIfNeeded(funcCallName);
lineStr += "(";
bool first = true;
const AttributeSet *paramAttrs = inst.getParamAttrs();
// attribute args start from 1
size_t argIdx = 1;
for(const Value *s : inst.args)
{
if(!first)
lineStr += ", ";
// see if we have param attrs for this param
rdcstr attrString;
if(paramAttrs && argIdx < paramAttrs->groupSlots.size() &&
paramAttrs->groupSlots[argIdx])
{
attrString = paramAttrs->groupSlots[argIdx]->toString(true) + " ";
}
lineStr += ArgToString(s, false, attrString);
first = false;
argIdx++;
}
lineStr += ")";
if(paramAttrs && paramAttrs->functionSlot)
lineStr +=
StringFormat::Fmt(" #%u", m_FuncAttrGroups.indexOf(paramAttrs->functionSlot));
}
}
}
break;
case Operation::Trunc:
case Operation::ZExt:
case Operation::SExt:
case Operation::FToU:
case Operation::FToS:
case Operation::UToF:
case Operation::SToF:
case Operation::FPTrunc:
case Operation::FPExt:
case Operation::PtrToI:
case Operation::IToPtr:
case Operation::Bitcast:
case Operation::AddrSpaceCast:
{
switch(inst.op)
{
case Operation::Trunc:
case Operation::ZExt:
case Operation::SExt:
case Operation::UToF:
case Operation::FPTrunc:
case Operation::FPExt:
case Operation::Bitcast:
case Operation::FToU:
case Operation::FToS:
case Operation::PtrToI:
case Operation::SToF: lineStr += "(" + inst.type->toString() + ")"; break;
case Operation::IToPtr: lineStr += "(void *)"; break;
case Operation::AddrSpaceCast: lineStr += "addrspacecast"; break;
default: break;
}
switch(inst.op)
{
case Operation::Trunc: commentStr = "truncate ";
case Operation::ZExt: commentStr += "zero extend "; break;
case Operation::SExt: commentStr += "signed extend "; break;
case Operation::UToF: commentStr += "unsigned "; break;
case Operation::FPTrunc: commentStr += "fp truncate "; break;
case Operation::FPExt: commentStr += "fp extend"; break;
case Operation::Bitcast: commentStr += "bitcast "; break;
case Operation::FToU: commentStr += "unsigned "; break;
case Operation::FToS: commentStr += "signed "; break;
case Operation::PtrToI: commentStr += "ptrtoi "; break;
case Operation::IToPtr: commentStr += "itoptr "; break;
default: break;
}
lineStr += "(";
lineStr += ArgToString(inst.args[0], false);
lineStr += ")";
break;
}
case Operation::ExtractVal:
{
lineStr += "extractvalue ";
lineStr += ArgToString(inst.args[0], false);
for(size_t n = 1; n < inst.args.size(); n++)
lineStr += StringFormat::Fmt(", %llu", cast<Literal>(inst.args[n])->literal);
break;
}
case Operation::FAdd:
case Operation::FSub:
case Operation::FMul:
case Operation::FDiv:
case Operation::FRem:
case Operation::Add:
case Operation::Sub:
case Operation::Mul:
case Operation::UDiv:
case Operation::SDiv:
case Operation::URem:
case Operation::SRem:
case Operation::ShiftLeft:
case Operation::LogicalShiftRight:
case Operation::ArithShiftRight:
case Operation::And:
case Operation::Or:
case Operation::Xor:
{
rdcstr opStr;
switch(inst.op)
{
case Operation::FAdd: opStr = " + "; break;
case Operation::FSub: opStr = " - "; break;
case Operation::FMul: opStr = " * "; break;
case Operation::FDiv: opStr = " / "; break;
case Operation::FRem: opStr = " % "; break;
case Operation::Add: opStr = " + "; break;
case Operation::Sub: opStr = " - "; break;
case Operation::Mul: opStr = " * "; break;
case Operation::UDiv: opStr = " / "; break;
case Operation::SDiv: opStr = " / "; break;
case Operation::URem: opStr = " % "; break;
case Operation::ShiftLeft: opStr = " << "; break;
case Operation::LogicalShiftRight: opStr = " >> "; break;
case Operation::ArithShiftRight: opStr = " >> "; break;
case Operation::And: opStr = " & "; break;
case Operation::Or: opStr = " | "; break;
case Operation::Xor: opStr = " ^ "; break;
default: break;
}
switch(inst.op)
{
case Operation::FRem: commentStr += "float "; break;
case Operation::UDiv:
case Operation::URem: commentStr += "unsigned "; break;
case Operation::SDiv:
case Operation::SRem: commentStr += "signed "; break;
case Operation::LogicalShiftRight: commentStr += "logical "; break;
case Operation::ArithShiftRight: commentStr += "arithmetic "; break;
default: break;
}
bool first = true;
for(const Value *s : inst.args)
{
lineStr += ArgToString(s, false);
if(first)
{
lineStr += opStr;
first = false;
}
}
break;
}
case Operation::Ret:
{
lineStr += "return";
if(!inst.args.empty())
lineStr += " " + ArgToString(inst.args[0], false);
break;
}
case Operation::Unreachable: lineStr += "unreachable"; break;
case Operation::Alloca:
{
lineStr += "alloca ";
lineStr += inst.type->inner->toString();
if(inst.align > 0)
lineStr += StringFormat::Fmt(", align %u", (1U << inst.align) >> 1);
break;
}
case Operation::GetElementPtr:
{
bool fallbackOutput = true;
if(!inst.type->isVoid())
{
// type "float addrspace(3)*" : addrspace(3) is DXIL specific, see DXIL::Type::PointerAddrSpace
rdcstr typeStr = inst.type->toString();
int start = typeStr.find(" addrspace(");
if(start > 0)
{
rdcstr scalarType = typeStr.substr(0, start);
scalarType.trim();
start += 11;
int end = typeStr.find(')', start);
if(end > start)
{
// Example output:
// DXC:
// %3 = getelementptr [6 x float], [6 x float] addrspace(3)*
// @"\01?s_x@@3@$$A.1dim", i32 0, i32 %9
// RD: GroupShared float* _3 = s_x[_9];
fallbackOutput = false;
rdcstr addrspaceStr(typeStr.substr(start, end - start));
int32_t value = atoi(addrspaceStr.c_str());
DXIL::Type::PointerAddrSpace addrspace = (DXIL::Type::PointerAddrSpace)value;
switch(addrspace)
{
case DXIL::Type::PointerAddrSpace::Default: lineStr = ""; break;
case DXIL::Type::PointerAddrSpace::DeviceMemory:
lineStr = "DeviceMemory";
break;
case DXIL::Type::PointerAddrSpace::CBuffer: lineStr = "CBuffer"; break;
case DXIL::Type::PointerAddrSpace::GroupShared: lineStr = "GroupShared"; break;
case DXIL::Type::PointerAddrSpace::GenericPointer: lineStr = ""; break;
case DXIL::Type::PointerAddrSpace::ImmediateCBuffer:
lineStr = "ImmediateCBuffer";
break;
};
lineStr += " ";
lineStr += scalarType;
lineStr += "* ";
if(!inst.getName().empty())
lineStr += StringFormat::Fmt("%c%s = ", DXIL::dxilIdentifier,
escapeStringIfNeeded(inst.getName()).c_str());
else if(inst.slot != ~0U)
lineStr += StringFormat::Fmt("%c%u = ", DXIL::dxilIdentifier, inst.slot);
// arg[0] : ptr
rdcstr ptrStr = ArgToString(inst.args[0], false);
// Try to de-mangle the pointer name
// @"\01?shared_pos@@3PAY0BC@$$CAMA.1dim" -> shared_pos
// Take the string between first alphabetical character and last
// alphanumeric character or "_"
start = 0;
int strEnd = (int)ptrStr.size();
while(start < strEnd)
{
if(isalpha(ptrStr[start]))
break;
++start;
}
if(start < strEnd)
{
end = start + 1;
while(end < strEnd)
{
char c = ptrStr[end];
if(!isalnum(c) && c != '_')
break;
++end;
}
}
if(end > start)
ptrStr = ptrStr.substr(start, end - start);
lineStr += ptrStr;
// arg[1] : index 0
bool first = true;
if(inst.args.size() > 1)
{
uint32_t v = 0;
if(!getival<uint32_t>(inst.args[1], v) || (v > 0))
{
lineStr += "[";
lineStr += ArgToString(inst.args[1], false);
lineStr += "]";
first = false;
}
}
// arg[2..] : index 1...N
for(size_t a = 2; a < inst.args.size(); ++a)
{
if(first)
lineStr += "[";
else
lineStr += " + ";
lineStr += ArgToString(inst.args[a], false);
if(first)
{
lineStr += "]";
first = false;
}
}
}
}
}
if(fallbackOutput)
{
lineStr += "getelementptr ";
bool first = true;
for(const Value *s : inst.args)
{
if(!first)
lineStr += ", ";
lineStr += ArgToString(s, false);
first = false;
}
}
if(inst.opFlags() & InstructionFlags::InBounds)
commentStr += "inbounds ";
break;
}
case Operation::LoadAtomic: commentStr += "atomic ";
case Operation::Load:
{
lineStr += "*";
if(inst.opFlags() & InstructionFlags::Volatile)
commentStr += "volatile ";
bool first = true;
for(const Value *s : inst.args)
{
if(!first)
lineStr += ", ";
lineStr += ArgToString(s, false);
first = false;
}
if(inst.align > 0)
commentStr += StringFormat::Fmt("align %u ", (1U << inst.align) >> 1);
break;
}
case Operation::StoreAtomic: commentStr += "atomic ";
case Operation::Store:
{
if(inst.opFlags() & InstructionFlags::Volatile)
commentStr += "volatile ";
lineStr = "*";
lineStr += ArgToString(inst.args[0], false);
lineStr += " = ";
lineStr += ArgToString(inst.args[1], false);
if(inst.align > 0)
commentStr += StringFormat::Fmt("align %u ", (1U << inst.align) >> 1);
break;
}
case Operation::FOrdEqual:
case Operation::FOrdGreater:
case Operation::FOrdGreaterEqual:
case Operation::FOrdLess:
case Operation::FOrdLessEqual:
case Operation::FOrdNotEqual:
case Operation::FUnordEqual:
case Operation::FUnordGreater:
case Operation::FUnordGreaterEqual:
case Operation::FUnordLess:
case Operation::FUnordLessEqual:
case Operation::FUnordNotEqual:
{
rdcstr opStr;
switch(inst.op)
{
case Operation::FOrdEqual: opStr = " == "; break;
case Operation::FOrdGreater: opStr = " > "; break;
case Operation::FOrdGreaterEqual: opStr = " >= "; break;
case Operation::FOrdLess: opStr = " < "; break;
case Operation::FOrdLessEqual: opStr = " <= "; break;
case Operation::FOrdNotEqual: opStr = " != "; break;
case Operation::FUnordEqual: opStr = " == ";
case Operation::FUnordGreater: opStr = " > "; break;
case Operation::FUnordGreaterEqual: opStr = " >= "; break;
case Operation::FUnordLess: opStr = " < "; break;
case Operation::FUnordLessEqual: opStr = " <= "; break;
case Operation::FUnordNotEqual: opStr = " != "; break;
default: break;
}
switch(inst.op)
{
case Operation::FUnord:
case Operation::FUnordEqual:
case Operation::FUnordGreater:
case Operation::FUnordGreaterEqual:
case Operation::FUnordLess:
case Operation::FUnordLessEqual: commentStr += "unordered ";
default: break;
}
lineStr += "(";
lineStr += ArgToString(inst.args[0], false);
lineStr += opStr;
lineStr += ArgToString(inst.args[1], false);
lineStr += ")";
break;
}
case Operation::FOrd:
{
// ord: yields true if both operands are not a QNAN.
lineStr += "!isqnan(";
lineStr += ArgToString(inst.args[0], false);
lineStr += ")";
lineStr += " && ";
lineStr += "!isqnan(";
lineStr += ArgToString(inst.args[1], false);
lineStr += ")";
break;
}
case Operation::FUnord:
{
// uno: yields true if either operand is a QNAN.
lineStr += "isqnan(";
lineStr += ArgToString(inst.args[0], false);
lineStr += ")";
lineStr += " || ";
lineStr += "isqnan(";
lineStr += ArgToString(inst.args[1], false);
lineStr += ")";
break;
}
case Operation::FOrdFalse: lineStr += "false"; break;
case Operation::FOrdTrue: lineStr += "true"; break;
case Operation::IEqual:
case Operation::INotEqual:
case Operation::UGreater:
case Operation::UGreaterEqual:
case Operation::ULess:
case Operation::ULessEqual:
case Operation::SGreater:
case Operation::SGreaterEqual:
case Operation::SLess:
case Operation::SLessEqual:
{
rdcstr opStr;
switch(inst.op)
{
case Operation::IEqual: opStr += " == "; break;
case Operation::INotEqual: opStr += " != "; break;
case Operation::UGreater: opStr += " > "; break;
case Operation::UGreaterEqual: opStr += " >= "; break;
case Operation::ULess: opStr += " < "; break;
case Operation::ULessEqual: opStr += " <= "; break;
case Operation::SGreater: opStr += " > "; break;
case Operation::SGreaterEqual: opStr += " >= "; break;
case Operation::SLess: opStr += " < "; break;
case Operation::SLessEqual: opStr += " <= "; break;
default: break;
}
switch(inst.op)
{
case Operation::SGreater:
case Operation::SGreaterEqual:
case Operation::SLess:
case Operation::SLessEqual: commentStr = "signed ";
default: break;
}
lineStr += "(";
lineStr += ArgToString(inst.args[0], false);
lineStr += opStr;
lineStr += ArgToString(inst.args[1], false);
lineStr += ")";
break;
}
case Operation::Select:
{
lineStr += ArgToString(inst.args[2], false);
lineStr += " ? ";
lineStr += ArgToString(inst.args[0], false);
lineStr += " : ";
lineStr += ArgToString(inst.args[1], false);
break;
}
case Operation::ExtractElement:
{
lineStr += "extractelement ";
lineStr += ArgToString(inst.args[0], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[1], false);
break;
}
case Operation::InsertElement:
{
lineStr += "insertelement ";
lineStr += ArgToString(inst.args[0], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[1], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[2], false);
break;
}
case Operation::ShuffleVector:
{
lineStr += "shufflevector ";
lineStr += ArgToString(inst.args[0], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[1], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[2], false);
break;
}
case Operation::InsertValue:
{
lineStr += "insertvalue ";
lineStr += ArgToString(inst.args[0], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[1], false);
for(size_t a = 2; a < inst.args.size(); a++)
{
lineStr += ", " + ToStr(cast<Literal>(inst.args[a])->literal);
}
break;
}
case Operation::Branch:
{
if(inst.args.size() > 1)
{
lineStr += "if (";
lineStr += ArgToString(inst.args[2], false);
lineStr += ") goto ";
lineStr += StringFormat::Fmt("%s", ArgToString(inst.args[0], false).c_str());
lineStr += " else goto ";
lineStr += StringFormat::Fmt("%s", ArgToString(inst.args[1], false).c_str());
}
else
{
lineStr += "goto ";
lineStr += ArgToString(inst.args[0], false);
}
break;
}
case Operation::Phi:
{
lineStr += "phi ";
lineStr += inst.type->toString();
for(size_t a = 0; a < inst.args.size(); a += 2)
{
if(a == 0)
lineStr += " ";
else
lineStr += ", ";
lineStr += StringFormat::Fmt("[ %s, %s ]", ArgToString(inst.args[a], false).c_str(),
ArgToString(inst.args[a + 1], false).c_str());
}
break;
}
case Operation::Switch:
{
lineStr += "switch ";
lineStr += ArgToString(inst.args[0], false);
lineStr += ", ";
lineStr += ArgToString(inst.args[1], false);
lineStr += " [";
lineStr += "\n";
m_DisassemblyInstructionLine++;
for(size_t a = 2; a < inst.args.size(); a += 2)
{
lineStr += StringFormat::Fmt(" %s, %s", ArgToString(inst.args[a], false).c_str(),
ArgToString(inst.args[a + 1], false).c_str());
lineStr += "\n";
m_DisassemblyInstructionLine++;
}
lineStr += " ]";
break;
}
case Operation::Fence:
{
lineStr += "fence ";
if(inst.opFlags() & InstructionFlags::SingleThread)
lineStr += "singlethread ";
switch((inst.opFlags() & InstructionFlags::SuccessOrderMask))
{
case InstructionFlags::SuccessUnordered: lineStr += "unordered"; break;
case InstructionFlags::SuccessMonotonic: lineStr += "monotonic"; break;
case InstructionFlags::SuccessAcquire: lineStr += "acquire"; break;
case InstructionFlags::SuccessRelease: lineStr += "release"; break;
case InstructionFlags::SuccessAcquireRelease: lineStr += "acq_rel"; break;
case InstructionFlags::SuccessSequentiallyConsistent: lineStr += "seq_cst"; break;
default: break;
}
break;
}
case Operation::CompareExchange:
{
lineStr += "cmpxchg ";
if(inst.opFlags() & InstructionFlags::Weak)
lineStr += "weak ";
if(inst.opFlags() & InstructionFlags::Volatile)
lineStr += "volatile ";
bool first = true;
for(const Value *s : inst.args)
{
if(!first)
lineStr += ", ";
lineStr += ArgToString(s, false);
first = false;
}
lineStr += " ";
if(inst.opFlags() & InstructionFlags::SingleThread)
lineStr += "singlethread ";
switch((inst.opFlags() & InstructionFlags::SuccessOrderMask))
{
case InstructionFlags::SuccessUnordered: lineStr += "unordered"; break;
case InstructionFlags::SuccessMonotonic: lineStr += "monotonic"; break;
case InstructionFlags::SuccessAcquire: lineStr += "acquire"; break;
case InstructionFlags::SuccessRelease: lineStr += "release"; break;
case InstructionFlags::SuccessAcquireRelease: lineStr += "acq_rel"; break;
case InstructionFlags::SuccessSequentiallyConsistent: lineStr += "seq_cst"; break;
default: break;
}
lineStr += " ";
switch((inst.opFlags() & InstructionFlags::FailureOrderMask))
{
case InstructionFlags::FailureUnordered: lineStr += "unordered"; break;
case InstructionFlags::FailureMonotonic: lineStr += "monotonic"; break;
case InstructionFlags::FailureAcquire: lineStr += "acquire"; break;
case InstructionFlags::FailureRelease: lineStr += "release"; break;
case InstructionFlags::FailureAcquireRelease: lineStr += "acq_rel"; break;
case InstructionFlags::FailureSequentiallyConsistent: lineStr += "seq_cst"; break;
default: break;
}
break;
}
case Operation::AtomicExchange:
case Operation::AtomicAdd:
case Operation::AtomicSub:
case Operation::AtomicAnd:
case Operation::AtomicNand:
case Operation::AtomicOr:
case Operation::AtomicXor:
case Operation::AtomicMax:
case Operation::AtomicMin:
case Operation::AtomicUMax:
case Operation::AtomicUMin:
{
lineStr += "atomicrmw ";
if(inst.opFlags() & InstructionFlags::Volatile)
lineStr += "volatile ";
switch(inst.op)
{
case Operation::AtomicExchange: lineStr += "xchg "; break;
case Operation::AtomicAdd: lineStr += "add "; break;
case Operation::AtomicSub: lineStr += "sub "; break;
case Operation::AtomicAnd: lineStr += "and "; break;
case Operation::AtomicNand: lineStr += "nand "; break;
case Operation::AtomicOr: lineStr += "or "; break;
case Operation::AtomicXor: lineStr += "xor "; break;
case Operation::AtomicMax: lineStr += "max "; break;
case Operation::AtomicMin: lineStr += "min "; break;
case Operation::AtomicUMax: lineStr += "umax "; break;
case Operation::AtomicUMin: lineStr += "umin "; break;
default: break;
}
bool first = true;
for(const Value *s : inst.args)
{
if(!first)
lineStr += ", ";
lineStr += ArgToString(s, false);
first = false;
}
lineStr += " ";
if(inst.opFlags() & InstructionFlags::SingleThread)
lineStr += "singlethread ";
switch((inst.opFlags() & InstructionFlags::SuccessOrderMask))
{
case InstructionFlags::SuccessUnordered: lineStr += "unordered"; break;
case InstructionFlags::SuccessMonotonic: lineStr += "monotonic"; break;
case InstructionFlags::SuccessAcquire: lineStr += "acquire"; break;
case InstructionFlags::SuccessRelease: lineStr += "release"; break;
case InstructionFlags::SuccessAcquireRelease: lineStr += "acq_rel"; break;
case InstructionFlags::SuccessSequentiallyConsistent: lineStr += "seq_cst"; break;
default: break;
}
break;
}
}
if(showDxFuncName)
{
if(inst.getFuncCall() && inst.getFuncCall()->name.beginsWith("dx.op.annotateHandle"))
{
// AnnotateHandle(res,props)
if(const Constant *props = cast<Constant>(inst.args[2]))
{
const Constant *packed[2];
if(props && !props->isNULL() && props->getMembers().size() == 2 &&
(packed[0] = cast<Constant>(props->getMembers()[0])) != NULL &&
(packed[1] = cast<Constant>(props->getMembers()[1])) != NULL)
{
uint32_t packedProps[2] = {};
packedProps[0] = packed[0]->getU32();
packedProps[1] = packed[1]->getU32();
bool uav = (packedProps[0] & (1 << 12)) != 0;
bool rov = (packedProps[0] & (1 << 13)) != 0;
bool globallyCoherent = (packedProps[0] & (1 << 14)) != 0;
bool sampelCmpOrCounter = (packedProps[0] & (1 << 15)) != 0;
ResourceKind resKind = (ResourceKind)(packedProps[0] & 0xFF);
ResourceClass resClass;
if(sampelCmpOrCounter && resKind == ResourceKind::Sampler)
resKind = ResourceKind::SamplerComparison;
if(resKind == ResourceKind::Sampler || resKind == ResourceKind::SamplerComparison)
resClass = ResourceClass::Sampler;
else if(resKind == ResourceKind::CBuffer)
resClass = ResourceClass::CBuffer;
else if(uav)
resClass = ResourceClass::UAV;
else
resClass = ResourceClass::SRV;
lineStr += " resource: ";
bool srv = (resClass == ResourceClass::SRV);
ComponentType compType = ComponentType(packedProps[1] & 0xFF);
uint8_t compCount = (packedProps[1] & 0xFF00) >> 8;
uint8_t feedbackType = packedProps[1] & 0xFF;
uint32_t structStride = packedProps[1];
switch(resKind)
{
case ResourceKind::Unknown: lineStr += "Unknown"; break;
case ResourceKind::Texture1D:
case ResourceKind::Texture2D:
case ResourceKind::Texture2DMS:
case ResourceKind::Texture3D:
case ResourceKind::TextureCube:
case ResourceKind::Texture1DArray:
case ResourceKind::Texture2DArray:
case ResourceKind::Texture2DMSArray:
case ResourceKind::TextureCubeArray:
case ResourceKind::TypedBuffer:
if(globallyCoherent)
lineStr += "globallycoherent ";
if(!srv && rov)
lineStr += "ROV";
else if(!srv)
lineStr += "RW";
switch(resKind)
{
case ResourceKind::Texture1D: lineStr += "Texture1D"; break;
case ResourceKind::Texture2D: lineStr += "Texture2D"; break;
case ResourceKind::Texture2DMS: lineStr += "Texture2DMS"; break;
case ResourceKind::Texture3D: lineStr += "Texture3D"; break;
case ResourceKind::TextureCube: lineStr += "TextureCube"; break;
case ResourceKind::Texture1DArray: lineStr += "Texture1DArray"; break;
case ResourceKind::Texture2DArray: lineStr += "Texture2DArray"; break;
case ResourceKind::Texture2DMSArray: lineStr += "Texture2DMSArray"; break;
case ResourceKind::TextureCubeArray: lineStr += "TextureCubeArray"; break;
case ResourceKind::TypedBuffer: lineStr += "TypedBuffer"; break;
default: break;
}
break;
case ResourceKind::RTAccelerationStructure:
lineStr += "RTAccelerationStructure";
break;
case ResourceKind::FeedbackTexture2D: lineStr += "FeedbackTexture2D"; break;
case ResourceKind::FeedbackTexture2DArray:
lineStr += "FeedbackTexture2DArray";
break;
case ResourceKind::StructuredBuffer:
if(globallyCoherent)
lineStr += "globallycoherent ";
lineStr += srv ? "StructuredBuffer" : "RWStructuredBuffer";
lineStr += StringFormat::Fmt("<stride=%u", structStride);
if(sampelCmpOrCounter)
lineStr += ", counter";
lineStr += ">";
break;
case ResourceKind::StructuredBufferWithCounter:
if(globallyCoherent)
lineStr += "globallycoherent ";
lineStr += srv ? "StructuredBufferWithCounter" : "RWStructuredBufferWithCounter";
lineStr += StringFormat::Fmt("<stride=%u>", structStride);
break;
case ResourceKind::RawBuffer:
if(globallyCoherent)
lineStr += "globallycoherent ";
lineStr += srv ? "ByteAddressBuffer" : "RWByteAddressBuffer";
break;
case ResourceKind::CBuffer:
RDCASSERT(resClass == ResourceClass::CBuffer);
lineStr += "CBuffer";
break;
case ResourceKind::Sampler:
RDCASSERT(resClass == ResourceClass::Sampler);
lineStr += "SamplerState";
break;
case ResourceKind::TBuffer:
RDCASSERT(resClass == ResourceClass::SRV);
lineStr += "TBuffer";
break;
case ResourceKind::SamplerComparison:
RDCASSERT(resClass == ResourceClass::Sampler);
lineStr += "SamplerComparisonState";
break;
}
if(resKind == ResourceKind::FeedbackTexture2D ||
resKind == ResourceKind::FeedbackTexture2DArray)
{
if(feedbackType == 0)
lineStr += "<MinMip>";
else if(feedbackType == 1)
lineStr += "<MipRegionUsed>";
else
lineStr += "<Invalid>";
}
else if(resKind == ResourceKind::Texture1D || resKind == ResourceKind::Texture2D ||
resKind == ResourceKind::Texture3D || resKind == ResourceKind::TextureCube ||
resKind == ResourceKind::Texture1DArray ||
resKind == ResourceKind::Texture2DArray ||
resKind == ResourceKind::TextureCubeArray ||
resKind == ResourceKind::TypedBuffer || resKind == ResourceKind::Texture2DMS ||
resKind == ResourceKind::Texture2DMSArray)
{
lineStr += "<";
if(compCount > 1)
lineStr += StringFormat::Fmt("%dx", compCount);
lineStr += StringFormat::Fmt("%s>", ToStr(compType).c_str());
}
}
}
}
}
if(!lineStr.empty())
{
lineStr += ";";
if(!commentStr.empty())
lineStr += " // " + commentStr;
m_Disassembly += " " + lineStr;
DisassemblyAddNewLine();
}
// if this is the last instruction don't print the next block's label
if(funcIdx == func.instructions.size() - 1)
break;
if(inst.op == Operation::Branch || inst.op == Operation::Unreachable ||
inst.op == Operation::Switch || inst.op == Operation::Ret)
{
DisassemblyAddNewLine();
curBlock++;
rdcstr labelName;
if(func.blocks[curBlock]->name.empty())
labelName = StringFormat::Fmt("; <label>:%u", func.blocks[curBlock]->slot);
else
labelName =
StringFormat::Fmt("%s: ", escapeStringIfNeeded(func.blocks[curBlock]->name).c_str());
labelName.reserve(50);
while(labelName.size() < 50)
labelName.push_back(' ');
labelName += "; preds = ";
bool first = true;
for(const Block *pred : func.blocks[curBlock]->preds)
{
if(!first)
labelName += ", ";
first = false;
if(pred->name.empty())
labelName += StringFormat::Fmt("%c%u", DXIL::dxilIdentifier, pred->slot);
else
labelName += StringFormat::Fmt("%c%s", DXIL::dxilIdentifier,
escapeStringIfNeeded(pred->name).c_str());
}
m_Disassembly += labelName;
DisassemblyAddNewLine();
}
}
m_Disassembly += "}";
DisassemblyAddNewLine(2);
}
else
{
DisassemblyAddNewLine(2);
}
m_Accum.exitFunction();
}
DisassemblyAddNewLine();
// TODO: decide how much of this should be output
// m_Disassembly += DisassembleFuncAttrGroups();
// m_Disassembly += DisassembleNamedMeta();
// m_Disassembly += DisassembleMeta();
m_Disassembly += "\n";
}