/* おまじない　*/
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
typedef long long ll;
typedef long double ld;
using namespace std;
const ll MOD=pow(10,9)+7;
const ll INF=(1LL<<62);
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};
const int ddx[8]={1,0,-1,-1,-1,0,1,1};
const int ddy[8]={1,1,1,0,-1,-1,-1,0};
void init(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
}
ll gcd(ll a,ll b){
    if(a<b)swap(a,b);
    if(a%b==0)return b;
    return gcd(a%b,b);
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}

template<class T>
void print(vector<T>v){
	ll size=v.size();
	for(int i=0;i<size;i++){
		cout<<v[i]<<" ";
	}
	cout<<endl;
}

template< typename Monoid >
class SegmentTree {
public:
  using F = function< Monoid(Monoid, Monoid) >;

  int sz;
  vector< Monoid > seg;

  const F f;
  const Monoid M1;

  SegmentTree(int n, const F f, const Monoid &M1) : f(f), M1(M1) {
    sz = 1;
    while(sz < n) sz <<= 1;
    seg.assign(2 * sz, M1);
  }

  void set(int k, const Monoid &x) {
    seg[k + sz] = x;
  }

  void build() {
    for(int k = sz - 1; k > 0; k--) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  void update(int k, const Monoid &x) {
    k += sz;
    seg[k] = x;
    while(k >>= 1) {
      seg[k] = f(seg[2 * k + 0], seg[2 * k + 1]);
    }
  }

  Monoid query(int a, int b) {
    Monoid L = M1, R = M1;
    for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if(a & 1) L = f(L, seg[a++]);
      if(b & 1) R = f(seg[--b], R);
    }
    return f(L, R);
  }

  Monoid operator[](const int &k) const {
    return seg[k + sz];
  }

  template< typename C >
  int find_subtree(int a, const C &check, Monoid &M, bool type) {
    while(a < sz) {
      Monoid nxt = type ? f(seg[2 * a + type], M) : f(M, seg[2 * a + type]);
      if(check(nxt)) a = 2 * a + type;
      else M = nxt, a = 2 * a + 1 - type;
    }
    return a - sz;
  }


  template< typename C >
  int find_first(int a, const C &check) {
    Monoid L = M1;
    if(a <= 0) {
      if(check(f(L, seg[1]))) return find_subtree(1, check, L, false);
      return -1;
    }
    int b = sz;
    for(a += sz, b += sz; a < b; a >>= 1, b >>= 1) {
      if(a & 1) {
        Monoid nxt = f(L, seg[a]);
        if(check(nxt)) return find_subtree(a, check, L, false);
        L = nxt;
        ++a;
      }
    }
    return -1;
  }

  template< typename C >
  int find_last(int b, const C &check) {
    Monoid R = M1;
    if(b >= sz) {
      if(check(f(seg[1], R))) return find_subtree(1, check, R, true);
      return -1;
    }
    int a = sz;
    for(b += sz; a < b; a >>= 1, b >>= 1) {
      if(b & 1) {
        Monoid nxt = f(seg[--b], R);
        if(check(nxt)) return find_subtree(b, check, R, true);
        R = nxt;
      }
    }
    return -1;
  }
};

int main(){
    init();
	ll H,W;
	cin>>H>>W;
	string s[H];
	for(int i=0;i<H;i++)cin>>s[i];

	//(0,0)から(H-1,W-1)の最短距離
	queue<pair<ll,pair<ll,ll>>>que;
	que.push(make_pair(0,make_pair(0,0)));
	ll max=100;
	vector<bool>seen(max*max,false);
	seen[0+max*0]=true;
	ll ans=-1;
	while(!que.empty()){
		ll dis=que.front().first;
		ll x=que.front().second.first;
		ll y=que.front().second.second;
		que.pop();
		if(x==H-1 && y==W-1){
			ans=dis;
			break;
		}
		for(int k=0;k<4;k++){
			ll nextX=x+dx[k];
			ll nextY=y+dy[k];
			if(nextX<0 || H<=nextX || nextY<0 || W<=nextY)continue;
			if(s[nextX][nextY]=='#')continue;
			if(seen[nextX + max*nextY])continue;
			seen[nextX + max*nextY]=true;
			que.push(make_pair(dis+1,make_pair(nextX,nextY)));
		}
	}

	ll count=0;
	for(int i=0;i<H;i++){
		for(int j=0;j<W;j++){
			if(s[i][j]=='#')count++;
		}
	}
	if(ans==-1){
		cout<<-1<<endl;
		return 0;
	}

	cout<<H*W-count-ans-1<<endl;
}

Measured memory_bytes: 256