mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-12 13:00:32 +00:00
Move disassembly to separate file
This commit is contained in:
@@ -460,39 +460,6 @@ static rdcstr getName(uint32_t parentBlock, const LLVMBC::BlockOrRecord &block)
|
||||
}
|
||||
}
|
||||
|
||||
bool needsEscaping(const rdcstr &name)
|
||||
{
|
||||
return name.find_first_not_of(
|
||||
"-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789") >= 0;
|
||||
}
|
||||
|
||||
rdcstr escapeString(rdcstr str)
|
||||
{
|
||||
for(size_t i = 0; i < str.size(); i++)
|
||||
{
|
||||
if(str[i] == '\'' || str[i] == '\\')
|
||||
{
|
||||
str.insert(i, "\\", 1);
|
||||
i++;
|
||||
}
|
||||
else if(str[i] == '\r' || str[i] == '\n' || str[i] == '\t' || !isprint(str[i]))
|
||||
{
|
||||
str.insert(i + 1, StringFormat::Fmt("%02X", str[i]));
|
||||
str[i] = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
str.push_back('"');
|
||||
str.insert(0, '"');
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
rdcstr escapeStringIfNeeded(const rdcstr &name)
|
||||
{
|
||||
return needsEscaping(name) ? escapeString(name) : name;
|
||||
}
|
||||
|
||||
static void dumpRecord(size_t idx, uint32_t parentBlock, const LLVMBC::BlockOrRecord &record,
|
||||
int indent)
|
||||
{
|
||||
@@ -1661,531 +1628,6 @@ D3D_PRIMITIVE_TOPOLOGY Program::GetOutputTopology()
|
||||
return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
}
|
||||
|
||||
void Program::MakeDisassemblyString()
|
||||
{
|
||||
const char *shaderName[] = {
|
||||
"Pixel", "Vertex", "Geometry", "Hull", "Domain",
|
||||
"Compute", "Library", "RayGeneration", "Intersection", "AnyHit",
|
||||
"ClosestHit", "Miss", "Callable", "Mesh", "Amplification",
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static const char *funcSigs[] = {
|
||||
"TempRegLoad(index)",
|
||||
"TempRegStore(index,value)",
|
||||
"MinPrecXRegLoad(regIndex,index,component)",
|
||||
"MinPrecXRegStore(regIndex,index,component,value)",
|
||||
"LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)",
|
||||
"StoreOutput(outputSigId,rowIndex,colIndex,value)",
|
||||
"FAbs(value)",
|
||||
"Saturate(value)",
|
||||
"IsNaN(value)",
|
||||
"IsInf(value)",
|
||||
"IsFinite(value)",
|
||||
"IsNormal(value)",
|
||||
"Cos(value)",
|
||||
"Sin(value)",
|
||||
"Tan(value)",
|
||||
"Acos(value)",
|
||||
"Asin(value)",
|
||||
"Atan(value)",
|
||||
"Hcos(value)",
|
||||
"Hsin(value)",
|
||||
"Htan(value)",
|
||||
"Exp(value)",
|
||||
"Frc(value)",
|
||||
"Log(value)",
|
||||
"Sqrt(value)",
|
||||
"Rsqrt(value)",
|
||||
"Round_ne(value)",
|
||||
"Round_ni(value)",
|
||||
"Round_pi(value)",
|
||||
"Round_z(value)",
|
||||
"Bfrev(value)",
|
||||
"Countbits(value)",
|
||||
"FirstbitLo(value)",
|
||||
"FirstbitHi(value)",
|
||||
"FirstbitSHi(value)",
|
||||
"FMax(a,b)",
|
||||
"FMin(a,b)",
|
||||
"IMax(a,b)",
|
||||
"IMin(a,b)",
|
||||
"UMax(a,b)",
|
||||
"UMin(a,b)",
|
||||
"IMul(a,b)",
|
||||
"UMul(a,b)",
|
||||
"UDiv(a,b)",
|
||||
"UAddc(a,b)",
|
||||
"USubb(a,b)",
|
||||
"FMad(a,b,c)",
|
||||
"Fma(a,b,c)",
|
||||
"IMad(a,b,c)",
|
||||
"UMad(a,b,c)",
|
||||
"Msad(a,b,c)",
|
||||
"Ibfe(a,b,c)",
|
||||
"Ubfe(a,b,c)",
|
||||
"Bfi(width,offset,value,replacedValue)",
|
||||
"Dot2(ax,ay,bx,by)",
|
||||
"Dot3(ax,ay,az,bx,by,bz)",
|
||||
"Dot4(ax,ay,az,aw,bx,by,bz,bw)",
|
||||
"CreateHandle(resourceClass,rangeId,index,nonUniformIndex)",
|
||||
"CBufferLoad(handle,byteOffset,alignment)",
|
||||
"CBufferLoadLegacy(handle,regIndex)",
|
||||
"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)",
|
||||
"TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)",
|
||||
"TextureStore(srv,coord0,coord1,coord2,value0,value1,value2,value3,mask)",
|
||||
"BufferLoad(srv,index,wot)",
|
||||
"BufferStore(uav,coord0,coord1,value0,value1,value2,value3,mask)",
|
||||
"BufferUpdateCounter(uav,inc)",
|
||||
"CheckAccessFullyMapped(status)",
|
||||
"GetDimensions(handle,mipLevel)",
|
||||
"TextureGather(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel)",
|
||||
"TextureGatherCmp(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel,compareVale)",
|
||||
"Texture2DMSGetSamplePosition(srv,index)",
|
||||
"RenderTargetGetSamplePosition(index)",
|
||||
"RenderTargetGetSampleCount()",
|
||||
"AtomicBinOp(handle,atomicOp,offset0,offset1,offset2,newValue)",
|
||||
"AtomicCompareExchange(handle,offset0,offset1,offset2,compareValue,newValue)",
|
||||
"Barrier(barrierMode)",
|
||||
"CalculateLOD(handle,sampler,coord0,coord1,coord2,clamped)",
|
||||
"Discard(condition)",
|
||||
"DerivCoarseX(value)",
|
||||
"DerivCoarseY(value)",
|
||||
"DerivFineX(value)",
|
||||
"DerivFineY(value)",
|
||||
"EvalSnapped(inputSigId,inputRowIndex,inputColIndex,offsetX,offsetY)",
|
||||
"EvalSampleIndex(inputSigId,inputRowIndex,inputColIndex,sampleIndex)",
|
||||
"EvalCentroid(inputSigId,inputRowIndex,inputColIndex)",
|
||||
"SampleIndex()",
|
||||
"Coverage()",
|
||||
"InnerCoverage()",
|
||||
"ThreadId(component)",
|
||||
"GroupId(component)",
|
||||
"ThreadIdInGroup(component)",
|
||||
"FlattenedThreadIdInGroup()",
|
||||
"EmitStream(streamId)",
|
||||
"CutStream(streamId)",
|
||||
"EmitThenCutStream(streamId)",
|
||||
"GSInstanceID()",
|
||||
"MakeDouble(lo,hi)",
|
||||
"SplitDouble(value)",
|
||||
"LoadOutputControlPoint(inputSigId,row,col,index)",
|
||||
"LoadPatchConstant(inputSigId,row,col)",
|
||||
"DomainLocation(component)",
|
||||
"StorePatchConstant(outputSigID,row,col,value)",
|
||||
"OutputControlPointID()",
|
||||
"PrimitiveID()",
|
||||
"CycleCounterLegacy()",
|
||||
"WaveIsFirstLane()",
|
||||
"WaveGetLaneIndex()",
|
||||
"WaveGetLaneCount()",
|
||||
"WaveAnyTrue(cond)",
|
||||
"WaveAllTrue(cond)",
|
||||
"WaveActiveAllEqual(value)",
|
||||
"WaveActiveBallot(cond)",
|
||||
"WaveReadLaneAt(value,lane)",
|
||||
"WaveReadLaneFirst(value)",
|
||||
"WaveActiveOp(value,op,sop)",
|
||||
"WaveActiveBit(value,op)",
|
||||
"WavePrefixOp(value,op,sop)",
|
||||
"QuadReadLaneAt(value,quadLane)",
|
||||
"QuadOp(value,op)",
|
||||
"BitcastI16toF16(value)",
|
||||
"BitcastF16toI16(value)",
|
||||
"BitcastI32toF32(value)",
|
||||
"BitcastF32toI32(value)",
|
||||
"BitcastI64toF64(value)",
|
||||
"BitcastF64toI64(value)",
|
||||
"LegacyF32ToF16(value)",
|
||||
"LegacyF16ToF32(value)",
|
||||
"LegacyDoubleToFloat(value)",
|
||||
"LegacyDoubleToSInt32(value)",
|
||||
"LegacyDoubleToUInt32(value)",
|
||||
"WaveAllBitCount(value)",
|
||||
"WavePrefixBitCount(value)",
|
||||
"AttributeAtVertex(inputSigId,inputRowIndex,inputColIndex,VertexID)",
|
||||
"ViewID()",
|
||||
"RawBufferLoad(srv,index,elementOffset,mask,alignment)",
|
||||
"RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)",
|
||||
"InstanceID()",
|
||||
"InstanceIndex()",
|
||||
"HitKind()",
|
||||
"RayFlags()",
|
||||
"DispatchRaysIndex(col)",
|
||||
"DispatchRaysDimensions(col)",
|
||||
"WorldRayOrigin(col)",
|
||||
"WorldRayDirection(col)",
|
||||
"ObjectRayOrigin(col)",
|
||||
"ObjectRayDirection(col)",
|
||||
"ObjectToWorld(row,col)",
|
||||
"WorldToObject(row,col)",
|
||||
"RayTMin()",
|
||||
"RayTCurrent()",
|
||||
"IgnoreHit()",
|
||||
"AcceptHitAndEndSearch()",
|
||||
"TraceRay(AccelerationStructure,RayFlags,InstanceInclusionMask,RayContributionToHitGroupIndex,MultiplierForGeometryContributionToShaderIndex,MissShaderIndex,Origin_X,Origin_Y,Origin_Z,TMin,Direction_X,Direction_Y,Direction_Z,TMax,payload)",
|
||||
"ReportHit(THit,HitKind,Attributes)",
|
||||
"CallShader(ShaderIndex,Parameter)",
|
||||
"CreateHandleForLib(Resource)",
|
||||
"PrimitiveIndex()",
|
||||
"Dot2AddHalf(acc,ax,ay,bx,by)",
|
||||
"Dot4AddI8Packed(acc,a,b)",
|
||||
"Dot4AddU8Packed(acc,a,b)",
|
||||
"WaveMatch(value)",
|
||||
"WaveMultiPrefixOp(value,mask0,mask1,mask2,mask3,op,sop)",
|
||||
"WaveMultiPrefixBitCount(value,mask0,mask1,mask2,mask3)",
|
||||
"SetMeshOutputCounts(numVertices,numPrimitives)",
|
||||
"EmitIndices(PrimitiveIndex,VertexIndex0,VertexIndex1,VertexIndex2)",
|
||||
"GetMeshPayload()",
|
||||
"StoreVertexOutput(outputSigId,rowIndex,colIndex,value,vertexIndex)",
|
||||
"StorePrimitiveOutput(outputSigId,rowIndex,colIndex,value,primitiveIndex)",
|
||||
"DispatchMesh(threadGroupCountX,threadGroupCountY,threadGroupCountZ,payload)",
|
||||
"WriteSamplerFeedback(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,clamp)",
|
||||
"WriteSamplerFeedbackBias(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,bias,clamp)",
|
||||
"WriteSamplerFeedbackLevel(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,lod)",
|
||||
"WriteSamplerFeedbackGrad(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)",
|
||||
"AllocateRayQuery(constRayFlags)",
|
||||
"RayQuery_TraceRayInline(rayQueryHandle,accelerationStructure,rayFlags,instanceInclusionMask,origin_X,origin_Y,origin_Z,tMin,direction_X,direction_Y,direction_Z,tMax)",
|
||||
"RayQuery_Proceed(rayQueryHandle)",
|
||||
"RayQuery_Abort(rayQueryHandle)",
|
||||
"RayQuery_CommitNonOpaqueTriangleHit(rayQueryHandle)",
|
||||
"RayQuery_CommitProceduralPrimitiveHit(rayQueryHandle,t)",
|
||||
"RayQuery_CommittedStatus(rayQueryHandle)",
|
||||
"RayQuery_CandidateType(rayQueryHandle)",
|
||||
"RayQuery_CandidateObjectToWorld3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CandidateWorldToObject3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CommittedObjectToWorld3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CommittedWorldToObject3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CandidateProceduralPrimitiveNonOpaque(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleFrontFace(rayQueryHandle)",
|
||||
"RayQuery_CommittedTriangleFrontFace(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleBarycentrics(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedTriangleBarycentrics(rayQueryHandle,component)",
|
||||
"RayQuery_RayFlags(rayQueryHandle)",
|
||||
"RayQuery_WorldRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_WorldRayDirection(rayQueryHandle,component)",
|
||||
"RayQuery_RayTMin(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleRayT(rayQueryHandle)",
|
||||
"RayQuery_CommittedRayT(rayQueryHandle)",
|
||||
"RayQuery_CandidateInstanceIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidateInstanceID(rayQueryHandle)",
|
||||
"RayQuery_CandidateGeometryIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidatePrimitiveIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidateObjectRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_CandidateObjectRayDirection(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedInstanceIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedInstanceID(rayQueryHandle)",
|
||||
"RayQuery_CommittedGeometryIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedPrimitiveIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedObjectRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedObjectRayDirection(rayQueryHandle,component)",
|
||||
"GeometryIndex()",
|
||||
"RayQuery_CandidateInstanceContributionToHitGroupIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedInstanceContributionToHitGroupIndex(rayQueryHandle)",
|
||||
"CreateHandleFromHeap(index,nonUniformIndex)",
|
||||
"AnnotateHandle(res,resourceClass,resourceKind,props)"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
m_Disassembly = StringFormat::Fmt("; %s Shader, compiled under SM%u.%u\n\n",
|
||||
shaderName[int(m_Type)], m_Major, m_Minor);
|
||||
m_Disassembly += StringFormat::Fmt("target datalayout = \"%s\"\n", m_Datalayout.c_str());
|
||||
m_Disassembly += StringFormat::Fmt("target triple = \"%s\"\n\n", m_Triple.c_str());
|
||||
|
||||
int instructionLine = 6;
|
||||
|
||||
bool typesPrinted = false;
|
||||
|
||||
for(size_t i = 0; i < m_Types.size(); i++)
|
||||
{
|
||||
const Type &typ = m_Types[i];
|
||||
|
||||
if(typ.type == Type::Struct && !typ.name.empty())
|
||||
{
|
||||
rdcstr name = typ.toString();
|
||||
m_Disassembly += StringFormat::Fmt("%s = type {", name.c_str());
|
||||
bool first = true;
|
||||
for(const Type *t : typ.members)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
first = false;
|
||||
m_Disassembly += StringFormat::Fmt(" %s", t->toString().c_str());
|
||||
}
|
||||
m_Disassembly += " }\n";
|
||||
typesPrinted = true;
|
||||
|
||||
instructionLine++;
|
||||
}
|
||||
}
|
||||
|
||||
if(typesPrinted)
|
||||
{
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_GlobalVars.size(); i++)
|
||||
{
|
||||
const GlobalVar &g = m_GlobalVars[i];
|
||||
|
||||
m_Disassembly += StringFormat::Fmt("@%s = ", escapeStringIfNeeded(g.name).c_str());
|
||||
if(g.external)
|
||||
m_Disassembly += "external ";
|
||||
if(g.isconst)
|
||||
m_Disassembly += "constant ";
|
||||
m_Disassembly += g.type->toString();
|
||||
|
||||
if(g.align > 0)
|
||||
m_Disassembly += StringFormat::Fmt(", align %u", g.align);
|
||||
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
if(!m_GlobalVars.empty())
|
||||
{
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
rdcstr namedMeta;
|
||||
|
||||
// need to disassemble the named metadata here so the IDs are assigned first before any functions
|
||||
// get dibs
|
||||
for(size_t i = 0; i < m_NamedMeta.size(); i++)
|
||||
{
|
||||
namedMeta += StringFormat::Fmt("!%s = %s!{", m_NamedMeta[i].name.c_str(),
|
||||
m_NamedMeta[i].distinct ? "distinct " : "");
|
||||
for(size_t m = 0; m < m_NamedMeta[i].children.size(); m++)
|
||||
{
|
||||
if(m != 0)
|
||||
namedMeta += ", ";
|
||||
if(m_NamedMeta[i].children[m])
|
||||
namedMeta += StringFormat::Fmt("!%u", GetOrAssignMetaID(m_NamedMeta[i].children[m]));
|
||||
else
|
||||
namedMeta += "null";
|
||||
}
|
||||
|
||||
namedMeta += "}\n";
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_Functions.size(); i++)
|
||||
{
|
||||
Function &func = m_Functions[i];
|
||||
|
||||
auto argToString = [this, &func](Symbol s) {
|
||||
rdcstr ret;
|
||||
switch(s.type)
|
||||
{
|
||||
case SymbolType::Unknown:
|
||||
case SymbolType::Alias:
|
||||
case SymbolType::Literal: ret = "???"; break;
|
||||
case SymbolType::Metadata:
|
||||
if(s.idx < m_Metadata.size())
|
||||
ret += StringFormat::Fmt("metadata !%u", GetOrAssignMetaID(&m_Metadata[s.idx]));
|
||||
else
|
||||
ret = "metadata " + GetFunctionMetadata(func, s.idx)->refString();
|
||||
break;
|
||||
case SymbolType::Function: ret = "@" + escapeStringIfNeeded(m_Functions[s.idx].name); break;
|
||||
case SymbolType::GlobalVar:
|
||||
ret = "@" + escapeStringIfNeeded(m_GlobalVars[s.idx].name);
|
||||
break;
|
||||
case SymbolType::Constant: ret = GetFunctionValue(func, s.idx)->toString(); break;
|
||||
case SymbolType::Argument: ret = "%" + escapeStringIfNeeded(func.args[s.idx].name); break;
|
||||
case SymbolType::Instruction:
|
||||
{
|
||||
const Instruction &refinst = func.instructions[s.idx];
|
||||
if(refinst.name.empty())
|
||||
ret = StringFormat::Fmt("%s %%%u", refinst.type->toString().c_str(), refinst.resultID);
|
||||
else
|
||||
ret = StringFormat::Fmt("%s %%%s", refinst.type->toString().c_str(),
|
||||
escapeStringIfNeeded(refinst.name).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
if(func.attrs)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt("; Function Attrs: %s\n", func.attrs->toString().c_str());
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
m_Disassembly += (func.external ? "declare " : "define ");
|
||||
m_Disassembly += func.funcType->declFunction("@" + escapeStringIfNeeded(func.name));
|
||||
|
||||
if(func.attrs)
|
||||
m_Disassembly += StringFormat::Fmt(" #%u", func.attrs->index);
|
||||
|
||||
if(!func.external)
|
||||
{
|
||||
m_Disassembly += " {\n";
|
||||
instructionLine++;
|
||||
|
||||
for(Instruction &inst : func.instructions)
|
||||
{
|
||||
inst.disassemblyLine = instructionLine;
|
||||
m_Disassembly += " ";
|
||||
if(!inst.name.empty())
|
||||
m_Disassembly += "%" + escapeStringIfNeeded(inst.name) + " = ";
|
||||
else if(inst.resultID != ~0U)
|
||||
m_Disassembly += StringFormat::Fmt("%%%u = ", inst.resultID);
|
||||
|
||||
bool debugCall = false;
|
||||
|
||||
switch(inst.op)
|
||||
{
|
||||
case Instruction::Unknown: m_Disassembly += "??? "; break;
|
||||
case Instruction::Call:
|
||||
{
|
||||
m_Disassembly += "call " + inst.type->toString();
|
||||
m_Disassembly += " @" + escapeStringIfNeeded(inst.funcCall->name);
|
||||
m_Disassembly += "(";
|
||||
bool first = true;
|
||||
for(Symbol &s : inst.args)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
first = false;
|
||||
|
||||
m_Disassembly += argToString(s);
|
||||
}
|
||||
m_Disassembly += ")";
|
||||
debugCall = inst.funcCall->name.beginsWith("llvm.dbg.");
|
||||
break;
|
||||
}
|
||||
case Instruction::Trunc: m_Disassembly += "trunc "; break;
|
||||
case Instruction::ZExt: m_Disassembly += "zext "; break;
|
||||
case Instruction::SExt: m_Disassembly += "sext "; break;
|
||||
case Instruction::FToU: m_Disassembly += "fptoui "; break;
|
||||
case Instruction::FToS:
|
||||
{
|
||||
m_Disassembly += "fptosi ";
|
||||
m_Disassembly += argToString(inst.args[0]);
|
||||
m_Disassembly += " to ";
|
||||
m_Disassembly += inst.type->toString();
|
||||
break;
|
||||
}
|
||||
case Instruction::UToF: m_Disassembly += "uitofp "; break;
|
||||
case Instruction::SToF: m_Disassembly += "sitofp "; break;
|
||||
case Instruction::FPTrunc: m_Disassembly += "fptrunc "; break;
|
||||
case Instruction::FPExt: m_Disassembly += "fpext "; break;
|
||||
case Instruction::PtrToI: m_Disassembly += "ptrtoi "; break;
|
||||
case Instruction::IToPtr: m_Disassembly += "itoptr "; break;
|
||||
case Instruction::Bitcast: m_Disassembly += "bitcast "; break;
|
||||
case Instruction::AddrSpaceCast: m_Disassembly += "addrspacecast "; break;
|
||||
case Instruction::ExtractVal:
|
||||
{
|
||||
m_Disassembly += "extractvalue ";
|
||||
m_Disassembly += argToString(inst.args[0]);
|
||||
for(size_t n = 1; n < inst.args.size(); n++)
|
||||
m_Disassembly += StringFormat::Fmt(", %llu", inst.args[n].idx);
|
||||
break;
|
||||
}
|
||||
case Instruction::Ret: m_Disassembly += "ret " + inst.type->toString(); break;
|
||||
}
|
||||
|
||||
if(inst.debugLoc != ~0U)
|
||||
{
|
||||
DebugLocation &debugLoc = m_DebugLocations[inst.debugLoc];
|
||||
|
||||
m_Disassembly += StringFormat::Fmt(", !dbg !%u", GetOrAssignMetaID(debugLoc));
|
||||
|
||||
if(!debugCall && debugLoc.line > 0)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt(" ; line:%llu col:%llu", debugLoc.line, debugLoc.col);
|
||||
}
|
||||
}
|
||||
|
||||
if(debugCall)
|
||||
{
|
||||
if(inst.funcCall->name == "llvm.dbg.value" || inst.funcCall->name == "llvm.dbg.declare")
|
||||
{
|
||||
RDCASSERT(inst.args[2].type == SymbolType::Metadata);
|
||||
RDCASSERT(inst.args[3].type == SymbolType::Metadata);
|
||||
m_Disassembly += StringFormat::Fmt(
|
||||
" ; var:%s ",
|
||||
escapeString(GetDebugVarName(GetFunctionMetadata(func, inst.args[2].idx)->dwarf)));
|
||||
m_Disassembly += GetFunctionMetadata(func, inst.args[3].idx)->valString();
|
||||
}
|
||||
}
|
||||
|
||||
if(inst.funcCall && inst.funcCall->name.beginsWith("dx.op."))
|
||||
{
|
||||
if(inst.args[0].type == SymbolType::Constant)
|
||||
{
|
||||
uint32_t opcode = GetFunctionValue(func, inst.args[0].idx)->val.uv[0];
|
||||
if(opcode < ARRAY_COUNT(funcSigs))
|
||||
{
|
||||
m_Disassembly += " ; ";
|
||||
m_Disassembly += funcSigs[opcode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
m_Disassembly += "}\n\n";
|
||||
instructionLine += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Disassembly += "\n\n";
|
||||
instructionLine += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_Attributes.size(); i++)
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt("attributes #%zu = { %s }\n", i, m_Attributes[i].toString().c_str());
|
||||
|
||||
if(!m_Attributes.empty())
|
||||
m_Disassembly += "\n";
|
||||
|
||||
m_Disassembly += namedMeta + "\n";
|
||||
|
||||
size_t numIdx = 0;
|
||||
size_t dbgIdx = 0;
|
||||
|
||||
for(uint32_t i = 0; i < m_NextMetaID; i++)
|
||||
{
|
||||
if(numIdx < m_NumberedMeta.size() && m_NumberedMeta[numIdx]->id == i)
|
||||
{
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt("!%u = %s%s\n", i, m_NumberedMeta[numIdx]->distinct ? "distinct " : "",
|
||||
m_NumberedMeta[numIdx]->valString().c_str());
|
||||
numIdx++;
|
||||
}
|
||||
else if(dbgIdx < m_DebugLocations.size() && m_DebugLocations[dbgIdx].id == i)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt("!%u = !DILocation(line: %llu, column: %llu, scope: %s", i,
|
||||
m_DebugLocations[dbgIdx].line, m_DebugLocations[dbgIdx].col,
|
||||
m_DebugLocations[dbgIdx].scope
|
||||
? m_DebugLocations[dbgIdx].scope->refString().c_str()
|
||||
: "null");
|
||||
if(m_DebugLocations[dbgIdx].inlinedAt)
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt(", inlinedAt: %s", m_DebugLocations[dbgIdx].inlinedAt->refString());
|
||||
m_Disassembly += ")\n";
|
||||
dbgIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Couldn't find meta ID %u", i);
|
||||
}
|
||||
}
|
||||
|
||||
m_Disassembly += "\n";
|
||||
}
|
||||
|
||||
uint32_t Program::GetOrAssignMetaID(Metadata *m)
|
||||
{
|
||||
if(m->id != ~0U)
|
||||
@@ -2251,334 +1693,9 @@ const Metadata *Program::GetFunctionMetadata(const Function &f, uint64_t v)
|
||||
return idx < m_Metadata.size() ? &m_Metadata[idx] : &f.metadata[idx - m_Metadata.size()];
|
||||
}
|
||||
|
||||
rdcstr Type::toString() const
|
||||
{
|
||||
if(!name.empty())
|
||||
{
|
||||
return "%" + escapeStringIfNeeded(name);
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case Void: return "void";
|
||||
case Scalar:
|
||||
{
|
||||
switch(scalarType)
|
||||
{
|
||||
case Void: return "void";
|
||||
case Int: return StringFormat::Fmt("i%u", bitWidth);
|
||||
case Float:
|
||||
switch(bitWidth)
|
||||
{
|
||||
case 16: return "half";
|
||||
case 32: return "float";
|
||||
case 64: return "double";
|
||||
default: return StringFormat::Fmt("fp%u", bitWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Vector: return StringFormat::Fmt("<%u x %s>", elemCount, inner->toString().c_str());
|
||||
case Pointer: return StringFormat::Fmt("%s*", inner->toString().c_str());
|
||||
case Array: return StringFormat::Fmt("[%u x %s]", elemCount, inner->toString().c_str());
|
||||
case Function: return declFunction(rdcstr());
|
||||
case Struct:
|
||||
{
|
||||
rdcstr ret;
|
||||
if(packedStruct)
|
||||
ret = "<{";
|
||||
else
|
||||
ret = "{";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
ret += members[i]->toString();
|
||||
}
|
||||
if(packedStruct)
|
||||
ret += "}>";
|
||||
else
|
||||
ret += "}";
|
||||
return ret;
|
||||
}
|
||||
|
||||
case Metadata: return "metadata";
|
||||
case Label: return "label";
|
||||
default: return "unknown_type";
|
||||
}
|
||||
}
|
||||
|
||||
rdcstr Type::declFunction(rdcstr funcName) const
|
||||
{
|
||||
rdcstr ret = inner->toString();
|
||||
ret += " " + funcName + "(";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
ret += members[i]->toString();
|
||||
}
|
||||
ret += ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcstr Attributes::toString() const
|
||||
{
|
||||
rdcstr ret = "";
|
||||
Attribute p = params;
|
||||
|
||||
if(p & Attribute::Alignment)
|
||||
{
|
||||
ret += StringFormat::Fmt(" align=%llu", align);
|
||||
p &= ~Attribute::Alignment;
|
||||
}
|
||||
if(p & Attribute::StackAlignment)
|
||||
{
|
||||
ret += StringFormat::Fmt(" alignstack=%llu", stackAlign);
|
||||
p &= ~Attribute::StackAlignment;
|
||||
}
|
||||
if(p & Attribute::Dereferenceable)
|
||||
{
|
||||
ret += StringFormat::Fmt(" dereferenceable=%llu", derefBytes);
|
||||
p &= ~Attribute::Dereferenceable;
|
||||
}
|
||||
if(p & Attribute::DereferenceableOrNull)
|
||||
{
|
||||
ret += StringFormat::Fmt(" dereferenceable_or_null=%llu", derefOrNullBytes);
|
||||
p &= ~Attribute::DereferenceableOrNull;
|
||||
}
|
||||
|
||||
if(p != Attribute::None)
|
||||
{
|
||||
ret = ToStr(p) + " " + ret;
|
||||
int offs = ret.indexOf('|');
|
||||
while(offs >= 0)
|
||||
{
|
||||
ret.erase((size_t)offs, 2);
|
||||
offs = ret.indexOf('|');
|
||||
}
|
||||
}
|
||||
|
||||
for(const rdcpair<rdcstr, rdcstr> &str : strs)
|
||||
ret += " " + escapeString(str.first) + "=" + escapeString(str.second);
|
||||
|
||||
return ret.trimmed();
|
||||
}
|
||||
|
||||
Metadata::~Metadata()
|
||||
{
|
||||
SAFE_DELETE(dwarf);
|
||||
}
|
||||
|
||||
rdcstr Metadata::refString() const
|
||||
{
|
||||
if(id == ~0U)
|
||||
return valString();
|
||||
return StringFormat::Fmt("!%u", id);
|
||||
}
|
||||
|
||||
rdcstr Metadata::valString() const
|
||||
{
|
||||
if(dwarf)
|
||||
{
|
||||
return dwarf->toString();
|
||||
}
|
||||
else if(value)
|
||||
{
|
||||
if(type == NULL)
|
||||
{
|
||||
return StringFormat::Fmt("!%s", escapeString(str).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(val)
|
||||
{
|
||||
if(type != val->type)
|
||||
RDCERR("Type mismatch in metadata");
|
||||
return val->toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(func && instruction < func->instructions.size())
|
||||
{
|
||||
const Instruction &inst = func->instructions[instruction];
|
||||
if(inst.name.empty())
|
||||
return StringFormat::Fmt("%s %%%u", inst.type->toString().c_str(), inst.resultID);
|
||||
else
|
||||
return StringFormat::Fmt("%s %%%s", inst.type->toString().c_str(),
|
||||
escapeStringIfNeeded(inst.name).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("No instruction symbol for value-less metadata");
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rdcstr ret = "!{";
|
||||
for(size_t i = 0; i < children.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
if(!children[i])
|
||||
ret += "null";
|
||||
else if(children[i]->value)
|
||||
ret += children[i]->valString();
|
||||
else
|
||||
ret += StringFormat::Fmt("!%u", children[i]->id);
|
||||
}
|
||||
ret += "}";
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
rdcstr Value::toString() const
|
||||
{
|
||||
if(type == NULL)
|
||||
return escapeString(str);
|
||||
|
||||
rdcstr ret;
|
||||
ret += type->toString() + " ";
|
||||
if(undef)
|
||||
{
|
||||
ret += "undef";
|
||||
}
|
||||
else if(symbol)
|
||||
{
|
||||
ret += StringFormat::Fmt("@%s", escapeStringIfNeeded(str).c_str());
|
||||
}
|
||||
else if(type->type == Type::Scalar)
|
||||
{
|
||||
if(type->scalarType == Type::Float)
|
||||
{
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lf", val.dv[0]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%f", val.fv[0]);
|
||||
}
|
||||
else if(type->scalarType == Type::Int)
|
||||
{
|
||||
// LLVM seems to always interpret these as signed? :(
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lld", val.u64v[0]);
|
||||
else if(type->bitWidth == 1)
|
||||
ret += val.uv[0] ? "true" : "false";
|
||||
else
|
||||
ret += StringFormat::Fmt("%d", val.uv[0]);
|
||||
}
|
||||
}
|
||||
else if(type->type == Type::Vector)
|
||||
{
|
||||
ret += "<";
|
||||
for(uint32_t i = 0; i < type->elemCount; i++)
|
||||
{
|
||||
if(type->scalarType == Type::Float)
|
||||
{
|
||||
// TODO need to know how to determine signedness here
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lf", val.dv[i]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%f", val.fv[i]);
|
||||
}
|
||||
else if(type->scalarType == Type::Int)
|
||||
{
|
||||
// TODO need to know how to determine signedness here
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%llu", val.u64v[i]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%u", val.uv[i]);
|
||||
}
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
else if(type->type == Type::Array)
|
||||
{
|
||||
ret += "[";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
|
||||
ret += members[i].toString();
|
||||
}
|
||||
ret += "]";
|
||||
}
|
||||
else if(type->type == Type::Struct)
|
||||
{
|
||||
ret += "{";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
|
||||
ret += members[i].toString();
|
||||
}
|
||||
ret += "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += StringFormat::Fmt("unsupported type %u", type->type);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}; // namespace DXIL
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const DXIL::Attribute &el)
|
||||
{
|
||||
BEGIN_BITFIELD_STRINGISE(DXIL::Attribute);
|
||||
{
|
||||
STRINGISE_BITFIELD_CLASS_VALUE_NAMED(None, "");
|
||||
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Alignment, "align");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(AlwaysInline, "alwaysinline");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ByVal, "byval");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InlineHint, "inlinehint");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InReg, "inreg");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(MinSize, "minsize");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Naked, "naked");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Nest, "nest");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoAlias, "noalias");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoBuiltin, "nobuiltin");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoCapture, "nocapture");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoDuplicate, "noduplicate");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoImplicitFloat, "noimplicitfloat");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoInline, "noinline");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NonLazyBind, "nonlazybind");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoRedZone, "noredzone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoReturn, "noreturn");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoUnwind, "nounwind");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(OptimizeForSize, "optsize");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReadNone, "readnone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReadOnly, "readonly");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Returned, "returned");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReturnsTwice, "returns_twice");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SExt, "signext");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackAlignment, "alignstack");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtect, "ssp");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtectReq, "sspreq");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtectStrong, "sspstrong");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StructRet, "sret");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeAddress, "sanitize_address");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeThread, "sanitize_thread");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeMemory, "sanitize_memory");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(UWTable, "uwtable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ZExt, "zeroext");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Builtin, "builtin");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Cold, "cold");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(OptimizeNone, "optnone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InAlloca, "inalloca");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NonNull, "nonnull");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(JumpTable, "jumptable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Dereferenceable, "dereferenceable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(DereferenceableOrNull, "dereferenceable_or_null");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Convergent, "convergent");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SafeStack, "safestack");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ArgMemOnly, "argmemonly");
|
||||
}
|
||||
END_BITFIELD_STRINGISE();
|
||||
}
|
||||
|
||||
@@ -384,4 +384,8 @@ private:
|
||||
rdcstr m_Disassembly;
|
||||
};
|
||||
|
||||
bool needsEscaping(const rdcstr &name);
|
||||
rdcstr escapeString(rdcstr str);
|
||||
rdcstr escapeStringIfNeeded(const rdcstr &name);
|
||||
|
||||
}; // namespace DXIL
|
||||
|
||||
@@ -73,9 +73,6 @@ enum class MetaDataRecord : uint32_t
|
||||
COMMON_BLOCK = 44,
|
||||
};
|
||||
|
||||
bool needsEscaping(const rdcstr &name);
|
||||
rdcstr escapeString(rdcstr str);
|
||||
|
||||
bool Program::ParseDebugMetaRecord(const LLVMBC::BlockOrRecord &metaRecord, Metadata &meta)
|
||||
{
|
||||
MetaDataRecord id = (MetaDataRecord)metaRecord.id;
|
||||
|
||||
@@ -0,0 +1,914 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2020 Baldur Karlsson
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
#include "common/formatting.h"
|
||||
#include "dxil_bytecode.h"
|
||||
|
||||
namespace DXIL
|
||||
{
|
||||
bool needsEscaping(const rdcstr &name)
|
||||
{
|
||||
return name.find_first_not_of(
|
||||
"-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789") >= 0;
|
||||
}
|
||||
|
||||
rdcstr escapeString(rdcstr str)
|
||||
{
|
||||
for(size_t i = 0; i < str.size(); i++)
|
||||
{
|
||||
if(str[i] == '\'' || str[i] == '\\')
|
||||
{
|
||||
str.insert(i, "\\", 1);
|
||||
i++;
|
||||
}
|
||||
else if(str[i] == '\r' || str[i] == '\n' || str[i] == '\t' || !isprint(str[i]))
|
||||
{
|
||||
str.insert(i + 1, StringFormat::Fmt("%02X", str[i]));
|
||||
str[i] = '\\';
|
||||
}
|
||||
}
|
||||
|
||||
str.push_back('"');
|
||||
str.insert(0, '"');
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
rdcstr escapeStringIfNeeded(const rdcstr &name)
|
||||
{
|
||||
return needsEscaping(name) ? escapeString(name) : name;
|
||||
}
|
||||
|
||||
void Program::MakeDisassemblyString()
|
||||
{
|
||||
const char *shaderName[] = {
|
||||
"Pixel", "Vertex", "Geometry", "Hull", "Domain",
|
||||
"Compute", "Library", "RayGeneration", "Intersection", "AnyHit",
|
||||
"ClosestHit", "Miss", "Callable", "Mesh", "Amplification",
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
static const char *funcSigs[] = {
|
||||
"TempRegLoad(index)",
|
||||
"TempRegStore(index,value)",
|
||||
"MinPrecXRegLoad(regIndex,index,component)",
|
||||
"MinPrecXRegStore(regIndex,index,component,value)",
|
||||
"LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)",
|
||||
"StoreOutput(outputSigId,rowIndex,colIndex,value)",
|
||||
"FAbs(value)",
|
||||
"Saturate(value)",
|
||||
"IsNaN(value)",
|
||||
"IsInf(value)",
|
||||
"IsFinite(value)",
|
||||
"IsNormal(value)",
|
||||
"Cos(value)",
|
||||
"Sin(value)",
|
||||
"Tan(value)",
|
||||
"Acos(value)",
|
||||
"Asin(value)",
|
||||
"Atan(value)",
|
||||
"Hcos(value)",
|
||||
"Hsin(value)",
|
||||
"Htan(value)",
|
||||
"Exp(value)",
|
||||
"Frc(value)",
|
||||
"Log(value)",
|
||||
"Sqrt(value)",
|
||||
"Rsqrt(value)",
|
||||
"Round_ne(value)",
|
||||
"Round_ni(value)",
|
||||
"Round_pi(value)",
|
||||
"Round_z(value)",
|
||||
"Bfrev(value)",
|
||||
"Countbits(value)",
|
||||
"FirstbitLo(value)",
|
||||
"FirstbitHi(value)",
|
||||
"FirstbitSHi(value)",
|
||||
"FMax(a,b)",
|
||||
"FMin(a,b)",
|
||||
"IMax(a,b)",
|
||||
"IMin(a,b)",
|
||||
"UMax(a,b)",
|
||||
"UMin(a,b)",
|
||||
"IMul(a,b)",
|
||||
"UMul(a,b)",
|
||||
"UDiv(a,b)",
|
||||
"UAddc(a,b)",
|
||||
"USubb(a,b)",
|
||||
"FMad(a,b,c)",
|
||||
"Fma(a,b,c)",
|
||||
"IMad(a,b,c)",
|
||||
"UMad(a,b,c)",
|
||||
"Msad(a,b,c)",
|
||||
"Ibfe(a,b,c)",
|
||||
"Ubfe(a,b,c)",
|
||||
"Bfi(width,offset,value,replacedValue)",
|
||||
"Dot2(ax,ay,bx,by)",
|
||||
"Dot3(ax,ay,az,bx,by,bz)",
|
||||
"Dot4(ax,ay,az,aw,bx,by,bz,bw)",
|
||||
"CreateHandle(resourceClass,rangeId,index,nonUniformIndex)",
|
||||
"CBufferLoad(handle,byteOffset,alignment)",
|
||||
"CBufferLoadLegacy(handle,regIndex)",
|
||||
"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)",
|
||||
"TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)",
|
||||
"TextureStore(srv,coord0,coord1,coord2,value0,value1,value2,value3,mask)",
|
||||
"BufferLoad(srv,index,wot)",
|
||||
"BufferStore(uav,coord0,coord1,value0,value1,value2,value3,mask)",
|
||||
"BufferUpdateCounter(uav,inc)",
|
||||
"CheckAccessFullyMapped(status)",
|
||||
"GetDimensions(handle,mipLevel)",
|
||||
"TextureGather(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel)",
|
||||
"TextureGatherCmp(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel,compareVale)",
|
||||
"Texture2DMSGetSamplePosition(srv,index)",
|
||||
"RenderTargetGetSamplePosition(index)",
|
||||
"RenderTargetGetSampleCount()",
|
||||
"AtomicBinOp(handle,atomicOp,offset0,offset1,offset2,newValue)",
|
||||
"AtomicCompareExchange(handle,offset0,offset1,offset2,compareValue,newValue)",
|
||||
"Barrier(barrierMode)",
|
||||
"CalculateLOD(handle,sampler,coord0,coord1,coord2,clamped)",
|
||||
"Discard(condition)",
|
||||
"DerivCoarseX(value)",
|
||||
"DerivCoarseY(value)",
|
||||
"DerivFineX(value)",
|
||||
"DerivFineY(value)",
|
||||
"EvalSnapped(inputSigId,inputRowIndex,inputColIndex,offsetX,offsetY)",
|
||||
"EvalSampleIndex(inputSigId,inputRowIndex,inputColIndex,sampleIndex)",
|
||||
"EvalCentroid(inputSigId,inputRowIndex,inputColIndex)",
|
||||
"SampleIndex()",
|
||||
"Coverage()",
|
||||
"InnerCoverage()",
|
||||
"ThreadId(component)",
|
||||
"GroupId(component)",
|
||||
"ThreadIdInGroup(component)",
|
||||
"FlattenedThreadIdInGroup()",
|
||||
"EmitStream(streamId)",
|
||||
"CutStream(streamId)",
|
||||
"EmitThenCutStream(streamId)",
|
||||
"GSInstanceID()",
|
||||
"MakeDouble(lo,hi)",
|
||||
"SplitDouble(value)",
|
||||
"LoadOutputControlPoint(inputSigId,row,col,index)",
|
||||
"LoadPatchConstant(inputSigId,row,col)",
|
||||
"DomainLocation(component)",
|
||||
"StorePatchConstant(outputSigID,row,col,value)",
|
||||
"OutputControlPointID()",
|
||||
"PrimitiveID()",
|
||||
"CycleCounterLegacy()",
|
||||
"WaveIsFirstLane()",
|
||||
"WaveGetLaneIndex()",
|
||||
"WaveGetLaneCount()",
|
||||
"WaveAnyTrue(cond)",
|
||||
"WaveAllTrue(cond)",
|
||||
"WaveActiveAllEqual(value)",
|
||||
"WaveActiveBallot(cond)",
|
||||
"WaveReadLaneAt(value,lane)",
|
||||
"WaveReadLaneFirst(value)",
|
||||
"WaveActiveOp(value,op,sop)",
|
||||
"WaveActiveBit(value,op)",
|
||||
"WavePrefixOp(value,op,sop)",
|
||||
"QuadReadLaneAt(value,quadLane)",
|
||||
"QuadOp(value,op)",
|
||||
"BitcastI16toF16(value)",
|
||||
"BitcastF16toI16(value)",
|
||||
"BitcastI32toF32(value)",
|
||||
"BitcastF32toI32(value)",
|
||||
"BitcastI64toF64(value)",
|
||||
"BitcastF64toI64(value)",
|
||||
"LegacyF32ToF16(value)",
|
||||
"LegacyF16ToF32(value)",
|
||||
"LegacyDoubleToFloat(value)",
|
||||
"LegacyDoubleToSInt32(value)",
|
||||
"LegacyDoubleToUInt32(value)",
|
||||
"WaveAllBitCount(value)",
|
||||
"WavePrefixBitCount(value)",
|
||||
"AttributeAtVertex(inputSigId,inputRowIndex,inputColIndex,VertexID)",
|
||||
"ViewID()",
|
||||
"RawBufferLoad(srv,index,elementOffset,mask,alignment)",
|
||||
"RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)",
|
||||
"InstanceID()",
|
||||
"InstanceIndex()",
|
||||
"HitKind()",
|
||||
"RayFlags()",
|
||||
"DispatchRaysIndex(col)",
|
||||
"DispatchRaysDimensions(col)",
|
||||
"WorldRayOrigin(col)",
|
||||
"WorldRayDirection(col)",
|
||||
"ObjectRayOrigin(col)",
|
||||
"ObjectRayDirection(col)",
|
||||
"ObjectToWorld(row,col)",
|
||||
"WorldToObject(row,col)",
|
||||
"RayTMin()",
|
||||
"RayTCurrent()",
|
||||
"IgnoreHit()",
|
||||
"AcceptHitAndEndSearch()",
|
||||
"TraceRay(AccelerationStructure,RayFlags,InstanceInclusionMask,RayContributionToHitGroupIndex,MultiplierForGeometryContributionToShaderIndex,MissShaderIndex,Origin_X,Origin_Y,Origin_Z,TMin,Direction_X,Direction_Y,Direction_Z,TMax,payload)",
|
||||
"ReportHit(THit,HitKind,Attributes)",
|
||||
"CallShader(ShaderIndex,Parameter)",
|
||||
"CreateHandleForLib(Resource)",
|
||||
"PrimitiveIndex()",
|
||||
"Dot2AddHalf(acc,ax,ay,bx,by)",
|
||||
"Dot4AddI8Packed(acc,a,b)",
|
||||
"Dot4AddU8Packed(acc,a,b)",
|
||||
"WaveMatch(value)",
|
||||
"WaveMultiPrefixOp(value,mask0,mask1,mask2,mask3,op,sop)",
|
||||
"WaveMultiPrefixBitCount(value,mask0,mask1,mask2,mask3)",
|
||||
"SetMeshOutputCounts(numVertices,numPrimitives)",
|
||||
"EmitIndices(PrimitiveIndex,VertexIndex0,VertexIndex1,VertexIndex2)",
|
||||
"GetMeshPayload()",
|
||||
"StoreVertexOutput(outputSigId,rowIndex,colIndex,value,vertexIndex)",
|
||||
"StorePrimitiveOutput(outputSigId,rowIndex,colIndex,value,primitiveIndex)",
|
||||
"DispatchMesh(threadGroupCountX,threadGroupCountY,threadGroupCountZ,payload)",
|
||||
"WriteSamplerFeedback(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,clamp)",
|
||||
"WriteSamplerFeedbackBias(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,bias,clamp)",
|
||||
"WriteSamplerFeedbackLevel(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,lod)",
|
||||
"WriteSamplerFeedbackGrad(feedbackTex,sampledTex,sampler,c0,c1,c2,c3,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)",
|
||||
"AllocateRayQuery(constRayFlags)",
|
||||
"RayQuery_TraceRayInline(rayQueryHandle,accelerationStructure,rayFlags,instanceInclusionMask,origin_X,origin_Y,origin_Z,tMin,direction_X,direction_Y,direction_Z,tMax)",
|
||||
"RayQuery_Proceed(rayQueryHandle)",
|
||||
"RayQuery_Abort(rayQueryHandle)",
|
||||
"RayQuery_CommitNonOpaqueTriangleHit(rayQueryHandle)",
|
||||
"RayQuery_CommitProceduralPrimitiveHit(rayQueryHandle,t)",
|
||||
"RayQuery_CommittedStatus(rayQueryHandle)",
|
||||
"RayQuery_CandidateType(rayQueryHandle)",
|
||||
"RayQuery_CandidateObjectToWorld3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CandidateWorldToObject3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CommittedObjectToWorld3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CommittedWorldToObject3x4(rayQueryHandle,row,col)",
|
||||
"RayQuery_CandidateProceduralPrimitiveNonOpaque(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleFrontFace(rayQueryHandle)",
|
||||
"RayQuery_CommittedTriangleFrontFace(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleBarycentrics(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedTriangleBarycentrics(rayQueryHandle,component)",
|
||||
"RayQuery_RayFlags(rayQueryHandle)",
|
||||
"RayQuery_WorldRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_WorldRayDirection(rayQueryHandle,component)",
|
||||
"RayQuery_RayTMin(rayQueryHandle)",
|
||||
"RayQuery_CandidateTriangleRayT(rayQueryHandle)",
|
||||
"RayQuery_CommittedRayT(rayQueryHandle)",
|
||||
"RayQuery_CandidateInstanceIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidateInstanceID(rayQueryHandle)",
|
||||
"RayQuery_CandidateGeometryIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidatePrimitiveIndex(rayQueryHandle)",
|
||||
"RayQuery_CandidateObjectRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_CandidateObjectRayDirection(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedInstanceIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedInstanceID(rayQueryHandle)",
|
||||
"RayQuery_CommittedGeometryIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedPrimitiveIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedObjectRayOrigin(rayQueryHandle,component)",
|
||||
"RayQuery_CommittedObjectRayDirection(rayQueryHandle,component)",
|
||||
"GeometryIndex()",
|
||||
"RayQuery_CandidateInstanceContributionToHitGroupIndex(rayQueryHandle)",
|
||||
"RayQuery_CommittedInstanceContributionToHitGroupIndex(rayQueryHandle)",
|
||||
"CreateHandleFromHeap(index,nonUniformIndex)",
|
||||
"AnnotateHandle(res,resourceClass,resourceKind,props)"
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
m_Disassembly = StringFormat::Fmt("; %s Shader, compiled under SM%u.%u\n\n",
|
||||
shaderName[int(m_Type)], m_Major, m_Minor);
|
||||
m_Disassembly += StringFormat::Fmt("target datalayout = \"%s\"\n", m_Datalayout.c_str());
|
||||
m_Disassembly += StringFormat::Fmt("target triple = \"%s\"\n\n", m_Triple.c_str());
|
||||
|
||||
int instructionLine = 6;
|
||||
|
||||
bool typesPrinted = false;
|
||||
|
||||
for(size_t i = 0; i < m_Types.size(); i++)
|
||||
{
|
||||
const Type &typ = m_Types[i];
|
||||
|
||||
if(typ.type == Type::Struct && !typ.name.empty())
|
||||
{
|
||||
rdcstr name = typ.toString();
|
||||
m_Disassembly += StringFormat::Fmt("%s = type {", name.c_str());
|
||||
bool first = true;
|
||||
for(const Type *t : typ.members)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
first = false;
|
||||
m_Disassembly += StringFormat::Fmt(" %s", t->toString().c_str());
|
||||
}
|
||||
m_Disassembly += " }\n";
|
||||
typesPrinted = true;
|
||||
|
||||
instructionLine++;
|
||||
}
|
||||
}
|
||||
|
||||
if(typesPrinted)
|
||||
{
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_GlobalVars.size(); i++)
|
||||
{
|
||||
const GlobalVar &g = m_GlobalVars[i];
|
||||
|
||||
m_Disassembly += StringFormat::Fmt("@%s = ", escapeStringIfNeeded(g.name).c_str());
|
||||
if(g.external)
|
||||
m_Disassembly += "external ";
|
||||
if(g.isconst)
|
||||
m_Disassembly += "constant ";
|
||||
m_Disassembly += g.type->toString();
|
||||
|
||||
if(g.align > 0)
|
||||
m_Disassembly += StringFormat::Fmt(", align %u", g.align);
|
||||
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
if(!m_GlobalVars.empty())
|
||||
{
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
rdcstr namedMeta;
|
||||
|
||||
// need to disassemble the named metadata here so the IDs are assigned first before any functions
|
||||
// get dibs
|
||||
for(size_t i = 0; i < m_NamedMeta.size(); i++)
|
||||
{
|
||||
namedMeta += StringFormat::Fmt("!%s = %s!{", m_NamedMeta[i].name.c_str(),
|
||||
m_NamedMeta[i].distinct ? "distinct " : "");
|
||||
for(size_t m = 0; m < m_NamedMeta[i].children.size(); m++)
|
||||
{
|
||||
if(m != 0)
|
||||
namedMeta += ", ";
|
||||
if(m_NamedMeta[i].children[m])
|
||||
namedMeta += StringFormat::Fmt("!%u", GetOrAssignMetaID(m_NamedMeta[i].children[m]));
|
||||
else
|
||||
namedMeta += "null";
|
||||
}
|
||||
|
||||
namedMeta += "}\n";
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_Functions.size(); i++)
|
||||
{
|
||||
Function &func = m_Functions[i];
|
||||
|
||||
auto argToString = [this, &func](Symbol s) {
|
||||
rdcstr ret;
|
||||
switch(s.type)
|
||||
{
|
||||
case SymbolType::Unknown:
|
||||
case SymbolType::Alias:
|
||||
case SymbolType::Literal: ret = "???"; break;
|
||||
case SymbolType::Metadata:
|
||||
if(s.idx < m_Metadata.size())
|
||||
ret += StringFormat::Fmt("metadata !%u", GetOrAssignMetaID(&m_Metadata[s.idx]));
|
||||
else
|
||||
ret = "metadata " + GetFunctionMetadata(func, s.idx)->refString();
|
||||
break;
|
||||
case SymbolType::Function: ret = "@" + escapeStringIfNeeded(m_Functions[s.idx].name); break;
|
||||
case SymbolType::GlobalVar:
|
||||
ret = "@" + escapeStringIfNeeded(m_GlobalVars[s.idx].name);
|
||||
break;
|
||||
case SymbolType::Constant: ret = GetFunctionValue(func, s.idx)->toString(); break;
|
||||
case SymbolType::Argument: ret = "%" + escapeStringIfNeeded(func.args[s.idx].name); break;
|
||||
case SymbolType::Instruction:
|
||||
{
|
||||
const Instruction &refinst = func.instructions[s.idx];
|
||||
if(refinst.name.empty())
|
||||
ret = StringFormat::Fmt("%s %%%u", refinst.type->toString().c_str(), refinst.resultID);
|
||||
else
|
||||
ret = StringFormat::Fmt("%s %%%s", refinst.type->toString().c_str(),
|
||||
escapeStringIfNeeded(refinst.name).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
if(func.attrs)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt("; Function Attrs: %s\n", func.attrs->toString().c_str());
|
||||
instructionLine++;
|
||||
}
|
||||
|
||||
m_Disassembly += (func.external ? "declare " : "define ");
|
||||
m_Disassembly += func.funcType->declFunction("@" + escapeStringIfNeeded(func.name));
|
||||
|
||||
if(func.attrs)
|
||||
m_Disassembly += StringFormat::Fmt(" #%u", func.attrs->index);
|
||||
|
||||
if(!func.external)
|
||||
{
|
||||
m_Disassembly += " {\n";
|
||||
instructionLine++;
|
||||
|
||||
for(Instruction &inst : func.instructions)
|
||||
{
|
||||
inst.disassemblyLine = instructionLine;
|
||||
m_Disassembly += " ";
|
||||
if(!inst.name.empty())
|
||||
m_Disassembly += "%" + escapeStringIfNeeded(inst.name) + " = ";
|
||||
else if(inst.resultID != ~0U)
|
||||
m_Disassembly += StringFormat::Fmt("%%%u = ", inst.resultID);
|
||||
|
||||
bool debugCall = false;
|
||||
|
||||
switch(inst.op)
|
||||
{
|
||||
case Instruction::Unknown: m_Disassembly += "??? "; break;
|
||||
case Instruction::Call:
|
||||
{
|
||||
m_Disassembly += "call " + inst.type->toString();
|
||||
m_Disassembly += " @" + escapeStringIfNeeded(inst.funcCall->name);
|
||||
m_Disassembly += "(";
|
||||
bool first = true;
|
||||
for(Symbol &s : inst.args)
|
||||
{
|
||||
if(!first)
|
||||
m_Disassembly += ", ";
|
||||
first = false;
|
||||
|
||||
m_Disassembly += argToString(s);
|
||||
}
|
||||
m_Disassembly += ")";
|
||||
debugCall = inst.funcCall->name.beginsWith("llvm.dbg.");
|
||||
break;
|
||||
}
|
||||
case Instruction::Trunc: m_Disassembly += "trunc "; break;
|
||||
case Instruction::ZExt: m_Disassembly += "zext "; break;
|
||||
case Instruction::SExt: m_Disassembly += "sext "; break;
|
||||
case Instruction::FToU: m_Disassembly += "fptoui "; break;
|
||||
case Instruction::FToS:
|
||||
{
|
||||
m_Disassembly += "fptosi ";
|
||||
m_Disassembly += argToString(inst.args[0]);
|
||||
m_Disassembly += " to ";
|
||||
m_Disassembly += inst.type->toString();
|
||||
break;
|
||||
}
|
||||
case Instruction::UToF: m_Disassembly += "uitofp "; break;
|
||||
case Instruction::SToF: m_Disassembly += "sitofp "; break;
|
||||
case Instruction::FPTrunc: m_Disassembly += "fptrunc "; break;
|
||||
case Instruction::FPExt: m_Disassembly += "fpext "; break;
|
||||
case Instruction::PtrToI: m_Disassembly += "ptrtoi "; break;
|
||||
case Instruction::IToPtr: m_Disassembly += "itoptr "; break;
|
||||
case Instruction::Bitcast: m_Disassembly += "bitcast "; break;
|
||||
case Instruction::AddrSpaceCast: m_Disassembly += "addrspacecast "; break;
|
||||
case Instruction::ExtractVal:
|
||||
{
|
||||
m_Disassembly += "extractvalue ";
|
||||
m_Disassembly += argToString(inst.args[0]);
|
||||
for(size_t n = 1; n < inst.args.size(); n++)
|
||||
m_Disassembly += StringFormat::Fmt(", %llu", inst.args[n].idx);
|
||||
break;
|
||||
}
|
||||
case Instruction::Ret: m_Disassembly += "ret " + inst.type->toString(); break;
|
||||
}
|
||||
|
||||
if(inst.debugLoc != ~0U)
|
||||
{
|
||||
DebugLocation &debugLoc = m_DebugLocations[inst.debugLoc];
|
||||
|
||||
m_Disassembly += StringFormat::Fmt(", !dbg !%u", GetOrAssignMetaID(debugLoc));
|
||||
|
||||
if(!debugCall && debugLoc.line > 0)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt(" ; line:%llu col:%llu", debugLoc.line, debugLoc.col);
|
||||
}
|
||||
}
|
||||
|
||||
if(debugCall)
|
||||
{
|
||||
if(inst.funcCall->name == "llvm.dbg.value" || inst.funcCall->name == "llvm.dbg.declare")
|
||||
{
|
||||
RDCASSERT(inst.args[2].type == SymbolType::Metadata);
|
||||
RDCASSERT(inst.args[3].type == SymbolType::Metadata);
|
||||
m_Disassembly += StringFormat::Fmt(
|
||||
" ; var:%s ",
|
||||
escapeString(GetDebugVarName(GetFunctionMetadata(func, inst.args[2].idx)->dwarf)));
|
||||
m_Disassembly += GetFunctionMetadata(func, inst.args[3].idx)->valString();
|
||||
}
|
||||
}
|
||||
|
||||
if(inst.funcCall && inst.funcCall->name.beginsWith("dx.op."))
|
||||
{
|
||||
if(inst.args[0].type == SymbolType::Constant)
|
||||
{
|
||||
uint32_t opcode = GetFunctionValue(func, inst.args[0].idx)->val.uv[0];
|
||||
if(opcode < ARRAY_COUNT(funcSigs))
|
||||
{
|
||||
m_Disassembly += " ; ";
|
||||
m_Disassembly += funcSigs[opcode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Disassembly += "\n";
|
||||
instructionLine++;
|
||||
}
|
||||
m_Disassembly += "}\n\n";
|
||||
instructionLine += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Disassembly += "\n\n";
|
||||
instructionLine += 2;
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < m_Attributes.size(); i++)
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt("attributes #%zu = { %s }\n", i, m_Attributes[i].toString().c_str());
|
||||
|
||||
if(!m_Attributes.empty())
|
||||
m_Disassembly += "\n";
|
||||
|
||||
m_Disassembly += namedMeta + "\n";
|
||||
|
||||
size_t numIdx = 0;
|
||||
size_t dbgIdx = 0;
|
||||
|
||||
for(uint32_t i = 0; i < m_NextMetaID; i++)
|
||||
{
|
||||
if(numIdx < m_NumberedMeta.size() && m_NumberedMeta[numIdx]->id == i)
|
||||
{
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt("!%u = %s%s\n", i, m_NumberedMeta[numIdx]->distinct ? "distinct " : "",
|
||||
m_NumberedMeta[numIdx]->valString().c_str());
|
||||
numIdx++;
|
||||
}
|
||||
else if(dbgIdx < m_DebugLocations.size() && m_DebugLocations[dbgIdx].id == i)
|
||||
{
|
||||
m_Disassembly += StringFormat::Fmt("!%u = !DILocation(line: %llu, column: %llu, scope: %s", i,
|
||||
m_DebugLocations[dbgIdx].line, m_DebugLocations[dbgIdx].col,
|
||||
m_DebugLocations[dbgIdx].scope
|
||||
? m_DebugLocations[dbgIdx].scope->refString().c_str()
|
||||
: "null");
|
||||
if(m_DebugLocations[dbgIdx].inlinedAt)
|
||||
m_Disassembly +=
|
||||
StringFormat::Fmt(", inlinedAt: %s", m_DebugLocations[dbgIdx].inlinedAt->refString());
|
||||
m_Disassembly += ")\n";
|
||||
dbgIdx++;
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Couldn't find meta ID %u", i);
|
||||
}
|
||||
}
|
||||
|
||||
m_Disassembly += "\n";
|
||||
}
|
||||
|
||||
rdcstr Type::toString() const
|
||||
{
|
||||
if(!name.empty())
|
||||
{
|
||||
return "%" + escapeStringIfNeeded(name);
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case Void: return "void";
|
||||
case Scalar:
|
||||
{
|
||||
switch(scalarType)
|
||||
{
|
||||
case Void: return "void";
|
||||
case Int: return StringFormat::Fmt("i%u", bitWidth);
|
||||
case Float:
|
||||
switch(bitWidth)
|
||||
{
|
||||
case 16: return "half";
|
||||
case 32: return "float";
|
||||
case 64: return "double";
|
||||
default: return StringFormat::Fmt("fp%u", bitWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
case Vector: return StringFormat::Fmt("<%u x %s>", elemCount, inner->toString().c_str());
|
||||
case Pointer: return StringFormat::Fmt("%s*", inner->toString().c_str());
|
||||
case Array: return StringFormat::Fmt("[%u x %s]", elemCount, inner->toString().c_str());
|
||||
case Function: return declFunction(rdcstr());
|
||||
case Struct:
|
||||
{
|
||||
rdcstr ret;
|
||||
if(packedStruct)
|
||||
ret = "<{";
|
||||
else
|
||||
ret = "{";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
ret += members[i]->toString();
|
||||
}
|
||||
if(packedStruct)
|
||||
ret += "}>";
|
||||
else
|
||||
ret += "}";
|
||||
return ret;
|
||||
}
|
||||
|
||||
case Metadata: return "metadata";
|
||||
case Label: return "label";
|
||||
default: return "unknown_type";
|
||||
}
|
||||
}
|
||||
|
||||
rdcstr Type::declFunction(rdcstr funcName) const
|
||||
{
|
||||
rdcstr ret = inner->toString();
|
||||
ret += " " + funcName + "(";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
ret += members[i]->toString();
|
||||
}
|
||||
ret += ")";
|
||||
return ret;
|
||||
}
|
||||
|
||||
rdcstr Attributes::toString() const
|
||||
{
|
||||
rdcstr ret = "";
|
||||
Attribute p = params;
|
||||
|
||||
if(p & Attribute::Alignment)
|
||||
{
|
||||
ret += StringFormat::Fmt(" align=%llu", align);
|
||||
p &= ~Attribute::Alignment;
|
||||
}
|
||||
if(p & Attribute::StackAlignment)
|
||||
{
|
||||
ret += StringFormat::Fmt(" alignstack=%llu", stackAlign);
|
||||
p &= ~Attribute::StackAlignment;
|
||||
}
|
||||
if(p & Attribute::Dereferenceable)
|
||||
{
|
||||
ret += StringFormat::Fmt(" dereferenceable=%llu", derefBytes);
|
||||
p &= ~Attribute::Dereferenceable;
|
||||
}
|
||||
if(p & Attribute::DereferenceableOrNull)
|
||||
{
|
||||
ret += StringFormat::Fmt(" dereferenceable_or_null=%llu", derefOrNullBytes);
|
||||
p &= ~Attribute::DereferenceableOrNull;
|
||||
}
|
||||
|
||||
if(p != Attribute::None)
|
||||
{
|
||||
ret = ToStr(p) + " " + ret;
|
||||
int offs = ret.indexOf('|');
|
||||
while(offs >= 0)
|
||||
{
|
||||
ret.erase((size_t)offs, 2);
|
||||
offs = ret.indexOf('|');
|
||||
}
|
||||
}
|
||||
|
||||
for(const rdcpair<rdcstr, rdcstr> &str : strs)
|
||||
ret += " " + escapeString(str.first) + "=" + escapeString(str.second);
|
||||
|
||||
return ret.trimmed();
|
||||
}
|
||||
|
||||
rdcstr Metadata::refString() const
|
||||
{
|
||||
if(id == ~0U)
|
||||
return valString();
|
||||
return StringFormat::Fmt("!%u", id);
|
||||
}
|
||||
|
||||
rdcstr Metadata::valString() const
|
||||
{
|
||||
if(dwarf)
|
||||
{
|
||||
return dwarf->toString();
|
||||
}
|
||||
else if(value)
|
||||
{
|
||||
if(type == NULL)
|
||||
{
|
||||
return StringFormat::Fmt("!%s", escapeString(str).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
if(val)
|
||||
{
|
||||
if(type != val->type)
|
||||
RDCERR("Type mismatch in metadata");
|
||||
return val->toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(func && instruction < func->instructions.size())
|
||||
{
|
||||
const Instruction &inst = func->instructions[instruction];
|
||||
if(inst.name.empty())
|
||||
return StringFormat::Fmt("%s %%%u", inst.type->toString().c_str(), inst.resultID);
|
||||
else
|
||||
return StringFormat::Fmt("%s %%%s", inst.type->toString().c_str(),
|
||||
escapeStringIfNeeded(inst.name).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("No instruction symbol for value-less metadata");
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rdcstr ret = "!{";
|
||||
for(size_t i = 0; i < children.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
if(!children[i])
|
||||
ret += "null";
|
||||
else if(children[i]->value)
|
||||
ret += children[i]->valString();
|
||||
else
|
||||
ret += StringFormat::Fmt("!%u", children[i]->id);
|
||||
}
|
||||
ret += "}";
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
rdcstr Value::toString() const
|
||||
{
|
||||
if(type == NULL)
|
||||
return escapeString(str);
|
||||
|
||||
rdcstr ret;
|
||||
ret += type->toString() + " ";
|
||||
if(undef)
|
||||
{
|
||||
ret += "undef";
|
||||
}
|
||||
else if(symbol)
|
||||
{
|
||||
ret += StringFormat::Fmt("@%s", escapeStringIfNeeded(str).c_str());
|
||||
}
|
||||
else if(type->type == Type::Scalar)
|
||||
{
|
||||
if(type->scalarType == Type::Float)
|
||||
{
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lf", val.dv[0]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%f", val.fv[0]);
|
||||
}
|
||||
else if(type->scalarType == Type::Int)
|
||||
{
|
||||
// LLVM seems to always interpret these as signed? :(
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lld", val.u64v[0]);
|
||||
else if(type->bitWidth == 1)
|
||||
ret += val.uv[0] ? "true" : "false";
|
||||
else
|
||||
ret += StringFormat::Fmt("%d", val.uv[0]);
|
||||
}
|
||||
}
|
||||
else if(type->type == Type::Vector)
|
||||
{
|
||||
ret += "<";
|
||||
for(uint32_t i = 0; i < type->elemCount; i++)
|
||||
{
|
||||
if(type->scalarType == Type::Float)
|
||||
{
|
||||
// TODO need to know how to determine signedness here
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%lf", val.dv[i]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%f", val.fv[i]);
|
||||
}
|
||||
else if(type->scalarType == Type::Int)
|
||||
{
|
||||
// TODO need to know how to determine signedness here
|
||||
if(type->bitWidth > 32)
|
||||
ret += StringFormat::Fmt("%llu", val.u64v[i]);
|
||||
else
|
||||
ret += StringFormat::Fmt("%u", val.uv[i]);
|
||||
}
|
||||
}
|
||||
ret += ">";
|
||||
}
|
||||
else if(type->type == Type::Array)
|
||||
{
|
||||
ret += "[";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
|
||||
ret += members[i].toString();
|
||||
}
|
||||
ret += "]";
|
||||
}
|
||||
else if(type->type == Type::Struct)
|
||||
{
|
||||
ret += "{";
|
||||
for(size_t i = 0; i < members.size(); i++)
|
||||
{
|
||||
if(i > 0)
|
||||
ret += ", ";
|
||||
|
||||
ret += members[i].toString();
|
||||
}
|
||||
ret += "}";
|
||||
}
|
||||
else
|
||||
{
|
||||
ret += StringFormat::Fmt("unsupported type %u", type->type);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}; // namespace DXIL
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const DXIL::Attribute &el)
|
||||
{
|
||||
BEGIN_BITFIELD_STRINGISE(DXIL::Attribute);
|
||||
{
|
||||
STRINGISE_BITFIELD_CLASS_VALUE_NAMED(None, "");
|
||||
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Alignment, "align");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(AlwaysInline, "alwaysinline");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ByVal, "byval");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InlineHint, "inlinehint");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InReg, "inreg");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(MinSize, "minsize");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Naked, "naked");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Nest, "nest");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoAlias, "noalias");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoBuiltin, "nobuiltin");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoCapture, "nocapture");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoDuplicate, "noduplicate");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoImplicitFloat, "noimplicitfloat");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoInline, "noinline");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NonLazyBind, "nonlazybind");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoRedZone, "noredzone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoReturn, "noreturn");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NoUnwind, "nounwind");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(OptimizeForSize, "optsize");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReadNone, "readnone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReadOnly, "readonly");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Returned, "returned");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ReturnsTwice, "returns_twice");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SExt, "signext");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackAlignment, "alignstack");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtect, "ssp");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtectReq, "sspreq");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StackProtectStrong, "sspstrong");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(StructRet, "sret");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeAddress, "sanitize_address");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeThread, "sanitize_thread");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SanitizeMemory, "sanitize_memory");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(UWTable, "uwtable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ZExt, "zeroext");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Builtin, "builtin");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Cold, "cold");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(OptimizeNone, "optnone");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(InAlloca, "inalloca");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(NonNull, "nonnull");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(JumpTable, "jumptable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Dereferenceable, "dereferenceable");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(DereferenceableOrNull, "dereferenceable_or_null");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Convergent, "convergent");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(SafeStack, "safestack");
|
||||
STRINGISE_BITFIELD_CLASS_BIT_NAMED(ArgMemOnly, "argmemonly");
|
||||
}
|
||||
END_BITFIELD_STRINGISE();
|
||||
}
|
||||
@@ -103,6 +103,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dxil_bytecode.cpp" />
|
||||
<ClCompile Include="dxil_debuginfo.cpp" />
|
||||
<ClCompile Include="dxil_disassemble.cpp" />
|
||||
<ClCompile Include="llvm_decoder.cpp" />
|
||||
<ClCompile Include="precompiled.cpp">
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<ClCompile Include="llvm_decoder.cpp" />
|
||||
<ClCompile Include="dxil_bytecode.cpp" />
|
||||
<ClCompile Include="dxil_debuginfo.cpp" />
|
||||
<ClCompile Include="dxil_disassemble.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="precompiled.h">
|
||||
|
||||
Reference in New Issue
Block a user