| 47 | } |
| 48 | |
| 49 | uint32_t FindOrCreateFunctionVariable(opt::IRContext* context, |
| 50 | opt::Function* function, |
| 51 | uint32_t pointer_type_id) { |
| 52 | // The pointer type of a function variable must have Function storage class. |
| 53 | assert(context->get_type_mgr() |
| 54 | ->GetType(pointer_type_id) |
| 55 | ->AsPointer() |
| 56 | ->storage_class() == spv::StorageClass::Function); |
| 57 | |
| 58 | // Go through the instructions in the function's first block until we find a |
| 59 | // suitable variable, or go past all the variables. |
| 60 | opt::BasicBlock::iterator iter = function->begin()->begin(); |
| 61 | for (;; ++iter) { |
| 62 | // We will either find a suitable variable, or find a non-variable |
| 63 | // instruction; we won't exhaust all instructions. |
| 64 | assert(iter != function->begin()->end()); |
| 65 | if (iter->opcode() != spv::Op::OpVariable) { |
| 66 | // If we see a non-variable, we have gone through all the variables. |
| 67 | break; |
| 68 | } |
| 69 | if (iter->type_id() == pointer_type_id) { |
| 70 | return iter->result_id(); |
| 71 | } |
| 72 | } |
| 73 | // At this point, iter refers to the first non-function instruction of the |
| 74 | // function's entry block. |
| 75 | const uint32_t variable_id = context->TakeNextId(); |
| 76 | auto variable_inst = MakeUnique<opt::Instruction>( |
| 77 | context, spv::Op::OpVariable, pointer_type_id, variable_id, |
| 78 | opt::Instruction::OperandList( |
| 79 | {{SPV_OPERAND_TYPE_STORAGE_CLASS, |
| 80 | {uint32_t(spv::StorageClass::Function)}}})); |
| 81 | iter->InsertBefore(std::move(variable_inst)); |
| 82 | return variable_id; |
| 83 | } |
| 84 | |
| 85 | uint32_t FindOrCreateGlobalUndef(opt::IRContext* context, uint32_t type_id) { |
| 86 | for (auto& inst : context->module()->types_values()) { |
no test coverage detected