TODO(krzysd) Handle function calls
| 546 | |
| 547 | // TODO(krzysd) Handle function calls |
| 548 | StatusOr<Operation*> ConvertOp( |
| 549 | const tflite::OperatorT& op, const std::vector<Value>& vals_map, |
| 550 | Value optional_arg_marker, const std::vector<std::string>& op_names, |
| 551 | const std::vector<std::string>& func_names, |
| 552 | const std::vector<std::unique_ptr<tflite::TensorT>>& tensors, Location loc, |
| 553 | OpBuilder builder) { |
| 554 | llvm::SmallVector<Value, 4> operands; |
| 555 | llvm::SmallVector<mlir::Type, 2> outputTypes; |
| 556 | |
| 557 | if (op.outputs.empty()) { |
| 558 | auto err = errors::InvalidArgument("operator with no outputs"); |
| 559 | return emitError(loc, err.ToString()), err; |
| 560 | } |
| 561 | |
| 562 | const bool is_basic_lstm = IsBasicLSTMOp(op.builtin_options); |
| 563 | const std::string& op_name = |
| 564 | is_basic_lstm ? "tfl.basic_lstm" : op_names.at(op.opcode_index); |
| 565 | OperationState op_state(loc, op_name); |
| 566 | |
| 567 | for (auto input_num : op.inputs) { |
| 568 | if (input_num == -1) { |
| 569 | assert(optional_arg_marker != nullptr); |
| 570 | op_state.addOperands({optional_arg_marker}); |
| 571 | } else { |
| 572 | op_state.addOperands({vals_map.at(input_num)}); |
| 573 | } |
| 574 | } |
| 575 | |
| 576 | for (auto output_num : op.outputs) { |
| 577 | auto& tensor = *tensors.at(output_num); |
| 578 | auto type_or_err = GetTensorType(tensor, builder); |
| 579 | if (!type_or_err.ok()) { |
| 580 | return emitError(loc, type_or_err.status().ToString()), |
| 581 | type_or_err.status(); |
| 582 | } |
| 583 | auto type = type_or_err.ConsumeValueOrDie(); |
| 584 | |
| 585 | if (op_name == "tfl.quantize") { |
| 586 | // Special case for quantize: return type must also be in qtype attribute |
| 587 | op_state.addAttribute("qtype", mlir::TypeAttr::get(type)); |
| 588 | } else if (op_name == "tfl.reshape" && type.hasStaticShape() && |
| 589 | op_state.operands.size() == 1) { |
| 590 | // Special case for reshape: the second op is optional in the old |
| 591 | // converter and kernel, so we create the second operand, which is |
| 592 | // required by the new converter, from the result shape. |
| 593 | auto shape_type = |
| 594 | RankedTensorType::get({type.getRank()}, builder.getIntegerType(32)); |
| 595 | mlir::SmallVector<mlir::Attribute, 4> shape; |
| 596 | shape.reserve(type.getRank()); |
| 597 | for (auto s : type.getShape()) { |
| 598 | shape.push_back(builder.getI32IntegerAttr(static_cast<int32_t>(s))); |
| 599 | } |
| 600 | auto output_shape = DenseElementsAttr::get(shape_type, shape); |
| 601 | auto shape_op = builder.create<tfl::ConstOp>(loc, output_shape); |
| 602 | op_state.addOperands({shape_op}); |
| 603 | } |
| 604 | |
| 605 | op_state.addTypes({type}); |
no test coverage detected