////////////////////////////////////////////////////////////////////
// This source code is for Visual Studio
////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <map>
#include <set>
#include <algorithm>
#include <sstream>
#include <iterator>
#include <stack>
#include <functional>
#include <iomanip>
#include <string>
#include <cstring>
#include <deque>
#include <math.h>
#include <assert.h>
 
#define	numberof(a)	(sizeof(a) / sizeof(a[0]))
#define	INF		INT32_MAX
#define Rep(i,n) for(int i = 0; i < (n); ++i )
 
using namespace std;
 
typedef vector< vector<int> > MAT;
typedef pair<int, int> PINT;
typedef long long ll;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int32_t s32;
typedef int64_t s64;
 
//constant
//--------------------------------------------
const double EPS = 1e-10;
const double PI  = acos(-1.0);
 
// @param[in] G[i][j]:ノードiにつながっているj番目のノード(firstがノード番号, secondがコスト。つながっているノードだけ含まれる)
// @param[in] startNode:起点ノード番号
// @retval : 起点からノードiへの最短経路の重み、INFで初期化
vector<ll> dijkstra(vector< vector< pair<ll, ll> > > & G, ll startNode)
{
	priority_queue< pair<ll, ll> > searchPQ;	// PQの要素はこれから探索するノード(firstがコスト, secondがノード番号)
	const ll node_number = G.size();
	vector<bool> isChecked(node_number, false);	// trueのときは探索済
	vector<ll> output_dist(node_number);
 
	Rep(i, node_number) {
		output_dist[i] = INF;
		isChecked[i] = false;
	}
 
	// 起点からスタート
	output_dist[startNode] = 0;
	searchPQ.push(make_pair(0, startNode));
 
	while (!searchPQ.empty())
	{
		pair<ll, ll> search_node = searchPQ.top(); searchPQ.pop();
		ll u = search_node.second;// 調べるノード
		isChecked[u] = true;
 
		if (output_dist[u] < search_node.first * (-1)) continue;// search_node.firstは負の値にしている
 
		for (ll j = 0; j < G[u].size(); j++) {
			// uにつながっているノードを探索
			ll v = G[u][j].first;
			if (isChecked[v] == true) continue;
			if (output_dist[v] > output_dist[u] + G[u][j].second) {
				output_dist[v] = output_dist[u] + G[u][j].second;
				searchPQ.push(make_pair(output_dist[v] * (-1), v));//priority_queueはデフォルトで大きい値をpopしてしまうのでマイナスをかける
			}
		}
	}
 
	return output_dist;
}
 
int main()
{
	ll H = 0;
	ll W = 0;
	ll ans = 0;
	ll black = 0;
 
	cin >> H >> W;
	vector< vector<char> > floor(H, vector<char>(W, '.'));
	Rep(y, H) {
		Rep(x, W) {
			cin >> floor[y][x];
			if ('#' == floor[y][x]) black++;
		}
	}
 
	vector< vector< pair<ll, ll> > > G(H * W);// (x, y) -> node (y * W + x)
	int dx[] = { 0, 0,  -1, 1 };
	int dy[] = { 1, -1,  0, 0 };
 
	Rep(y, H) {
		Rep(x, W) {
			// check (x, y)
			ll node = y * W + x;
 
			// search around node
			Rep(k, 4) {
				ll new_x = x + dx[k];
				ll new_y = y + dy[k];
				ll new_node = new_y * W + new_x;
				if (new_x < 0 || new_x >= W) continue;
				if (new_y < 0 || new_y >= H) continue;
 
				if ('#' == floor[new_y][new_x]) {
					//G[node].push_back(make_pair(new_node, INF));
				}
				else if ('.' == floor[new_y][new_x]) {
					//graph.addEdge(node, new_node, 1);
					G[node].push_back(make_pair(new_node, 1));
				}
			}
		}
	}
 
	// solve
	// (0, 0) - (W - 1, H - 1)
	vector<ll> result = dijkstra(G, 0);
	if (result[(H - 1) * W + W - 1] == INF) {
		ans = -1;
	}
	else {
		ll black_enable = H * W - result[(H - 1) * W + W - 1] - 1;
		ans = black_enable - black;
	}
 
	cout << ans << endl;
 
	return 0;
}

Measured memory_bytes: 512