Use optimized 1x1 conv implementation.

Change-Id: I6be5c3f6fc8b981ab738fb492e8b3318544aa289
diff --git a/tensorflow/lite/micro/kernels/kelvin/conv.cc b/tensorflow/lite/micro/kernels/kelvin/conv.cc
index 0d2f068..03904bc 100644
--- a/tensorflow/lite/micro/kernels/kelvin/conv.cc
+++ b/tensorflow/lite/micro/kernels/kelvin/conv.cc
@@ -16,6 +16,12 @@
 namespace tflite {
 namespace {
 
+constexpr int kFilterHeightIndex = 1;
+constexpr int kFilterWidthIndex = 2;
+constexpr int kFilterInputChannelIndex = 3;
+constexpr int kInputChannelIndex = 3;
+constexpr int kOutputChannelIndex = 3;
+
 void* Init(TfLiteContext* context, const char* buffer, size_t length) {
   TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr);
   return context->AllocatePersistentBuffer(context, sizeof(OpDataConv));
@@ -85,7 +91,64 @@
           break;
         }
         case kTfLiteInt64: {
-          const auto fn = opt ? kelvin::opt::conv_per_channel_b64 : reference_integer_ops::ConvPerChannel<int64_t>;
+          const auto filter_shape = tflite::micro::GetTensorShape(filter);
+          const auto input_shape = tflite::micro::GetTensorShape(input);
+          const auto output_shape = tflite::micro::GetTensorShape(output);
+          if (opt && filter_shape.Dims(kFilterHeightIndex) == 1 &&
+                     filter_shape.Dims(kFilterWidthIndex) == 1 &&
+                     filter_shape.Dims(kFilterInputChannelIndex) % 32 == 0 &&
+                     filter_shape.Dims(kOutputChannelIndex) % 2 == 0) {
+            kelvin::opt::conv_per_channel_b64_1x1(
+                params_q,
+                data.per_channel_output_multiplier,
+                data.per_channel_output_shift,
+                tflite::micro::GetTensorShape(input),
+                tflite::micro::GetTensorData<int16_t>(input),
+                tflite::micro::GetTensorShape(filter),
+                tflite::micro::GetTensorData<int8_t>(filter),
+                tflite::micro::GetTensorShape(bias),
+                tflite::micro::GetOptionalTensorData<std::int64_t>(bias),
+                tflite::micro::GetTensorShape(output),
+                tflite::micro::GetTensorData<int16_t>(output));
+            break;
+          }
+          // TODO(derekjchow): Check for valid padding
+          if (opt && filter_shape.Dims(kFilterHeightIndex) == 1
+                  && filter_shape.Dims(kFilterInputChannelIndex) % 32 == 0
+                  && filter_shape.Dims(kOutputChannelIndex) % 2 == 0) {
+            if (input_shape.Dims(kInputChannelIndex) ==
+                filter_shape.Dims(kFilterInputChannelIndex)) {
+              kelvin::opt::conv_per_channel_b64_filter1xn_non_group(
+                  params_q,
+                  data.per_channel_output_multiplier,
+                  data.per_channel_output_shift,
+                  tflite::micro::GetTensorShape(input),
+                  tflite::micro::GetTensorData<int16_t>(input),
+                  tflite::micro::GetTensorShape(filter),
+                  tflite::micro::GetTensorData<int8_t>(filter),
+                  tflite::micro::GetTensorShape(bias),
+                  tflite::micro::GetOptionalTensorData<std::int64_t>(bias),
+                  tflite::micro::GetTensorShape(output),
+                  tflite::micro::GetTensorData<int16_t>(output));
+              break;
+            } else if (filter_shape.Dims(kFilterInputChannelIndex) % 32 == 0) {
+              kelvin::opt::conv_per_channel_b64_filter1xn_group(
+                  params_q,
+                  data.per_channel_output_multiplier,
+                  data.per_channel_output_shift,
+                  tflite::micro::GetTensorShape(input),
+                  tflite::micro::GetTensorData<int16_t>(input),
+                  tflite::micro::GetTensorShape(filter),
+                  tflite::micro::GetTensorData<int8_t>(filter),
+                  tflite::micro::GetTensorShape(bias),
+                  tflite::micro::GetOptionalTensorData<std::int64_t>(bias),
+                  tflite::micro::GetTensorShape(output),
+                  tflite::micro::GetTensorData<int16_t>(output));
+              break;
+            }
+          }
+          const auto fn = opt ? kelvin::opt::conv_per_channel_b64
+                              : reference_integer_ops::ConvPerChannel<int64_t>;
           fn(
               params_q,
               data.per_channel_output_multiplier, data.per_channel_output_shift,