| 1120 | } |
| 1121 | |
| 1122 | Optional<BufferOffset<tflite::SubGraph>> Translator::BuildSubGraph( |
| 1123 | const std::string& name, Region* region) { |
| 1124 | bool has_input_attr = false; |
| 1125 | if (auto fn = dyn_cast<FuncOp>(region->getParentOp())) { |
| 1126 | InitializeNamesFromAttribute(fn, &has_input_attr); |
| 1127 | } |
| 1128 | std::vector<BufferOffset<tflite::Tensor>> tensors; |
| 1129 | llvm::DenseMap<Value, int> tensor_index_map; |
| 1130 | |
| 1131 | // Builds tensor and buffer for argument or operation result. Returns false |
| 1132 | // on failure. |
| 1133 | auto build_tensor_and_buffer = [&](Value value, const std::string& name) { |
| 1134 | // NoneType represents optional and may be skipped here. |
| 1135 | if (value.getType().isa<NoneType>()) { |
| 1136 | return true; |
| 1137 | } |
| 1138 | |
| 1139 | tensor_index_map.insert({value, tensors.size()}); |
| 1140 | auto tensor_or = BuildTensor(value, name, buffers_.size()); |
| 1141 | if (!tensor_or) return false; |
| 1142 | tensors.push_back(*tensor_or); |
| 1143 | |
| 1144 | // TODO(ashwinm): Check if for stateful tensors, if it is also needed to |
| 1145 | // make the Buffer empty apart from setting the buffer_idx=0 in the Tensor. |
| 1146 | // This does not seem to affect runtime behavior for RNN/LSTM, but would be |
| 1147 | // good for reducing memory footprint. |
| 1148 | if (auto* inst = value.getDefiningOp()) { |
| 1149 | auto buffer_or = BuildBuffer(inst); |
| 1150 | if (!buffer_or) return false; |
| 1151 | buffers_.push_back(*buffer_or); |
| 1152 | } else { |
| 1153 | buffers_.push_back(empty_buffer_); |
| 1154 | } |
| 1155 | return true; |
| 1156 | }; |
| 1157 | |
| 1158 | std::vector<BufferOffset<tflite::Operator>> operators; |
| 1159 | auto& bb = region->front(); |
| 1160 | |
| 1161 | // Main function's arguments are first passed to `input` op so they don't |
| 1162 | // have associated tensor and buffer. Build FlatBuffer tensor and buffer for |
| 1163 | // other functions. |
| 1164 | for (unsigned i = 0, e = bb.getNumArguments(); i < e; ++i) { |
| 1165 | mlir::BlockArgument arg = bb.getArgument(i); |
| 1166 | std::string name; |
| 1167 | if (has_input_attr) name = std::string(name_mapper_.GetUniqueName(arg)); |
| 1168 | if (name.empty()) name = absl::StrCat("arg", i); |
| 1169 | if (!build_tensor_and_buffer(arg, name)) return llvm::None; |
| 1170 | } |
| 1171 | |
| 1172 | bool failed_once = false; |
| 1173 | for (auto& inst : bb) { |
| 1174 | if (inst.isKnownTerminator()) break; |
| 1175 | |
| 1176 | for (auto val : inst.getResults()) { |
| 1177 | std::string name = UniqueName(val); |
| 1178 | if (!build_tensor_and_buffer(val, name)) return llvm::None; |
| 1179 | } |
nothing calls this directly
no test coverage detected