void Synthesizer::encodeSecondOperand(const Operand &secondOperand) { if(secondType != Operand::OPERAND_UNKNOWN) { throw INTERNAL_ERROR; // Instruction source already set } secondType = secondOperand.type; if(Operand::isReg(secondType)) { secondReg = secondOperand.reg; } else if(Operand::isMem(secondType)) { encodeBase(secondOperand); encodeIndex(secondOperand); setScale(secondOperand.scale); setDisplacement(secondOperand.displacement); referenceLabel(secondOperand.reference); } else if(Operand::isImm(secondType)) { encodeImmediate(secondOperand.value); referenceLabel(secondOperand.reference); } else if(!Operand::isVoid(secondType)) { throw INTERNAL_ERROR; } }
void Synthesizer::encodeFirstOperand(const Operand &firstOperand) { if(firstType != Operand::OPERAND_UNKNOWN) { throw INTERNAL_ERROR; // Instruction destination already set } firstType = firstOperand.type; if(Operand::isReg(firstType)) { firstReg = firstOperand.reg; } else if(Operand::isMem(firstType)) { encodeBase(firstOperand); encodeIndex(firstOperand); setScale(firstOperand.scale); setDisplacement(firstOperand.displacement); referenceLabel(firstOperand.reference); } else if(Operand::isImm(firstType)) { encodeImmediate(firstOperand.value); referenceLabel(firstOperand.reference); } else if(!Operand::isVoid(firstType)) { throw INTERNAL_ERROR; } }
void Synthesizer::encodeThirdOperand(const Operand &thirdOperand) { if(Operand::isImm(thirdOperand)) { encodeImmediate(thirdOperand.value); referenceLabel(thirdOperand.reference); } else if(!Operand::isVoid(thirdOperand)) { throw INTERNAL_ERROR; } }
/// @brief Translate an Opcode operand to binary form /// /// @param[in] grammar the grammar to use for compilation /// @param[in, out] context the dynamic compilation info /// @param[in] type of the operand /// @param[in] textValue word of text to be parsed /// @param[out] pInst return binary Opcode /// @param[in,out] pExpectedOperands the operand types expected /// /// @return result code spv_result_t spvTextEncodeOperand(const libspirv::AssemblyGrammar& grammar, libspirv::AssemblyContext* context, const spv_operand_type_t type, const char* textValue, spv_instruction_t* pInst, spv_operand_pattern_t* pExpectedOperands) { // NOTE: Handle immediate int in the stream if ('!' == textValue[0]) { if (auto error = encodeImmediate(context, textValue, pInst)) { return error; } *pExpectedOperands = spvAlternatePatternFollowingImmediate(*pExpectedOperands); return SPV_SUCCESS; } // Optional literal operands can fail to parse. In that case use // SPV_FAILED_MATCH to avoid emitting a diagostic. Use the following // for those situations. spv_result_t error_code_for_literals = spvOperandIsOptional(type) ? SPV_FAILED_MATCH : SPV_ERROR_INVALID_TEXT; switch (type) { case SPV_OPERAND_TYPE_ID: case SPV_OPERAND_TYPE_TYPE_ID: case SPV_OPERAND_TYPE_RESULT_ID: case SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID: case SPV_OPERAND_TYPE_SCOPE_ID: case SPV_OPERAND_TYPE_OPTIONAL_ID: { if ('%' == textValue[0]) { textValue++; } else { return context->diagnostic() << "Expected id to start with %."; } if (!spvIsValidID(textValue)) { return context->diagnostic() << "Invalid ID " << textValue; } const uint32_t id = context->spvNamedIdAssignOrGet(textValue); if (type == SPV_OPERAND_TYPE_TYPE_ID) pInst->resultTypeId = id; spvInstructionAddWord(pInst, id); // Set the extended instruction type. // The import set id is the 3rd operand of OpExtInst. if (pInst->opcode == SpvOpExtInst && pInst->words.size() == 4) { auto ext_inst_type = context->getExtInstTypeForId(pInst->words[3]); if (ext_inst_type == SPV_EXT_INST_TYPE_NONE) { return context->diagnostic() << "Invalid extended instruction import Id " << pInst->words[2]; } pInst->extInstType = ext_inst_type; } } break; case SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER: { // The assembler accepts the symbolic name for an extended instruction, // and emits its corresponding number. spv_ext_inst_desc extInst; if (grammar.lookupExtInst(pInst->extInstType, textValue, &extInst)) { return context->diagnostic() << "Invalid extended instruction name '" << textValue << "'."; } spvInstructionAddWord(pInst, extInst->ext_inst); // Prepare to parse the operands for the extended instructions. spvPushOperandTypes(extInst->operandTypes, pExpectedOperands); } break; case SPV_OPERAND_TYPE_SPEC_CONSTANT_OP_NUMBER: { // The assembler accepts the symbolic name for the opcode, but without // the "Op" prefix. For example, "IAdd" is accepted. The number // of the opcode is emitted. SpvOp opcode; if (grammar.lookupSpecConstantOpcode(textValue, &opcode)) { return context->diagnostic() << "Invalid " << spvOperandTypeStr(type) << " '" << textValue << "'."; } spv_opcode_desc opcodeEntry = nullptr; if (grammar.lookupOpcode(opcode, &opcodeEntry)) { return context->diagnostic(SPV_ERROR_INTERNAL) << "OpSpecConstant opcode table out of sync"; } spvInstructionAddWord(pInst, uint32_t(opcodeEntry->opcode)); // Prepare to parse the operands for the opcode. Except skip the // type Id and result Id, since they've already been processed. assert(opcodeEntry->hasType); assert(opcodeEntry->hasResult); assert(opcodeEntry->numTypes >= 2); spvPushOperandTypes(opcodeEntry->operandTypes + 2, pExpectedOperands); } break; case SPV_OPERAND_TYPE_LITERAL_INTEGER: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_INTEGER: { // The current operand is an *unsigned* 32-bit integer. // That's just how the grammar works. libspirv::IdType expected_type = { 32, false, libspirv::IdTypeClass::kScalarIntegerType}; if (auto error = context->binaryEncodeNumericLiteral( textValue, error_code_for_literals, expected_type, pInst)) { return error; } } break; case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER: // This is a context-independent literal number which can be a 32-bit // number of floating point value. if (auto error = context->binaryEncodeNumericLiteral( textValue, error_code_for_literals, libspirv::kUnknownType, pInst)) { return error; } break; case SPV_OPERAND_TYPE_OPTIONAL_TYPED_LITERAL_INTEGER: case SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER: { libspirv::IdType expected_type = libspirv::kUnknownType; // The encoding for OpConstant, OpSpecConstant and OpSwitch all // depend on either their own result-id or the result-id of // one of their parameters. if (SpvOpConstant == pInst->opcode || SpvOpSpecConstant == pInst->opcode) { // The type of the literal is determined by the type Id of the // instruction. expected_type = context->getTypeOfTypeGeneratingValue(pInst->resultTypeId); if (!libspirv::isScalarFloating(expected_type) && !libspirv::isScalarIntegral(expected_type)) { spv_opcode_desc d; const char* opcode_name = "opcode"; if (SPV_SUCCESS == grammar.lookupOpcode(pInst->opcode, &d)) { opcode_name = d->name; } return context->diagnostic() << "Type for " << opcode_name << " must be a scalar floating point or integer type"; } } else if (pInst->opcode == SpvOpSwitch) { // The type of the literal is the same as the type of the selector. expected_type = context->getTypeOfValueInstruction(pInst->words[1]); if (!libspirv::isScalarIntegral(expected_type)) { return context->diagnostic() << "The selector operand for OpSwitch must be the result" " of an instruction that generates an integer scalar"; } } if (auto error = context->binaryEncodeNumericLiteral( textValue, error_code_for_literals, expected_type, pInst)) { return error; } } break; case SPV_OPERAND_TYPE_LITERAL_STRING: case SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING: { spv_literal_t literal = {}; spv_result_t error = spvTextToLiteral(textValue, &literal); if (error != SPV_SUCCESS) { if (error == SPV_ERROR_OUT_OF_MEMORY) return error; return context->diagnostic(error_code_for_literals) << "Invalid literal string '" << textValue << "'."; } if (literal.type != SPV_LITERAL_TYPE_STRING) { return context->diagnostic() << "Expected literal string, found literal number '" << textValue << "'."; } // NOTE: Special case for extended instruction library import if (SpvOpExtInstImport == pInst->opcode) { const spv_ext_inst_type_t ext_inst_type = spvExtInstImportTypeGet(literal.str.c_str()); if (SPV_EXT_INST_TYPE_NONE == ext_inst_type) { return context->diagnostic() << "Invalid extended instruction import '" << literal.str << "'"; } if ((error = context->recordIdAsExtInstImport(pInst->words[1], ext_inst_type))) return error; } if (context->binaryEncodeString(literal.str.c_str(), pInst)) return SPV_ERROR_INVALID_TEXT; } break; case SPV_OPERAND_TYPE_FP_FAST_MATH_MODE: case SPV_OPERAND_TYPE_FUNCTION_CONTROL: case SPV_OPERAND_TYPE_LOOP_CONTROL: case SPV_OPERAND_TYPE_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_IMAGE: case SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS: case SPV_OPERAND_TYPE_SELECTION_CONTROL: { uint32_t value; if (grammar.parseMaskOperand(type, textValue, &value)) { return context->diagnostic() << "Invalid " << spvOperandTypeStr(type) << " operand '" << textValue << "'."; } if (auto error = context->binaryEncodeU32(value, pInst)) return error; // Prepare to parse the operands for this logical operand. grammar.pushOperandTypesForMask(type, value, pExpectedOperands); } break; case SPV_OPERAND_TYPE_OPTIONAL_CIV: { auto error = spvTextEncodeOperand( grammar, context, SPV_OPERAND_TYPE_OPTIONAL_LITERAL_NUMBER, textValue, pInst, pExpectedOperands); if (error == SPV_FAILED_MATCH) { // It's not a literal number -- is it a literal string? error = spvTextEncodeOperand(grammar, context, SPV_OPERAND_TYPE_OPTIONAL_LITERAL_STRING, textValue, pInst, pExpectedOperands); } if (error == SPV_FAILED_MATCH) { // It's not a literal -- is it an ID? error = spvTextEncodeOperand(grammar, context, SPV_OPERAND_TYPE_OPTIONAL_ID, textValue, pInst, pExpectedOperands); } if (error) { return context->diagnostic(error) << "Invalid word following !<integer>: " << textValue; } if (pExpectedOperands->empty()) { pExpectedOperands->push_back(SPV_OPERAND_TYPE_OPTIONAL_CIV); } } break; default: { // NOTE: All non literal operands are handled here using the operand // table. spv_operand_desc entry; if (grammar.lookupOperand(type, textValue, strlen(textValue), &entry)) { return context->diagnostic() << "Invalid " << spvOperandTypeStr(type) << " '" << textValue << "'."; } if (context->binaryEncodeU32(entry->value, pInst)) { return context->diagnostic() << "Invalid " << spvOperandTypeStr(type) << " '" << textValue << "'."; } // Prepare to parse the operands for this logical operand. spvPushOperandTypes(entry->operandTypes, pExpectedOperands); } break; } return SPV_SUCCESS; }
ge_id_t GeneticEventManager::encode_event( const GeneticEvent * ge ) { ge_id_t id; if( ge->getType() == SUBSTITUTION ) { switch( ge->length() ) { case 0: assert( false ); break; case 1: id = encodeImmediate( ge, efSUBSTITUTION1 ); delete ge; break; case 2: id = encodeImmediate( ge, efSUBSTITUTION2 ); delete ge; break; case 3: id = encodeImmediate( ge, efSUBSTITUTION3 ); delete ge; break; case 4: id = encodeImmediate( ge, efSUBSTITUTION4 ); delete ge; break; default: index_t idx = m_events->size(); m_events->push_back( ge ); id = encodeIndex( idx ); break; } } else if( ge->getType() == DELETION ) { id = encodeDeletion( ge->getStart(), ge->getEnd() ); delete ge; } else if( ge->getType() == INSERTION ) { switch( ge->length() ) { case 0: assert( false ); break; case 1: id = encodeImmediate( ge, efINSERT1 ); delete ge; break; case 2: id = encodeImmediate( ge, efINSERT2 ); delete ge; break; case 3: id = encodeImmediate( ge, efINSERT3 ); delete ge; break; case 4: id = encodeImmediate( ge, efINSERT4 ); delete ge; break; default: index_t idx = m_events->size(); m_events->push_back( ge ); id = encodeIndex( idx ); break; } } else { index_t idx = m_events->size(); m_events->push_back( ge ); id = encodeIndex( idx ); } return id; }