// #include <stdio.h>
// #include <vector>
#include <cmath>
// // #include <algorithm>
// using namespace std;

#include <vector>
#include <queue>
#include <climits>
#include <cstdio>

struct Node {
  // このノードから伸びるエッジの情報
  int number;
  std::vector<int> edges_to;    // 各エッジの接続先のノード番号
  std::vector<int> edges_cost;  // 各エッジのコスト

  // ダイクストラ法のためのデータ
  bool done;  // 確定ノードか否か
  int cost;   // このノードへの現時点で判明している最小コスト
  Node() {
    done = false;
    cost = INT_MAX;
  }
  bool operator> (const Node &node) const {
    return cost > node.cost;
  }
};

class MyGraph {
public:
  MyGraph(int numNodes) {
    this->numNodes = numNodes;
    nodes = std::vector<Node>(numNodes);
    doneCount = 0;
  }
  int numNodes;
  std::vector<Node> nodes;
  std::priority_queue<Node, std::vector<Node>, std::greater<Node> > queue;
  int doneCount;

  void addEdge(int edge_from, int edge_to, int edge_cost) {
    nodes[edge_from].number = edge_from;
    nodes[edge_from].edges_to.push_back(edge_to);
    nodes[edge_from].edges_cost.push_back(edge_cost);
  }
  void updateCost(int node_start) {
    nodes[node_start].cost = 0;
    queue.push(nodes[node_start]);
    while (!queue.empty()) {
      Node &node = nodes[queue.top().number];
      queue.pop();
      if (node.done) {
        continue;
      }
      //printf("%d\n", node.number);
      node.done = true;
      doneCount++;
      for (int i = 0; i < (int)node.edges_to.size(); ++i) {
        Node &nodeNext = nodes[node.edges_to[i]];
        if (!nodeNext.done && nodeNext.cost > node.cost + node.edges_cost[i]) {
          nodeNext.cost = node.cost + node.edges_cost[i];
          //printf("%d %d\n", nodeNext.number, node.cost + node.edges_cost[i]);
          queue.push(nodeNext);
        }
      }
    }
  }
  int updateCost(int node_start, int node_goal) {
    nodes[node_start].cost = 0;
    queue.push(nodes[node_start]);
    while (!queue.empty()) {
      Node &node = nodes[queue.top().number];
      if (node.number == node_goal) {
        return node.cost;
      }
      queue.pop();
      if (node.done) {
        continue;
      }
      // printf("%d\n", node.number);
      node.done = true;
      doneCount++;
      for (int i = 0; i < (int)node.edges_to.size(); ++i) {
        Node &nodeNext = nodes[node.edges_to[i]];
        if (!nodeNext.done && nodeNext.cost > node.cost + node.edges_cost[i]) {
          nodeNext.cost = node.cost + node.edges_cost[i];
          // printf("%d %d\n", nodeNext.number, node.cost + node.edges_cost[i]);
          queue.push(nodeNext);
        }
      }
    }
    return nodes[node_goal].cost;
  }
  int getCost(int node_num) {
    return nodes[node_num].cost;
  }
};


int main(int argc, char const *argv[]) {
  int H, W;
  scanf("%d%d", &H, &W);
  char s[H][W];
  int b = 0;
  for (int i = 0; i < H; i ++) {
    scanf("%s", s[i]);
  }
  // for (int x = 0; x < H; x ++) {
  //   for (int y = 0; y < W; y ++) {
  //     printf("%c", s[x][y]);
  //   }
  //   printf("\n");
  // }
  MyGraph graph = MyGraph(H*W);
  for (int x = 0; x < H; x ++) {
    for (int y = 0; y < W; y ++) {
      if (s[x][y] == '#') {
        b++;
        continue;
      }
      for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
          int h = i ? pow(-1, j) : 0;
          int w = !i ? pow(-1, j) : 0;
          if (x + h >= 0 && x + h < H && y + w >= 0 && y + w < W) {
            if (s[x + h][y + w] != '#') {
              graph.addEdge(x*W + y, (x + h)*W + (y + w), 1);
            }
          }
        }
      }
    }
  }
  int cost = graph.updateCost(0, H*W - 1);
  if (cost == INT_MAX) {
    printf("%d\n", -1);
  } else {
    //printf("%d %d %d\n", H*W, cost , b);
    printf("%d\n", H*W - (cost + 1) - b);
  }
  return 0;
}


Measured memory_bytes: 512