// Loop over all the instructions, in order, processing each. // Boiler plate for each is handled here directly, the rest is dispatched. void SpirvStream::processInstructions() { // Instructions while (word < size) { int instructionStart = word; // Instruction wordCount and opcode unsigned int firstWord = stream[word]; unsigned wordCount = firstWord >> WordCountShift; Op opCode = (Op)(firstWord & OpCodeMask); int nextInst = word + wordCount; ++word; // Presence of full instruction if (nextInst > size) Kill(out, "stream instruction terminated too early"); // Base for computing number of operands; will be updated as more is learned unsigned numOperands = wordCount - 1; // Type <id> Id typeId = 0; if (InstructionDesc[opCode].hasType()) { typeId = stream[word++]; --numOperands; } // Result <id> Id resultId = 0; if (InstructionDesc[opCode].hasResult()) { resultId = stream[word++]; --numOperands; // save instruction for future reference idInstruction[resultId] = instructionStart; } outputResultId(resultId); outputTypeId(typeId); outputIndent(); // Hand off the Op and all its operands disassembleInstruction(resultId, typeId, opCode, numOperands); if (word != nextInst) { out << " ERROR, incorrect number of operands consumed. At " << word << " instead of " << nextInst << " instruction start was " << instructionStart; word = nextInst; } out << std::endl; } }
void outputField ( FudgeField * field, unsigned int indent ) { /* Output the field's type, name (if present) and ordinal (if present) */ outputIndent ( indent ); outputType ( field->type ); printf ( " " ); if ( field->flags & FUDGE_FIELD_HAS_NAME ) { outputString ( field->name ); if ( field->flags & FUDGE_FIELD_HAS_ORDINAL ) printf ( "/" ); } if ( field->flags & FUDGE_FIELD_HAS_ORDINAL ) printf ( "ord(%d)", field->ordinal ); printf ( ": " ); /* Output the field contents */ switch ( field->type ) { case FUDGE_TYPE_INDICATOR: break; case FUDGE_TYPE_BOOLEAN: printf ( field->data.boolean ? "true" : "false" ); break; case FUDGE_TYPE_BYTE: printf ( "%d", field->data.byte ); break; case FUDGE_TYPE_SHORT: printf ( "%d", field->data.i16 ); break; case FUDGE_TYPE_INT: printf ( "%d", field->data.i32 ); break; case FUDGE_TYPE_LONG: printf ( "%ld", ( long int ) field->data.i64 ); break; case FUDGE_TYPE_FLOAT: printf ( "%f", field->data.f32 ); break; case FUDGE_TYPE_DOUBLE: printf ( "%f", field->data.f64 ); break; case FUDGE_TYPE_SHORT_ARRAY: outputArray ( field->data.bytes, field->numbytes, "%d", 2, 8 ); break; case FUDGE_TYPE_INT_ARRAY: outputArray ( field->data.bytes, field->numbytes, "%d", 4, 8 ); break; case FUDGE_TYPE_LONG_ARRAY: outputArray ( field->data.bytes, field->numbytes, "%lu", 8, 4 ); break; case FUDGE_TYPE_FLOAT_ARRAY: outputArray ( field->data.bytes, field->numbytes, "%f", 4, 4 ); break; case FUDGE_TYPE_DOUBLE_ARRAY: outputArray ( field->data.bytes, field->numbytes, "%f", 8, 4 ); break; case FUDGE_TYPE_STRING: outputString ( field->data.string ); break; case FUDGE_TYPE_BYTE_ARRAY: case FUDGE_TYPE_BYTE_ARRAY_4: case FUDGE_TYPE_BYTE_ARRAY_8: case FUDGE_TYPE_BYTE_ARRAY_16: case FUDGE_TYPE_BYTE_ARRAY_20: case FUDGE_TYPE_BYTE_ARRAY_32: case FUDGE_TYPE_BYTE_ARRAY_64: case FUDGE_TYPE_BYTE_ARRAY_128: case FUDGE_TYPE_BYTE_ARRAY_256: case FUDGE_TYPE_BYTE_ARRAY_512: outputArray ( field->data.bytes, field->numbytes, "%d", 1, 10 ); break; case FUDGE_TYPE_FUDGE_MSG: printf ( "\n" ); outputIndent ( indent ); printf ( "{\n" ); outputMessage ( field->data.message, indent + 1 ); outputIndent ( indent ); printf ( "}" ); break; default: printf ( "%d bytes ", field->numbytes ); outputArray ( field->data.bytes, field->numbytes, "%d", 1, 8 ); break; } printf ( "\n" ); }
void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands) { // Process the opcode out << (OpcodeString(opCode) + 2); // leave out the "Op" if (opCode == OpLoopMerge || opCode == OpSelectionMerge) nextNestedControl = stream[word]; else if (opCode == OpBranchConditional || opCode == OpSwitch) { if (nextNestedControl) { nestedControl.push(nextNestedControl); nextNestedControl = 0; } } else if (opCode == OpExtInstImport) { idDescriptor[resultId] = (const char*)(&stream[word]); } else { if (resultId != 0 && idDescriptor[resultId].size() == 0) { switch (opCode) { case OpTypeInt: idDescriptor[resultId] = "int"; break; case OpTypeFloat: idDescriptor[resultId] = "float"; break; case OpTypeBool: idDescriptor[resultId] = "bool"; break; case OpTypeStruct: idDescriptor[resultId] = "struct"; break; case OpTypePointer: idDescriptor[resultId] = "ptr"; break; case OpTypeVector: if (idDescriptor[stream[word]].size() > 0) idDescriptor[resultId].append(idDescriptor[stream[word]].begin(), idDescriptor[stream[word]].begin() + 1); idDescriptor[resultId].append("vec"); switch (stream[word + 1]) { case 2: idDescriptor[resultId].append("2"); break; case 3: idDescriptor[resultId].append("3"); break; case 4: idDescriptor[resultId].append("4"); break; case 8: idDescriptor[resultId].append("8"); break; case 16: idDescriptor[resultId].append("16"); break; case 32: idDescriptor[resultId].append("32"); break; default: break; } break; default: break; } } } // Process the operands. Note, a new context-dependent set could be // swapped in mid-traversal. // Handle images specially, so can put out helpful strings. if (opCode == OpTypeImage) { out << " "; disassembleIds(1); out << " " << DimensionString((Dim)stream[word++]); out << (stream[word++] != 0 ? " depth" : ""); out << (stream[word++] != 0 ? " array" : ""); out << (stream[word++] != 0 ? " multi-sampled" : ""); switch (stream[word++]) { case 0: out << " runtime"; break; case 1: out << " sampled"; break; case 2: out << " nonsampled"; break; } out << " format:" << ImageFormatString((ImageFormat)stream[word++]); if (numOperands == 8) { out << " " << AccessQualifierString(stream[word++]); } return; } // Handle all the parameterized operands for (int op = 0; op < InstructionDesc[opCode].operands.getNum() && numOperands > 0; ++op) { out << " "; OperandClass operandClass = InstructionDesc[opCode].operands.getClass(op); switch (operandClass) { case OperandId: case OperandScope: case OperandMemorySemantics: disassembleIds(1); --numOperands; // Get names for printing "(XXX)" for readability, *after* this id if (opCode == OpName) idDescriptor[stream[word - 1]] = (const char*)(&stream[word]); break; case OperandVariableIds: disassembleIds(numOperands); return; case OperandImageOperands: outputMask(OperandImageOperands, stream[word++]); --numOperands; disassembleIds(numOperands); return; case OperandOptionalLiteral: case OperandVariableLiterals: if ((opCode == OpDecorate && stream[word - 1] == DecorationBuiltIn) || (opCode == OpMemberDecorate && stream[word - 1] == DecorationBuiltIn)) { out << BuiltInString(stream[word++]); --numOperands; ++op; } disassembleImmediates(numOperands); return; case OperandVariableIdLiteral: while (numOperands > 0) { out << std::endl; outputResultId(0); outputTypeId(0); outputIndent(); out << " Type "; disassembleIds(1); out << ", member "; disassembleImmediates(1); numOperands -= 2; } return; case OperandVariableLiteralId: while (numOperands > 0) { out << std::endl; outputResultId(0); outputTypeId(0); outputIndent(); out << " case "; disassembleImmediates(1); out << ": "; disassembleIds(1); numOperands -= 2; } return; case OperandLiteralNumber: disassembleImmediates(1); --numOperands; if (opCode == OpExtInst) { ExtInstSet extInstSet = GLSL450Inst; const char* name = idDescriptor[stream[word - 2]].c_str(); if (0 == memcmp("OpenCL", name, 6)) { extInstSet = OpenCLExtInst; #ifdef AMD_EXTENSIONS } else if (strcmp(spv::E_SPV_AMD_shader_ballot, name) == 0 || strcmp(spv::E_SPV_AMD_shader_trinary_minmax, name) == 0 || strcmp(spv::E_SPV_AMD_shader_explicit_vertex_parameter, name) == 0 || strcmp(spv::E_SPV_AMD_gcn_shader, name) == 0) { extInstSet = GLSLextAMDInst; #endif #ifdef NV_EXTENSIONS }else if (strcmp(spv::E_SPV_NV_sample_mask_override_coverage, name) == 0 || strcmp(spv::E_SPV_NV_geometry_shader_passthrough, name) == 0 || strcmp(spv::E_SPV_NV_viewport_array2, name) == 0 || strcmp(spv::E_SPV_NVX_multiview_per_view_attributes, name) == 0) { extInstSet = GLSLextNVInst; #endif } unsigned entrypoint = stream[word - 1]; if (extInstSet == GLSL450Inst) { if (entrypoint < GLSLstd450Count) { out << "(" << GlslStd450DebugNames[entrypoint] << ")"; } #ifdef AMD_EXTENSIONS } else if (extInstSet == GLSLextAMDInst) { out << "(" << GLSLextAMDGetDebugNames(name, entrypoint) << ")"; #endif #ifdef NV_EXTENSIONS } else if (extInstSet == GLSLextNVInst) { out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")"; #endif } } break; case OperandOptionalLiteralString: case OperandLiteralString: numOperands -= disassembleString(); break; default: assert(operandClass >= OperandSource && operandClass < OperandOpcode); if (OperandClassParams[operandClass].bitmask) outputMask(operandClass, stream[word++]); else out << OperandClassParams[operandClass].getName(stream[word++]); --numOperands; break; } } return; }