| 1845 | } |
| 1846 | |
| 1847 | spv_result_t ValidateAccessChain(ValidationState_t& _, |
| 1848 | const Instruction* inst) { |
| 1849 | const spv::Op opcode = inst->opcode(); |
| 1850 | const bool untyped_pointer = spvOpcodeGeneratesUntypedPointer(inst->opcode()); |
| 1851 | |
| 1852 | // The result type must be OpTypePointer for regular access chains and an |
| 1853 | // OpTypeUntypedPointerKHR for untyped access chains. |
| 1854 | auto result_type = _.FindDef(inst->type_id()); |
| 1855 | if (untyped_pointer) { |
| 1856 | if (!result_type || |
| 1857 | spv::Op::OpTypeUntypedPointerKHR != result_type->opcode()) { |
| 1858 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 1859 | << "The Result Type of Op" << spvOpcodeString(opcode) << " <id> " |
| 1860 | << _.getIdName(inst->id()) |
| 1861 | << " must be OpTypeUntypedPointerKHR. Found Op" |
| 1862 | << spvOpcodeString(result_type->opcode()) << "."; |
| 1863 | } |
| 1864 | } else { |
| 1865 | if (!result_type || spv::Op::OpTypePointer != result_type->opcode()) { |
| 1866 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 1867 | << "The Result Type of Op" << spvOpcodeString(opcode) << " <id> " |
| 1868 | << _.getIdName(inst->id()) << " must be OpTypePointer. Found Op" |
| 1869 | << spvOpcodeString(result_type->opcode()) << "."; |
| 1870 | } |
| 1871 | } |
| 1872 | |
| 1873 | if (untyped_pointer) { |
| 1874 | // Base type must be a non-pointer type. |
| 1875 | const auto base_type = _.FindDef(inst->GetOperandAs<uint32_t>(2)); |
| 1876 | if (!base_type || !spvOpcodeGeneratesType(base_type->opcode()) || |
| 1877 | base_type->opcode() == spv::Op::OpTypePointer || |
| 1878 | base_type->opcode() == spv::Op::OpTypeUntypedPointerKHR) { |
| 1879 | return _.diag(SPV_ERROR_INVALID_ID, inst) |
| 1880 | << "Base type must be a non-pointer type"; |
| 1881 | } |
| 1882 | |
| 1883 | const auto ContainsBlock = [&_](const Instruction* type_inst) { |
| 1884 | if (type_inst->opcode() == spv::Op::OpTypeStruct) { |
| 1885 | if (_.HasDecoration(type_inst->id(), spv::Decoration::Block) || |
| 1886 | _.HasDecoration(type_inst->id(), spv::Decoration::BufferBlock)) { |
| 1887 | return true; |
| 1888 | } |
| 1889 | } |
| 1890 | return false; |
| 1891 | }; |
| 1892 | |
| 1893 | // Block (and BufferBlock) arrays cannot be reinterpreted via untyped access |
| 1894 | // chains. |
| 1895 | const bool base_type_block_array = |
| 1896 | base_type->opcode() == spv::Op::OpTypeArray && |
| 1897 | _.ContainsType(base_type->id(), ContainsBlock, |
| 1898 | /* traverse_all_types = */ false); |
| 1899 | |
| 1900 | const auto base_index = untyped_pointer ? 3 : 2; |
| 1901 | const auto base_id = inst->GetOperandAs<uint32_t>(base_index); |
| 1902 | auto base = _.FindDef(base_id); |
| 1903 | // Strictly speaking this misses trivial access chains and function |
| 1904 | // parameter chasing, but that would be a significant complication in the |
no test coverage detected