Repository: microsoft/onnxruntime
File: onnxruntime/core/providers/webnn/builders/impl/gatherBlockQuantized_op_builder.cc (C++)

Code before:
bool GatherBlockQuantizedOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node,
                                                           const emscripten::val& wnn_limits,
                                                           const logging::Logger& logger) const {
  const auto& input_defs = node.InputDefs();
  std::vector<int64_t> input_shape;
  std::vector<int64_t> scales_shape;
  if (!GetShape(*input_defs[0], input_shape, logger) ||
      !GetShape(*input_defs[2], scales_shape, logger)) {
    return false;
  }

  if (input_shape.size() != scales_shape.size()) {
    LOGS(logger, VERBOSE) << "GatherBlockQuantized: input and scales must have the same rank.";
    return false;
  }

  const std::string_view op_type = node.OpType();
  int32_t input_type = 0;
  int32_t scales_type = 0;
  if (!GetType(*input_defs[0], input_type, logger) ||
      !GetType(*input_defs[2], scales_type, logger)) {
    return false;
  }

  // Only need to check the input data type of ops that consume the inputs of GatherBlockQuantized.
  // WebNN dequantizeLinear's input should be same as input, gather's input should be same as scales input.
  return IsDataTypeSupportedByWebNNOp(op_type, "dequantizeLinear", input_type, wnn_limits, "input", "data", logger) &&
         IsDataTypeSupportedByWebNNOp(op_type, "gather", scales_type, wnn_limits, "input", "scales", logger);

  return true;
}

bool GatherBlockQuantizedOpBuilder::HasSupportedOutputsImpl(const Node& node,
                                                            const emscripten::val& wnn_limits,
                                                            const logging::Logger& logger) const {
  const auto& output_defs = node.OutputDefs();
  const std::string_view op_type = node.OpType();
  int32_t output_type;
  if (!GetType(*output_defs[0], output_type, logger)) {
    return false;
  }

  // Only need to check the output data type of ops that produce the output of GatherBlockQuantized.
  // WebNN gather's output should be same as GatherBlockQuantized's output.
  return IsDataTypeSupportedByWebNNOp(op_type, "gather", output_type, wnn_limits, "output", "output", logger);
}

void CreateGatherBlockQuantizedOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) {
  op_registrations.builders.push_back(std::make_unique<GatherBlockQuantizedOpBuilder>());
  op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get());
}

Review comment (suggestion):
```suggestion
  // WebNN dequantizeLinear's input should be same as input. gather's input should be same as scales input.
```

Code after:
bool GatherBlockQuantizedOpBuilder::HasSupportedInputsImpl(const GraphViewer&, const Node& node,
                                                           const emscripten::val& wnn_limits,
                                                           const logging::Logger& logger) const {
  const auto& input_defs = node.InputDefs();
  std::vector<int64_t> input_shape;
  std::vector<int64_t> scales_shape;
  if (!GetShape(*input_defs[0], input_shape, logger) ||
      !GetShape(*input_defs[2], scales_shape, logger)) {
    return false;
  }

  if (input_shape.size() != scales_shape.size()) {
    LOGS(logger, VERBOSE) << "GatherBlockQuantized: input and scales must have the same rank.";
    return false;
  }

  const std::string_view op_type = node.OpType();
  int32_t input_type = 0;
  int32_t scales_type = 0;
  if (!GetType(*input_defs[0], input_type, logger) ||
      !GetType(*input_defs[2], scales_type, logger)) {
    return false;
  }

  // Only need to check the input data type of ops that consume the inputs of GatherBlockQuantized.
  // WebNN dequantizeLinear's input should be same as input. WebNN gather's input should be same as scales input.
  return IsDataTypeSupportedByWebNNOp(op_type, "dequantizeLinear", input_type, wnn_limits, "input", "data", logger) &&
         IsDataTypeSupportedByWebNNOp(op_type, "gather", scales_type, wnn_limits, "input", "scales", logger);

  return true;
}

bool GatherBlockQuantizedOpBuilder::HasSupportedOutputsImpl(const Node& node,
                                                            const emscripten::val& wnn_limits,
                                                            const logging::Logger& logger) const {
  const auto& output_defs = node.OutputDefs();
  const std::string_view op_type = node.OpType();
  int32_t output_type;
  if (!GetType(*output_defs[0], output_type, logger)) {
    return false;
  }

  // Only need to check the output data type of ops that produce the output of GatherBlockQuantized.
  // WebNN gather's output should be same as GatherBlockQuantized's output.
  return IsDataTypeSupportedByWebNNOp(op_type, "gather", output_type, wnn_limits, "output", "output", logger);
}

void CreateGatherBlockQuantizedOpBuilder(const std::string& op_type, OpBuilderRegistrations& op_registrations) {
  op_registrations.builders.push_back(std::make_unique<GatherBlockQuantizedOpBuilder>());
  op_registrations.op_builder_map.emplace(op_type, op_registrations.builders.back().get());
}