From 551fbdd294c6ab620b4e8d939431f50ae57b3a77 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 28 Jul 2015 23:43:25 +0200 Subject: [PATCH] Most SPIR-V structs now fleshed out --- .../shaders/spirv/spirv_disassemble.cpp | 300 ++++++++++++++++-- 1 file changed, 274 insertions(+), 26 deletions(-) diff --git a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp index d95e63603..4ee133bf0 100644 --- a/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_disassemble.cpp @@ -52,39 +52,38 @@ static string OptionalFlagString(EnumType e) return (int)e ? "[" + ToStr::Get(e) + "]" : ""; } +struct SPVDecoration +{ + SPVDecoration() : decoration(spv::DecorationPrecisionLow), val(0) {} + + spv::Decoration decoration; + + uint32_t val; +}; + struct SPVExtInstSet { + SPVExtInstSet() : instructions(NULL) {} + string setname; const char **instructions; }; struct SPVEntryPoint { + SPVEntryPoint() : func(0), model(spv::ExecutionModelVertex) {} + // entry point will come before declaring instruction, // so we reference the function by ID uint32_t func; spv::ExecutionModel model; }; -struct SPVOperation -{ - // this is modified on the fly, it's used as a measure of whether we - // can combine multiple statements into one line when displaying the - // disassembly. - int complexity; - - // arguments always reference IDs that already exist (branch/flow - // control type statements aren't SPVOperations) - vector arguments; -}; - -struct SPVFlowControl -{ -}; - struct SPVTypeData { - SPVTypeData() : bitCount(32), vectorSize(1), matrixSize(1), arraySize(1) {} + SPVTypeData() : + baseType(NULL), storage(spv::StorageClassUniformConstant), + bitCount(32), vectorSize(1), matrixSize(1), arraySize(1) {} enum { @@ -111,6 +110,10 @@ struct SPVTypeData SPVTypeData *baseType; + string name; + + vector decorations; + // struct/function vector< pair > children; @@ -125,29 +128,84 @@ struct SPVTypeData uint32_t arraySize; }; -struct SPVFunction {}; -struct SPVBlock {}; +struct SPVInstruction; + +struct SPVOperation +{ + SPVOperation() : type(NULL), complexity(0) {} + + SPVTypeData *type; + + // this is modified on the fly, it's used as a measure of whether we + // can combine multiple statements into one line when displaying the + // disassembly. + int complexity; + + // arguments always reference IDs that already exist (branch/flow + // control type statements aren't SPVOperations) + vector arguments; +}; struct SPVConstant { + SPVConstant() : type(NULL), u64(0) {} + SPVTypeData *type; - uint32_t value[16]; + union + { + uint64_t u64; + uint32_t u32; + uint16_t u16; + int64_t i64; + int32_t i32; + int16_t i16; + float f; + double d; + }; + + vector children; }; struct SPVVariable { + SPVVariable() : type(NULL), storage(spv::StorageClassUniformConstant), initialiser(NULL) {} + SPVTypeData *type; + spv::StorageClass storage; + SPVConstant *initialiser; +}; + +struct SPVFlowControl +{ +}; + +struct SPVBlock +{ + SPVBlock() : mergeFlow(NULL), exitFlow(NULL) {} + + vector operations; + + SPVFlowControl *mergeFlow; + SPVFlowControl *exitFlow; +}; + +struct SPVFunction +{ + SPVFunction() : retType(NULL), funcType(NULL), control(spv::FunctionControlMaskNone) {} + + SPVTypeData *retType; + SPVTypeData *funcType; + spv::FunctionControlMask control; + vector blocks; + vector variables; }; struct SPVInstruction { - spv::Op opcode; - - // line number in disassembly (used for stepping when debugging) - int line; - SPVInstruction() { + opcode = spv::OpNop; + ext = NULL; entry = NULL; op = NULL; @@ -159,6 +217,8 @@ struct SPVInstruction var = NULL; line = -1; + + source.col = source.line = 0; } ~SPVInstruction() @@ -183,9 +243,18 @@ struct SPVInstruction { return opcode != spv::OpLabel; } + + spv::Op opcode; + + // line number in disassembly (used for stepping when debugging) + int line; + + struct { string filename; uint32_t line; uint32_t col; } source; string str; + vector decorations; + // zero or one of these pointers might be set SPVExtInstSet *ext; // this ID is an extended instruction set SPVEntryPoint *entry; // this ID is an entry point @@ -200,6 +269,15 @@ struct SPVInstruction struct SPVModule { + SPVModule() + { + shadType = eSPIRVInvalid; + moduleVersion = 0; + generator = 0; + source.lang = spv::SourceLanguageUnknown; source.ver = 0; + model.addr = spv::AddressingModelLogical; model.mem = spv::MemoryModelSimple; + } + ~SPVModule() { for(size_t i=0; i < operations.size(); i++) @@ -306,6 +384,9 @@ void DisassembleSPIRV(SPIRVShaderStage shadType, const vector &spirv, RDCASSERT(spirv[4] == 0); + SPVFunction *curFunc = NULL; + SPVBlock *curBlock = NULL; + size_t it = 5; while(it < spirv.size()) { @@ -357,6 +438,12 @@ void DisassembleSPIRV(SPIRVShaderStage shadType, const vector &spirv, module.ids[spirv[it+1]] = &op; break; } + case spv::OpString: + { + op.str = (const char *)&spirv[it+2]; + module.ids[spirv[it+1]] = &op; + break; + } ////////////////////////////////////////////////////////////////////// // Type opcodes case spv::OpTypeVoid: @@ -475,6 +562,137 @@ void DisassembleSPIRV(SPIRVShaderStage shadType, const vector &spirv, module.ids[spirv[it+1]] = &op; break; } + ////////////////////////////////////////////////////////////////////// + // Constants + case spv::OpConstant: + { + SPVInstruction *typeInst = module.ids[spirv[it+1]]; + RDCASSERT(typeInst && typeInst->type); + + op.constant = new SPVConstant(); + op.constant->type = typeInst->type; + + op.constant->u32 = spirv[it+3]; + + if(WordCount > 3) + { + // only handle 32-bit or 64-bit constants + RDCASSERT(WordCount <= 4); + + uint64_t lo = spirv[it+3]; + uint64_t hi = spirv[it+4]; + + op.constant->u64 = lo | (hi<<32); + } + + module.ids[spirv[it+2]] = &op; + break; + } + case spv::OpConstantComposite: + { + SPVInstruction *typeInst = module.ids[spirv[it+1]]; + RDCASSERT(typeInst && typeInst->type); + + op.constant = new SPVConstant(); + op.constant->type = typeInst->type; + + for(int i=3; i < WordCount; i++) + { + SPVInstruction *constInst = module.ids[spirv[it+i]]; + RDCASSERT(constInst && constInst->constant); + + op.constant->children.push_back(constInst->constant); + } + + module.ids[spirv[it+2]] = &op; + + break; + } + ////////////////////////////////////////////////////////////////////// + // Functions + case spv::OpFunction: + { + SPVInstruction *retTypeInst = module.ids[spirv[it+1]]; + RDCASSERT(retTypeInst && retTypeInst->type); + + SPVInstruction *typeInst = module.ids[spirv[it+4]]; + RDCASSERT(typeInst && typeInst->type); + + op.func = new SPVFunction(); + op.func->retType = retTypeInst->type; + op.func->funcType = typeInst->type; + op.func->control = spv::FunctionControlMask(spirv[it+3]); + + module.ids[spirv[it+2]] = &op; + + curFunc = op.func; + + break; + } + case spv::OpFunctionEnd: + { + curFunc = NULL; + break; + } + ////////////////////////////////////////////////////////////////////// + // Variables + case spv::OpVariable: + { + SPVInstruction *typeInst = module.ids[spirv[it+1]]; + RDCASSERT(typeInst && typeInst->type); + + op.var = new SPVVariable(); + op.var->type = typeInst->type; + op.var->storage = spv::StorageClass(spirv[it+3]); + + if(WordCount > 4) + { + SPVInstruction *initInst = module.ids[spirv[it+4]]; + RDCASSERT(initInst && initInst->constant); + op.var->initialiser = initInst->constant; + } + + if(curFunc) curFunc->variables.push_back(op.var); + else module.globals.push_back(&op); + + module.ids[spirv[it+2]] = &op; + break; + } + ////////////////////////////////////////////////////////////////////// + // Operations with special parameters + case spv::OpAccessChain: + case spv::OpLoad: + case spv::OpStore: + case spv::OpCopyMemory: + break; + ////////////////////////////////////////////////////////////////////// + // Easy to handle opcodes with just some number of ID parameters + case spv::OpIAdd: + case spv::OpIMul: + case spv::OpFAdd: + case spv::OpFMul: + case spv::OpSLessThan: + case spv::OpExtInst: + { + SPVInstruction *typeInst = module.ids[spirv[it+1]]; + RDCASSERT(typeInst && typeInst->type); + + op.op = new SPVOperation(); + op.op->type = typeInst->type; + + for(int i=3; i < WordCount; i++) + { + SPVInstruction *argInst = module.ids[spirv[it+i]]; + RDCASSERT(argInst); + + op.op->arguments.push_back(argInst); + } + + module.ids[spirv[it+2]] = &op; + + curBlock->operations.push_back(op.op); + break; + } default: break; } @@ -504,17 +722,47 @@ void DisassembleSPIRV(SPIRVShaderStage shadType, const vector &spirv, case spv::OpMemberName: { SPVInstruction *varInst = module.ids[spirv[it+1]]; - RDCASSERT(varInst && varInst->type && varInst->type->type == eStruct); + RDCASSERT(varInst && varInst->type && varInst->type->type == SPVTypeData::eStruct); uint32_t memIdx = spirv[it+2]; RDCASSERT(memIdx < varInst->type->children.size()); varInst->type->children[memIdx].second = (const char *)&spirv[it+3]; break; } + case spv::OpLine: + { + SPVInstruction *varInst = module.ids[spirv[it+1]]; + RDCASSERT(varInst); + + SPVInstruction *fileInst = module.ids[spirv[it+2]]; + RDCASSERT(fileInst); + + varInst->source.filename = fileInst->str; + varInst->source.line = spirv[it+3]; + varInst->source.col = spirv[it+4]; + break; + } case spv::OpDecorate: + { + SPVInstruction *inst = module.ids[spirv[it+1]]; + RDCASSERT(inst); + + SPVDecoration d; + d.decoration = spv::Decoration(spirv[it+2]); + + // TODO this isn't enough for all decorations + RDCASSERT(WordCount <= 3); + if(WordCount > 2) + d.val = spirv[it+3]; + + inst->decorations.push_back(d); + break; + } case spv::OpMemberDecorate: case spv::OpGroupDecorate: case spv::OpGroupMemberDecorate: case spv::OpDecorationGroup: + // TODO + RDCBREAK(); break; }